DDSI-RTPS 2.5 — Spec Coverage

Source: internal/standards/cache/omg/ddsi-rtps-2.5.pdf (206 pages, OMG formal/2022-04-01) — OMG DDSI-RTPS 2.5

Item-by-item audit against the PDF following internal/spec-coverage/PROCESS.md. Page numbers are PDF pages (PDF page = printed page + 6). Every row of a normative table is an item of its own. done stands only where code and a test cover the requirement; a test citation names the test function as file::module::name.

Context: The DDSI-RTPS 2.5 stack is spread over:

  • crates/rtps/ · docs.rs — header, submessages, HeaderExtension, ParameterList, inline QoS, receiver state, writer and reader state machines with their proxies, HistoryCache, fragmentation, discovery data types.
  • crates/discovery/ · docs.rs — SPDP, SEDP, TypeLookup, the secure builtin endpoints.
  • crates/transport/ · docs.rs, crates/transport-udp/ — the transport interface and the UDP/IP PSM (§9.5).
  • crates/dcps/ · docs.rs — the DDS side (§8.2.10), the Writer Liveliness Protocol, KeyHash, the encapsulation header (§10).
  • crates/qos/ · docs.rs — the QoS policies and their wire format.

Open items: see ddsi-rtps-2.5.open.en.md.


§1 Scope

§1 Scope

Spec: §1, p. 7 — “This specification defines an interoperability wire protocol for DDS. Its purpose and scope are to ensure that applications based on different vendors’ implementations of DDS can interoperate.”

Repo: crates/rtps/src/lib.rs

Tests: —

Status: n/a (informative) — statement of purpose; the requirements are in §7.5–§10 and listed there one by one.


§2 Conformance

§2 Conformance

Spec: §2, p. 7 — “Implementations of this specification must comply with the conformance statements listed in 8.4.2 of this specification.”

Repo: —

Tests: —

Status: n/a (informative) — a reference without a requirement of its own; the conformance statements of §8.4.2 are listed one by one under §8.4.2.1–§8.4.2.3.


§3 Normative References

§3 Normative References

Spec: §3, p. 7 — list of normative documents [1] DDS 1.4, [2] IDL 4.2, [3] DDS-XTypes 1.2, [4] NTP version 3 (RFC 1305), [5] MD5 (RFC 1321), [6] SCTP CRC32c (RFC 4960 appendix B), [7] AUTOSAR CRC routines R20-11.

Repo: —

Tests: —

Status: n/a (informative) — cross-reference list. What follows from the references is listed where it is used: Time_t in NTP format under §9.3.2.2, MD5 under §9.4.2.15 and §9.6.4.8, CRC32c and CRC64 under §9.4.2.15.


§4 Terms and Definitions

§4 Terms and Definitions

Spec: §4, p. 7 — “For the purposes of this specification, the terms and definitions given in the normative references apply.”

Repo: —

Tests: —

Status: n/a (informative) — reference to terms, no requirement.


§5 Symbols

§5 Symbols

Spec: §5, p. 7 — abbreviations CDR, DDS, EDP, GUID, PDP, PIM, PSM, RTPS, SEDP.

Repo: —

Tests: —

Status: n/a (informative) — list of abbreviations.


§6 Additional Information

§6.1 Changes to Adopted OMG Specifications

Spec: §6.1, p. 9 — “This specification does not change any adopted OMG specifications.”

Repo: —

Tests: —

Status: n/a (informative) — editorial statement.

§6.2 How to Read this Specification

Spec: §6.2, p. 9 — reading guide to PIM, PSM and the modules.

Repo: —

Tests: —

Status: n/a (informative) — reading guide.

§6.3 Acknowledgments

Spec: §6.3, pp. 9–11 — contributing companies and persons per revision.

Repo: —

Tests: —

Status: n/a (informative) — acknowledgments.

§6.4 Statement of Maturity

Spec: §6.4, p. 11 — maturity and known implementations.

Repo: —

Tests: —

Status: n/a (informative) — background.


§7 Overview

§7.1 Introduction

Spec: §7.1, p. 13 — motivation for a DDS wire protocol.

Repo: —

Tests: —

Status: n/a (informative) — introduction without a requirement.

§7.2 Requirements for a DDS Wire-protocol

Spec: §7.2, pp. 13–14 — requirements on a DDS wire protocol as design goals (no central name server, no single point of failure, extensibility).

Repo: —

Tests: —

Status: n/a (informative) — design goals; the mechanisms that follow from them (SPDP/SEDP without a server, versioning) are listed under §8.5 and §8.6.

§7.3 The RTPS Wire-protocol

Spec: §7.3, p. 14 — origin and properties of RTPS.

Repo: —

Tests: —

Status: n/a (informative) — description.

§7.4 The RTPS Platform Independent Model (PIM)

Spec: §7.4–§7.4.4, pp. 14–17 — structure of the PIM into the modules Structure, Messages, Behavior and Discovery.

Repo: —

Tests: —

Status: n/a (informative) — overview; the modules are listed under §8.2–§8.5.

§7.5 The UDP/IP PSM is mandatory

Spec: §7.5, p. 17 — “Multiple PSMs may be supported, but all implementations of DDS must at least implement the PSM on top of UDP/IP, which is presented in Clause 9.”

Repo: crates/transport-udp/src/udp_transport.rs (UdpTransport); crates/dcps/src/runtime.rs (SPDP/SEDP and user data over UDP).

Tests: crates/transport-udp/tests/e2e.rs::e2e_write_udp_read_single_datagram, crates/transport-udp/tests/e2e.rs::e2e_write_udp_read_multiple_in_order, crates/transport-udp/src/udp_transport.rs::tests::send_recv_v6_loopback

Status: done

§7.6 Transport: unicast address within 16 octets

Spec: §7.6, p. 18 — “The transport has a generalized notion of a unicast address (shall fit within 16 bytes).”

Repo: crates/rtps/src/wire_types.rs (Locator::address: [u8; 16])

Tests: crates/rtps/src/wire_types.rs::tests::locator_udp_v6_constructor_keeps_full_address, crates/rtps/src/wire_types.rs::tests::locator_udp_v4_layout

Status: done

§7.6 Transport: port within 4 octets

Spec: §7.6, p. 18 — “The transport has a generalized notion of a port (shall fit within 4 bytes)”.

Repo: crates/rtps/src/wire_types.rs (Locator::port: u32)

Tests: crates/rtps/src/wire_types.rs::tests::locator_roundtrip_le

Status: done

§7.6 Transport: send a datagram to an address/port

Spec: §7.6, p. 18 — “The transport can send a datagram (uninterpreted sequence of octets) to a specific address/port.”

Repo: crates/transport/src/lib.rs (Transport::send); crates/transport-udp/src/udp_transport.rs (UdpTransport::send)

Tests: crates/transport-udp/src/udp_transport.rs::tests::loopback_send_and_recv_delivers_datagram, crates/transport-udp/tests/e2e.rs::e2e_write_udp_read_single_datagram

Status: done

§7.6 Transport: receive a datagram at an address/port

Spec: §7.6, p. 18 — “The transport can receive a datagram at a specific address/port.”

Repo: crates/transport/src/lib.rs (Transport::recv); crates/transport-udp/src/udp_transport.rs (UdpTransport::recv, UdpTransport::bind_v4)

Tests: crates/transport-udp/src/udp_transport.rs::tests::bind_v4_returns_local_locator_with_assigned_port, crates/transport-udp/src/udp_transport.rs::tests::loopback_multiple_datagrams_in_order

Status: done

§7.6 Transport drops incomplete or corrupted messages

Spec: §7.6, p. 18 — “The transport will drop messages if incomplete or corrupted during transfer (i.e., RTPS assumes messages are complete and not corrupted).”

Repo: —

Tests: —

Status: n/a (informative) — an assumption about the transport, not a requirement on the RTPS implementation. For UDP the operating system checks the UDP header checksum; the optional message checksum of the HeaderExtension is listed under §8.3.3.2 and §9.4.2.15.


§8.1 Introduction

§8.1 The PIM as a virtual machine

Spec: §8.1, p. 19 — “This description is not intended to constrain the internal implementation in any way. The only criteria for a compliant implementation is that the externally-observable behavior satisfies the requirements for interoperability.”

Repo: —

Tests: —

Status: n/a (informative) — sets the yardstick for the PIM items: what is checked is the externally observable behaviour, not the class structure.


§8.2 Structure Module

§8.2.1 Overview

Spec: §8.2.1, p. 19 — every RTPS entity corresponds to a DDS entity; the HistoryCache is the interface between the two.

Repo: —

Tests: —

Status: n/a (informative) — overview; the relation is listed per transition under §8.2.10.

§8.2.1.1 Table 8.1 classes of the virtual machine

Spec: §8.2.1.1, pp. 20–21, Table 8.1 — summary of the classes Entity, Endpoint, Participant, Writer, Reader, HistoryCache, CacheChange, Data.

Repo: —

Tests: —

Status: n/a (informative) — summary; every class is listed with its attributes under §8.2.2–§8.2.9.

§8.2.1.2 Table 8.2 GUID_t

Spec: §8.2.1.2, p. 21, Table 8.2 — “GUID_t … Must be possible to represent using 16 octets. The following values are reserved by the protocol: GUID_UNKNOWN”.

Repo: crates/rtps/src/wire_types.rs (Guid, Guid::WIRE_SIZE, Guid::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::guid_layout_is_prefix_then_entity_id, crates/rtps/src/wire_types.rs::tests::guid_roundtrip, crates/rtps/src/wire_types.rs::tests::guid_prefix_unknown_is_zero, crates/rtps/src/wire_types.rs::tests::entity_id_unknown_is_four_zero_octets

Status: done — Guid::UNKNOWN is composed of the two tested UNKNOWN parts.

§8.2.1.2 Table 8.2 GuidPrefix_t

Spec: §8.2.1.2, p. 21, Table 8.2 — “GuidPrefix_t … Must be possible to represent using 12 octets. The following values are reserved by the protocol: GUIDPREFIX_UNKNOWN”.

Repo: crates/rtps/src/wire_types.rs (GuidPrefix, GuidPrefix::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::guid_prefix_unknown_is_zero, crates/rtps/src/wire_types.rs::tests::guid_prefix_roundtrip

Status: done

§8.2.1.2 Table 8.2 EntityId_t

Spec: §8.2.1.2, p. 21, Table 8.2 — “EntityId_t … Must be possible to represent using 4 octets. The following values are reserved by the protocol: ENTITYID_UNKNOWN”.

Repo: crates/rtps/src/wire_types.rs (EntityId, EntityId::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::entity_id_unknown_is_four_zero_octets, crates/rtps/src/wire_types.rs::tests::entity_id_roundtrip

Status: done

§8.2.1.2 Table 8.2 SequenceNumber_t

Spec: §8.2.1.2, p. 21, Table 8.2 — “SequenceNumber_t … Must be possible to represent using 64 bits. The following values are reserved by the protocol: SEQUENCENUMBER_UNKNOWN”.

Repo: crates/rtps/src/wire_types.rs (SequenceNumber(i64), SequenceNumber::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::sequence_number_unknown_high_minus_one_low_zero, crates/rtps/src/wire_types.rs::tests::sequence_number_roundtrip_le, crates/rtps/src/wire_types.rs::tests::sequence_number_roundtrip_be

Status: done

§8.2.1.2 Table 8.2 Locator_t

Spec: §8.2.1.2, p. 22, Table 8.2 — “It must be possible to represent the discriminator and port number using 4 octets each, the address using 16 octets.” Reserved: LOCATOR_INVALID, LOCATOR_KIND_INVALID, LOCATOR_KIND_RESERVED, LOCATOR_KIND_UDPv4, LOCATOR_KIND_UDPv6, LOCATOR_ADDRESS_INVALID, LOCATOR_PORT_INVALID.

Repo: crates/rtps/src/wire_types.rs (Locator, LocatorKind::{Invalid, Reserved, UdpV4, UdpV6}, Locator::INVALID, Locator::ADDRESS_INVALID, Locator::PORT_INVALID)

Tests: crates/rtps/src/wire_types.rs::tests::locator_invalid_constant_matches_spec, crates/rtps/src/wire_types.rs::tests::locator_reserved_constant_kind_is_zero, crates/rtps/src/wire_types.rs::tests::locator_udp_v4_any_kind_is_one, crates/rtps/src/wire_types.rs::tests::locator_udp_v6_any_kind_is_two, crates/rtps/src/wire_types.rs::tests::locator_roundtrip_le

Status: done — the values of the constants are listed under §9.3.2.4.

§8.2.1.2 Table 8.2 TopicKind_t

Spec: §8.2.1.2, p. 22, Table 8.2 — “Enumeration used to distinguish whether a Topic has defined some fields within to be used as the ‘key’ … NO_KEY, WITH_KEY”.

Repo: crates/rtps/src/wire_types.rs (TopicKind::{NoKey, WithKey}, EntityKind::topic_kind, TopicKind::writer_entity_kind, TopicKind::reader_entity_kind)

Tests: crates/rtps/src/wire_types.rs::tests::topic_kind_follows_entity_kind_octet_of_table_9_1, crates/rtps/src/wire_types.rs::tests::topic_kind_entity_kind_pairs_round_trip

Status: done

§8.2.1.2 Table 8.2 ChangeKind_t

Spec: §8.2.1.2, p. 22, Table 8.2 — “It can take the values: ALIVE, ALIVE_FILTERED, NOT_ALIVE_DISPOSED, NOT_ALIVE_UNREGISTERED”.

Repo: crates/rtps/src/history_cache.rs (ChangeKind::{Alive, AliveFiltered, NotAliveDisposed, NotAliveUnregistered, NotAliveDisposedUnregistered})

Tests: crates/rtps/src/history_cache.rs::tests::change_kind_distinct_variants, crates/rtps/src/history_cache.rs::tests::change_kind_alive_filtered_is_alive_but_not_relevant, crates/rtps/src/history_cache.rs::tests::change_kind_not_alive_kinds_are_not_alive

Status: done — NotAliveDisposedUnregistered is an additional combination for a PID_STATUS_INFO with both bits.

§8.2.1.2 Table 8.2 ChangeCount_t

Spec: §8.2.1.2, p. 22, Table 8.2 — “Type used to hold a counter representing the number of HistoryCache changes that belong to a certain category.”

Repo: crates/rtps/src/submessages.rs (GapSubmessage::filtered_count, Option<u64>)

Tests: crates/rtps/src/submessages.rs::tests::gap_filtered_count_is_eight_octets_high_then_low, crates/rtps/src/submessages.rs::tests::gap_with_filtered_count_roundtrip_le

Status: done — the counter is 64 bits wide (high, low; eight octets, §9.3.2.11).

§8.2.1.2 Table 8.2 ReliabilityKind_t

Spec: §8.2.1.2, p. 22, Table 8.2 — “Enumeration used to indicate the level of the reliability used for communications. It can take the values: BEST_EFFORT, RELIABLE.”

Repo: crates/qos/src/policies/reliability.rs (ReliabilityKind::{BestEffort, Reliable})

Tests: crates/qos/src/policies/reliability.rs::tests::try_from_u32_is_strict, crates/qos/src/policies/reliability.rs::tests::best_effort_lt_reliable

Status: done

§8.2.1.2 Table 8.2 InstanceHandle_t

Spec: §8.2.1.2, p. 22, Table 8.2 — “Type used to represent the identity of a data-object whose changes in value are communicated by the RTPS protocol.”

Repo: crates/rtps/src/history_cache.rs (CacheChange::key_hash); crates/dcps/src/instance_handle.rs (InstanceHandle)

Tests: crates/dcps/src/instance_handle.rs::tests::from_guid_distinguishes_keys, crates/rtps/src/history_cache.rs::tests::keep_last_per_instance_keeps_the_newest_of_each_instance

Status: done — at the RTPS level the KeyHash (§9.6.4.8) carries the identity of the instance.

§8.2.1.2 Table 8.2 ProtocolVersion_t

Spec: §8.2.1.2, p. 22, Table 8.2 — reserves PROTOCOLVERSION, PROTOCOLVERSION_1_0, _1_1, _2_0, _2_1, _2_2, _2_4; “PROTOCOLVERSION is an alias for the most recent version, in this case PROTOCOLVERSION_2_4”.

Repo: crates/rtps/src/wire_types.rs (ProtocolVersion::{V1_0, V1_1, V2_0, V2_1, V2_2, V2_3, V2_4, V2_5, CURRENT})

Tests: crates/rtps/src/wire_types.rs::tests::protocol_version_aliases_match_spec, crates/rtps/src/wire_types.rs::tests::protocol_version_all_aliases_roundtrip, crates/rtps/src/wire_types.rs::tests::protocol_version_default_is_2_5

Status: done — CURRENT is 2.5 per §8.3.3.1 (“protocol version 2.5”); the statement “in this case PROTOCOLVERSION_2_4” in Table 8.2 contradicts §8.3.3.1.

§8.2.1.2 Table 8.2 VendorId_t

Spec: §8.2.1.2, p. 22, Table 8.2 — “The possible values for the vendorId are assigned by the OMG. The following values are reserved by the protocol: VENDORID_UNKNOWN”.

Repo: crates/rtps/src/wire_types.rs (VendorId, VendorId::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::vendor_id_unknown_is_two_zero_octets, crates/rtps/src/wire_types.rs::tests::vendor_id_roundtrip

Status: done — the value ZeroDDS sends is listed under §8.3.3.1 (vendorId).

§8.2.1.3 Configuration attributes of the RTPS Entities

Spec: §8.2.1.3, p. 23, Figure 8.2 — configuration attributes of the entities; writer and reader attributes follow in §8.4.

Repo: —

Tests: —

Status: n/a (informative) — overview; the attributes are listed one by one in Table 8.8, Table 8.9 and §8.4.7/§8.4.10.

§8.2.2 HistoryCache: role on the writer and the reader side

Spec: §8.2.2, p. 23 — writer side: “the partial history of changes … needed to service existing and future matched RTPS Reader endpoints”; reader side: “the partial superposition of changes to data-objects made by all the matched RTPS Writer endpoints”.

Repo: crates/rtps/src/history_cache.rs (HistoryCache); crates/rtps/src/reliable_writer.rs (ReliableWriter, field cache); crates/rtps/src/reliable_reader.rs (ReliableReader)

Tests: crates/rtps/src/reliable_writer.rs::tests::keep_last_evicts_oldest_on_overflow, crates/rtps/src/reliable_reader.rs::tests::two_writers_with_overlapping_sn_spaces_both_delivered

Status: done

§8.2.2 Table 8.3 HistoryCache::changes

Spec: §8.2.2, p. 24, Table 8.3 — “changes: CacheChange[*] — The list of CacheChanges contained in the HistoryCache.”

Repo: crates/rtps/src/history_cache.rs (HistoryCache, get, iter_range, len)

Tests: crates/rtps/src/history_cache.rs::tests::insert_and_get, crates/rtps/src/history_cache.rs::tests::iter_range_is_ordered

Status: done

§8.2.2.1 HistoryCache new

Spec: §8.2.2.1, p. 25 — “This operation creates a new RTPS HistoryCache. The newly-created history cache is initialized with an empty list of changes.”

Repo: crates/rtps/src/history_cache.rs (HistoryCache::new, HistoryCache::new_with_kind)

Tests: crates/rtps/src/history_cache.rs::tests::new_cache_is_empty

Status: done

§8.2.2.2 HistoryCache add_change

Spec: §8.2.2.2, p. 25 — “This operation inserts the CacheChange a_change into the HistoryCache. This operation will only fail if there are not enough resources to add the change to the HistoryCache.”

Repo: crates/rtps/src/history_cache.rs (HistoryCache::insert, HistoryCache::insert_returning_evicted, CacheError)

Tests: crates/rtps/src/history_cache.rs::tests::insert_and_get, crates/rtps/src/history_cache.rs::tests::insert_at_capacity_is_err, crates/rtps/src/history_cache.rs::tests::insert_duplicate_is_err

Status: done — insert also refuses a sequence number already present; not observable from outside, since a writer assigns each number once.

§8.2.2.2 RESOURCE_LIMITS and propagation of errors to the DDS user

Spec: §8.2.2.2, p. 25 — “It is the responsibility of the DDS service implementation to configure the HistoryCache in a manner consistent with the DDS Entity RESOURCE_LIMITS QoS and to propagate any errors to the DDS-user in the manner specified by the DDS specification.”

Repo: crates/dcps/src/runtime.rs (await_writer_room); crates/rtps/src/history_cache.rs (HistoryKind, HistoryCache::set_per_instance_depth)

Tests: crates/dcps/tests/reader_history_resource_limits.rs::a_writer_refuses_an_instance_beyond_its_own_max_instances, crates/dcps/tests/reader_history_resource_limits.rs::keep_all_max_samples_total_rejects_when_reliable, crates/dcps/tests/reader_room_backpressure.rs::a_full_keep_all_reader_blocks_its_writer_and_loses_nothing

Status: done

§8.2.2.3 HistoryCache remove_change

Spec: §8.2.2.3, p. 25 — “This operation indicates that a previously-added CacheChange should be removed from the HistoryCache … The determination of which changes should be removed from the cache is made based on the QoS associated with the related DDS entity and on the acknowledgment status of the CacheChange.”

Repo: crates/rtps/src/history_cache.rs (HistoryCache::remove_up_to, remove_up_to_with, remove_highest); crates/rtps/src/reliable_writer.rs (ReliableWriter::remove_samples_up_to)

Tests: crates/rtps/src/history_cache.rs::tests::remove_up_to_inclusive, crates/rtps/src/history_cache.rs::tests::remove_up_to_with_no_matches_is_noop, crates/rtps/src/reliable_writer.rs::tests::the_unacked_window_fills_and_acknowledgements_free_it

Status: done

§8.2.2.4 HistoryCache get_seq_num_min

Spec: §8.2.2.4, p. 25 — “This operation retrieves the smallest value of the CacheChange::sequenceNumber attribute among the CacheChange stored in the HistoryCache.”

Repo: crates/rtps/src/history_cache.rs (HistoryCache::min_sn)

Tests: crates/rtps/src/history_cache.rs::tests::min_max_sn_reflect_content

Status: done

§8.2.2.5 HistoryCache get_seq_num_max

Spec: §8.2.2.5, p. 25 — “This operation retrieves the largest value of the CacheChange::sequenceNumber attribute among the CacheChange stored in the HistoryCache.”

Repo: crates/rtps/src/history_cache.rs (HistoryCache::max_sn)

Tests: crates/rtps/src/history_cache.rs::tests::min_max_sn_reflect_content

Status: done

§8.2.3 Table 8.5 CacheChange::kind

Spec: §8.2.3, p. 26, Table 8.5 — “kind: ChangeKind_t — Identifies the kind of change.”

Repo: crates/rtps/src/history_cache.rs (CacheChange::kind); crates/rtps/src/reliable_reader.rs (DeliveredSample::kind)

Tests: crates/rtps/src/history_cache.rs::tests::cache_change_alive_constructor, crates/rtps/src/reliable_reader.rs::tests::dispose_data_yields_not_alive_disposed, crates/rtps/src/reliable_reader.rs::tests::unregister_data_yields_not_alive_unregistered

Status: done

§8.2.3 Table 8.5 CacheChange::writerGuid

Spec: §8.2.3, p. 26, Table 8.5 — “writerGuid: GUID_t — The GUID_t that identifies the RTPS Writer that made the change”.

Repo: crates/rtps/src/reliable_reader.rs (DeliveredSample::writer_guid); writer side implicit, one HistoryCache per writer.

Tests: crates/rtps/src/reliable_reader.rs::tests::two_writers_with_overlapping_sn_spaces_both_delivered, crates/rtps/src/reliable_reader.rs::tests::same_entity_id_different_prefix_not_confused

Status: done

§8.2.3 Table 8.5 CacheChange::instanceHandle

Spec: §8.2.3, p. 26, Table 8.5 — “instanceHandle: InstanceHandle_t — Identifies the instance of the data-object to which the change applies.”

Repo: crates/rtps/src/history_cache.rs (CacheChange::key_hash); crates/rtps/src/reliable_reader.rs (DeliveredSample::key_hash)

Tests: crates/rtps/src/history_cache.rs::tests::the_instance_index_follows_inserts_evictions_and_removals, crates/rtps/src/reliable_writer.rs::tests::keyed_alive_preserves_inline_hash_on_data_fragments_and_rebuilds

Status: done

§8.2.3 Table 8.5 CacheChange::sequenceNumber

Spec: §8.2.3, p. 26, Table 8.5 — “sequenceNumber: SequenceNumber_t — Sequence number assigned by the RTPS Writer to uniquely identify the change.”

Repo: crates/rtps/src/history_cache.rs (CacheChange::sequence_number)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_increments_sn_and_returns_data_datagram, crates/rtps/src/writer.rs::tests::writer_increments_sequence_number_per_write

Status: done

§8.2.3 Table 8.5 CacheChange::data_value

Spec: §8.2.3, p. 26, Table 8.5 — “data_value: Data — The data value associated with the change. Depending on the kind of CacheChange, there may be no associated data.”

Repo: crates/rtps/src/history_cache.rs (CacheChange::payload, CacheChange::lifecycle)

Tests: crates/rtps/src/history_cache.rs::tests::cache_change_alive_constructor, crates/rtps/src/reliable_writer.rs::tests::lifecycle_without_a_key_clears_k_and_sends_no_payload

Status: done

§8.2.3 Table 8.5 CacheChange::inlineQos

Spec: §8.2.3, p. 26, Table 8.5 — “inlineQos: ParameterList — Contains QoS that may affect the interpretation of the CacheChange::data_value.”

Repo: crates/rtps/src/history_cache.rs (CacheChange::inline_qos, CacheChange::with_inline_qos); reader side: crates/rtps/src/reliable_reader.rs (DeliveredSample with the evaluated parameters key_hash, coherent_set_sn, related_sample_identity)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_reader_that_expects_inline_qos_gets_the_writers_qos_with_each_data, crates/rtps/src/reliable_reader.rs::tests::delivered_sample_carries_the_coherent_set_marker

Status: done

§8.2.4 Table 8.6 Entity::guid

Spec: §8.2.4, p. 26, Table 8.6 — “guid: GUID_t — Globally and uniquely identifies the RTPS Entity within the DDS domain. Maps to the value of the DDS BuiltinTopicKey_t”.

Repo: crates/rtps/src/wire_types.rs (Guid); crates/dcps/src/builtin_topics.rs (key of the builtin topic data)

Tests: crates/rtps/src/wire_types.rs::tests::guid_layout_is_prefix_then_entity_id, crates/dcps/src/instance_handle.rs::tests::from_guid_distinguishes_keys

Status: done

§8.2.4.1 Table 8.7 GUID = <prefix, entityId>

Spec: §8.2.4.1, pp. 26–27, Table 8.7 — “The GUID is built as a tuple <prefix, entityId> combining a GuidPrefix_t prefix and an EntityId_t entityId.”

Repo: crates/rtps/src/wire_types.rs (Guid::new, Guid::to_bytes)

Tests: crates/rtps/src/wire_types.rs::tests::guid_layout_is_prefix_then_entity_id

Status: done

§8.2.4.2 Participant GUID <prefix, ENTITYID_PARTICIPANT>

Spec: §8.2.4.2, p. 27 — “Every Participant has GUID <prefix, ENTITYID_PARTICIPANT>”.

Repo: crates/rtps/src/wire_types.rs (EntityId::PARTICIPANT); crates/dcps/src/participant.rs (random_guid_prefix)

Tests: crates/rtps/src/wire_types.rs::tests::entity_id_participant_constant, crates/dcps/src/participant.rs::tests::random_guid_prefixes_share_host_id_within_process

Status: done

§8.2.4.2 Prefix unique in the domain

Spec: §8.2.4.2, p. 27 — “The implementation is free to choose the prefix, as long as every Participant in the Domain has a unique GUID.”

Repo: crates/dcps/src/participant.rs (next_process_unique, namespaced_pid, process_unique); crates/dcps/src/runtime.rs (DcpsRuntime::prefix_collisions)

Tests: crates/dcps/src/participant.rs::tests::the_prefixes_of_one_process_are_pairwise_different, crates/dcps/src/participant.rs::tests::two_pid_namespaces_with_the_same_pid_give_different_prefixes, crates/dcps/src/runtime.rs::tests::a_beacon_with_the_own_prefix_from_another_participant_is_counted

Status: done — the prefixes of the participants of one process are pairwise different (counter of the process, 65536 per process, also for the C API and the bridges); across processes and hosts the construction prevents the collision (item “Prefix uniqueness across hosts and processes”).

§8.2.4.2 Prefix uniqueness across hosts and processes

Spec: §8.2.4.2, p. 27 — “every Participant in the Domain has a unique GUID”.

Repo: crates/dcps/src/participant.rs (namespaced_pid, pid_namespace_inode, next_process_unique, process_unique); crates/dcps/src/runtime.rs (DcpsRuntime::prefix_collisions, same_process)

Tests: crates/dcps/src/participant.rs::tests::two_pid_namespaces_with_the_same_pid_give_different_prefixes, crates/dcps/src/participant.rs::tests::the_prefixes_of_one_process_share_ten_octets_and_differ_in_the_tail, crates/dcps/src/participant.rs::tests::random_guid_prefixes_share_host_id_within_process, crates/dcps/src/runtime.rs::tests::a_beacon_with_the_own_prefix_from_another_participant_is_counted

Status: done — the prefix consists of the VendorId, the host value (4 octets), the process id and a process part (a seed from the operating system’s randomness plus a counter of the process). The process id carries the mark of the PID namespace (namespaced_pid: XOR with a mask from the inode of /proc/self/ns/pid, zero in the initial namespace, one-to-one within a namespace). Containers with the host’s network (the same host value) and a PID namespace of their own whose first process has the number 1 therefore carry different prefixes. same_process (first ten octets) and same_host (host value) read as before. Remaining collision: two different host names with the same 32-bit hash, the same marked process id and the same process part; DcpsRuntime::prefix_collisions counts an SPDP beacon with the own prefix and foreign locators.

§8.2.4.3 GUID of an endpoint group

Spec: §8.2.4.3, p. 27 — “The endpoint Groups contained by a Participant with GUID <participantPrefix, ENTITYID_PARTICIPANT> have the GUID <participantPrefix, entityId>. The entityId is the unique identification of the Group relative to the Participant.”

Repo: crates/dcps/src/publisher.rs (PublisherInner::entity_id), crates/dcps/src/subscriber.rs (SubscriberInner::entity_id), crates/dcps/src/runtime.rs (build_publication_data, build_subscription_data: group_guid)

Tests: crates/rtps/src/publication_data.rs::tests::the_writers_group_travels_as_pid_group_guid, crates/rtps/src/wire_types.rs::tests::every_kind_table_9_1_names_decodes_to_a_named_kind

Status: done

§8.2.4.4 GUID of the endpoints of a participant

Spec: §8.2.4.4, p. 27 — “The Endpoints contained by a Participant with GUID <participantPrefix, ENTITYID_PARTICIPANT> have the GUID <participantPrefix, entityId>. The entityId is the unique identification of the Endpoint relative to the Participant.”

Repo: crates/dcps/src/runtime.rs (next_entity_key, entity_key_in_use, held_entity_keys, release_entity_key); crates/dcps/src/publisher.rs, crates/dcps/src/subscriber.rs (Drop of the inner types)

Tests: crates/dcps/src/runtime.rs::tests::a_wrapped_entity_key_counter_skips_the_key_of_a_live_writer, crates/dcps/src/runtime.rs::tests::a_wrapped_entity_key_counter_skips_reserved_and_group_keys_until_they_are_given_back

Status: done — the 3-octet key comes from a counter; after the 24 bits wrap, a key is skipped that a registered writer, reader, an announced topic, a reserved id that is not registered yet or a group id (publisher, subscriber) holds; a key that is given back is free again.

§8.2.5 Table 8.8 Participant::defaultUnicastLocatorList

Spec: §8.2.5, p. 28, Table 8.8 — “Default list of unicast locators … These are the unicast locators that will be used in case the Endpoint does not specify its own set of Locators.”

Repo: crates/rtps/src/participant_data.rs (ParticipantBuiltinTopicData::default_unicast_locators)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done — the endpoint’s fallback to the default locators is listed under §8.5.5.1.

§8.2.5 Table 8.8 Participant::defaultMulticastLocatorList

Spec: §8.2.5, p. 28, Table 8.8 — “Default list of multicast locators … used in case the Endpoint does not specify its own set of Locators.”

Repo: crates/rtps/src/participant_data.rs (ParticipantBuiltinTopicData::default_multicast_locators)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§8.2.5 Table 8.8 Participant::protocolVersion

Spec: §8.2.5, p. 28, Table 8.8 — “protocolVersion: ProtocolVersion_t — Identifies the version of the RTPS protocol that the Participant uses to communicate.”

Repo: crates/rtps/src/participant_data.rs (ParticipantBuiltinTopicData::protocol_version); crates/rtps/src/header.rs (RtpsHeader::new)

Tests: crates/rtps/src/header.rs::tests::header_protocol_version_at_bytes_4_5, crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§8.2.5 Table 8.8 Participant::vendorId

Spec: §8.2.5, p. 28, Table 8.8 — “vendorId: VendorId_t — Identifies the vendor of the RTPS middleware that contains the Participant.”

Repo: crates/rtps/src/participant_data.rs (ParticipantBuiltinTopicData::vendor_id); crates/rtps/src/header.rs

Tests: crates/rtps/src/header.rs::tests::header_vendor_id_at_bytes_6_7, crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§8.2.6 RTPS Group: a publisher contains writers, a subscriber readers

Spec: §8.2.6, pp. 28–29 — “The RTPS Publisher contains RTPS Writer endpoints. The RTPS Publisher maps to a DDS Publisher. The RTPS Subscriber contains RTPS Reader endpoints. The RTPS Subscriber maps to a DDS Subscriber.”

Repo: crates/dcps/src/publisher.rs (Publisher::create_datawriter); crates/dcps/src/subscriber.rs (Subscriber::create_datareader)

Tests: crates/dcps/tests/entity_deletion.rs::a_writer_of_another_publisher_is_left_as_it_was, crates/dcps/tests/entity_deletion.rs::a_reader_of_another_subscriber_is_left_as_it_was, crates/dcps/tests/entity_deletion.rs::publisher_delete_contained_entities_deletes_every_writer

Status: done — the GUID of the group is listed under §8.2.4.3.

§8.2.7 Table 8.9 Endpoint::unicastLocatorList

Spec: §8.2.7, p. 29, Table 8.9 — “List of unicast locators … that can be used to send messages to the Endpoint. The list may be empty.”

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::unicast_locators); crates/rtps/src/subscription_data.rs (SubscriptionBuiltinTopicData::unicast_locators)

Tests: crates/rtps/src/publication_data.rs::tests::endpoint_locators_roundtrip_le

Status: done — the reader side uses the same helpers (encode_locator_params, collect_locator_params); its test is listed under §8.5.4.4.

§8.2.7 Table 8.9 Endpoint::multicastLocatorList

Spec: §8.2.7, p. 29, Table 8.9 — “List of multicast locators … that can be used to send messages to the Endpoint. The list may be empty.”

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::multicast_locators); crates/rtps/src/subscription_data.rs (SubscriptionBuiltinTopicData::multicast_locators)

Tests: crates/rtps/src/publication_data.rs::tests::endpoint_locators_roundtrip_le

Status: done — the reader side uses the same helpers; its test is listed under §8.5.4.4.

§8.2.7 Table 8.9 Endpoint::reliabilityLevel

Spec: §8.2.7, p. 29, Table 8.9 — “reliabilityLevel: ReliabilityKind_t — The levels of reliability supported by the Endpoint. Maps to the RELIABILITY QoS ‘kind.’”

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::reliability); crates/rtps/src/writer.rs (BestEffortWriter); crates/rtps/src/reliable_writer.rs (ReliableWriter)

Tests: crates/rtps/src/publication_data.rs::tests::roundtrip_le, crates/rtps/src/reliable_reader.rs::tests::best_effort_reader_skips_leading_gap

Status: done

§8.2.7 Table 8.9 Endpoint::topicKind

Spec: §8.2.7, p. 29, Table 8.9 — “topicKind: TopicKind_t — Used to indicate whether the Endpoint supports instance lifecycle management operations (see 8.7.4).”

Repo: crates/rtps/src/wire_types.rs (EntityKind::topic_kind); crates/dcps/src/publisher.rs (choice of the entityKind from DdsType::HAS_KEY)

Tests: crates/dcps/src/publisher.rs::tests::live_datawriter_entity_kind_is_nokey_for_keyless_type, crates/rtps/src/wire_types.rs::tests::topic_kind_of_the_predefined_entity_ids

Status: done

§8.2.7 Table 8.9 Endpoint::endpointGroup

Spec: §8.2.7, p. 29, Table 8.9 — “endpointGroup: EntityId_t — Used to identify the RTPS Group (Publisher or Subscriber) to which the Endpoint belongs.”

Repo: crates/dcps/src/runtime.rs (UserWriterConfig::group_entity_id, UserReaderConfig::group_entity_id)

Tests: crates/rtps/src/publication_data.rs::tests::the_writers_group_travels_as_pid_group_guid

Status: done

§8.2.8 An RTPS Writer belongs to a publisher

Spec: §8.2.8, pp. 29–30 — “Its role is to transfer all CacheChange changes in its HistoryCache to the HistoryCache of the matching remote RTPS Readers. An RTPS Writer belongs to an RTPS Group of type Publisher.”

Repo: crates/dcps/src/publisher.rs (Publisher::create_datawriter); crates/rtps/src/reliable_writer.rs (ReliableWriter)

Tests: crates/dcps/tests/entity_deletion.rs::delete_publisher_refuses_a_publisher_with_writers, crates/rtps/tests/reliable_e2e.rs::e2e_zero_loss_delivers_all_in_order

Status: done

§8.2.9 An RTPS Reader belongs to a subscriber

Spec: §8.2.9, p. 30 — “RTPS Reader specializes RTPS Endpoint and represents the actor that receives CacheChange messages from the matched RTPS Writer endpoints. An RTPS Reader belongs to an RTPS Group of type Subscriber.”

Repo: crates/dcps/src/subscriber.rs (Subscriber::create_datareader); crates/rtps/src/reliable_reader.rs (ReliableReader)

Tests: crates/dcps/tests/entity_deletion.rs::a_reader_of_another_subscriber_is_left_as_it_was, crates/rtps/tests/reliable_e2e.rs::e2e_10_percent_loss_delivers_all_in_order

Status: done

§8.2.10 Relation to DDS Entities

Spec: §8.2.10, p. 30 — “How exactly a DDS Entity interacts with the HistoryCache however, is implementation specific and not formally modeled by the RTPS protocol.”

Repo: —

Tests: —

Status: n/a (informative) — explains the transitions; they are listed one by one under §8.2.10.1 and §8.2.10.2.

§8.2.10.1 DataWriter: every change is relevant to every reader

Spec: §8.2.10.1, pp. 30–31 — “By default, all changes in the HistoryCache are considered relevant for each matching remote RTPS Reader. … The Reader itself will always filter.”

Repo: crates/rtps/src/reliable_writer.rs (ReliableWriter::write, delivery to every ReaderProxy)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_fans_out_to_all_reader_proxies

Status: done — the reader-side filter is listed under §8.7.3.

§8.2.10.1 Table 8.11 DataWriter T1 (new DDS DataWriter)

Spec: §8.2.10.1, p. 32, Table 8.11 T1 — “the_rtps_writer = new RTPS::Writer; the_dds_writer.related_rtps_writer := the_rtps_writer;”

Repo: crates/dcps/src/publisher.rs (Publisher::create_datawriter); crates/dcps/src/runtime.rs (register_user_writer_as)

Tests: crates/dcps/src/publisher.rs::tests::live_datawriter_entity_kind_is_nokey_for_keyless_type, crates/dcps/tests/entity_lifecycle.rs::datawriter_and_datareader_follow_their_factories_entity_factory_policy

Status: done

§8.2.10.1 Table 8.11 DataWriter T2 (write)

Spec: §8.2.10.1, p. 32, Table 8.11 T2 — “a_change := the_rtps_writer.new_change(ALIVE, data, inlineQos, handle); the_rtps_writer.writer_cache.add_change(a_change);” postcondition “the_rtps_writer.writer_cache.get_seq_num_max() == a_change.sequenceNumber”.

Repo: crates/dcps/src/publisher.rs (DataWriter::write); crates/rtps/src/reliable_writer.rs (ReliableWriter::write)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_increments_sn_and_returns_data_datagram, crates/rtps/src/reliable_writer.rs::tests::heartbeat_carries_cache_range

Status: done

§8.2.10.1 Table 8.11 DataWriter T3 (dispose, WITH_KEY)

Spec: §8.2.10.1, p. 32 — “if (the_rtps_writer.topicKind == WITH_KEY) { a_change := the_rtps_writer.new_change(NOT_ALIVE_DISPOSED, , inlineQos, handle); the_rtps_writer.writer_cache.add_change(a_change); }”

Repo: crates/dcps/src/publisher.rs (DataWriter::dispose_w_timestamp); crates/dcps/src/runtime.rs (write_user_lifecycle); crates/rtps/src/reliable_writer.rs (ReliableWriter::write_lifecycle)

Tests: crates/dcps/tests/lifecycle_wire_e2e.rs::linux::dispose_propagates_over_wire_to_reader, crates/rtps/src/reliable_writer.rs::tests::lifecycle_with_a_key_sets_k_and_carries_it

Status: done

§8.2.10.1 Table 8.11 DataWriter T4 (unregister, WITH_KEY)

Spec: §8.2.10.1, p. 33 — “if (the_rtps_writer.topicKind == WITH_KEY) { a_change := the_rtps_writer.new_change(NOT_ALIVE_UNREGISTERED, , inlineQos, handle); the_rtps_writer.writer_cache.add_change(a_change); }”

Repo: crates/dcps/src/publisher.rs (DataWriter::unregister_instance_w_timestamp); crates/dcps/src/runtime.rs (write_user_lifecycle)

Tests: crates/dcps/tests/lifecycle_wire_e2e.rs::linux::unregister_with_autodispose_false_propagates_unregister_only, crates/rtps/src/reliable_reader.rs::tests::unregister_data_yields_not_alive_unregistered

Status: done

§8.2.10.1 T3/T4 without effect for NO_KEY

Spec: §8.2.10.1, pp. 32–33 — dispose and unregister: “This operation has no effect if the topicKind==NO_KEY.”

Repo: crates/dcps/src/runtime.rs (write_user_lifecycle_with, keyless_lifecycle_not_sent); writer.keyless_lifecycle_on_wire

Tests: crates/dcps/src/runtime.rs::tests::dispose_and_unregister_of_a_no_key_writer_send_no_marker_unless_asked_for, crates/dcps/tests/runtime_config_layering.rs::the_heartbeat_digest_and_keyless_lifecycle_settings_are_read_from_yaml, crates/dcps/tests/keyless_instance.rs::the_writer_disposes_the_one_instance_of_a_keyless_topic

Status: done — dispose and unregister of a writer without a key create no change and send no marker (counted in DcpsRuntime::keyless_lifecycle_not_sent); the writer’s own instance state changes (DDS 1.4 §2.2.1.2.2: one instance). writer.keyless_lifecycle_on_wire (environment ZERODDS_WRITER_KEYLESS_LIFECYCLE_ON_WIRE) sends the marker (status bits only) for a peer that expects it. Expected from the vendors: readers of topics without a key no longer see NOT_ALIVE_DISPOSED from ZeroDDS writers; whether Cyclone DDS, Fast DDS or OpenDDS themselves send a marker for NO_KEY is not measured.

§8.2.10.1 Table 8.11 DataWriter T5 (delete DDS DataWriter)

Spec: §8.2.10.1, p. 33 — “delete the_dds_writer.related_rtps_writer;”

Repo: crates/dcps/src/publisher.rs (Publisher::delete_datawriter)

Tests: crates/dcps/tests/entity_deletion.rs::delete_datawriter_deletes_the_writer_behind_every_handle, crates/dcps/tests/entity_deletion.rs::the_last_handle_deletes_the_writer

Status: done

§8.2.10.2 DataReader: read and take access the HistoryCache

Spec: §8.2.10.2, p. 33 — “The changes returned to the user are those in the HistoryCache that pass all Reader specific filters, if any.”

Repo: crates/dcps/src/subscriber.rs (DataReader::read, DataReader::take)

Tests: crates/dcps/tests/sample_info_lifecycle.rs::reader_take_filtered_with_state_mask_filters

Status: done

§8.2.10.2 Table 8.12 DataReader T1 (new DDS DataReader)

Spec: §8.2.10.2, p. 34, Table 8.12 T1 — “the_rtps_reader = new RTPS::Reader; the_dds_reader.related_rtps_reader := the_rtps_reader;”

Repo: crates/dcps/src/subscriber.rs (Subscriber::create_datareader); crates/dcps/src/runtime.rs (register_user_reader)

Tests: crates/dcps/tests/entity_lifecycle.rs::datawriter_and_datareader_follow_their_factories_entity_factory_policy

Status: done

§8.2.10.2 Table 8.12 DataReader T2 (read)

Spec: §8.2.10.2, p. 34 — “Changes returned to the application remain in the RTPS Reader’s HistoryCache such that subsequent read or take operations can find them again.”

Repo: crates/dcps/src/subscriber.rs (DataReader::read, DataReader::read_with_info)

Tests: crates/dcps/tests/sample_info_lifecycle.rs::reader_read_marks_sample_state_read, crates/dcps/tests/reader_history_resource_limits.rs::plain_read_keep_last_1_keeps_only_the_newest_per_instance_and_is_idempotent

Status: done

§8.2.10.2 Table 8.12 DataReader T3 (take)

Spec: §8.2.10.2, pp. 34–35 — “Changes returned to the application are removed from the RTPS Reader’s HistoryCache such that subsequent read or take operations do not find the same change.”

Repo: crates/dcps/src/subscriber.rs (DataReader::take, DataReader::take_with_info)

Tests: crates/dcps/tests/sample_info_lifecycle.rs::reader_take_next_instance_consumes, crates/dcps/tests/sample_info_lifecycle.rs::reader_view_state_transitions_to_not_new_on_second_sample

Status: done

§8.2.10.2 Table 8.12 DataReader T4 (delete DDS DataReader)

Spec: §8.2.10.2, p. 35 — “delete the_dds_reader.related_rtps_reader;”

Repo: crates/dcps/src/subscriber.rs (Subscriber::delete_datareader)

Tests: crates/dcps/tests/entity_deletion.rs::delete_datareader_refuses_a_reader_that_holds_conditions, crates/dcps/tests/entity_deletion.rs::lookup_datareader_hands_out_a_handle_to_the_same_reader

Status: done


§8.3 Messages Module

§8.3.1 Overview

Spec: §8.3.1, p. 35 — structure of the module; “The number of Submessages that can be sent in a single RTPS Message is only limited by the maximum message size the underlying transport can support.”

Repo: —

Tests: —

Status: n/a (informative) — structure; the requirements follow in §8.3.2–§8.3.8.

§8.3.2 Table 8.13 ProtocolId_t (PROTOCOL_RTPS)

Spec: §8.3.2, p. 35, Table 8.13 — “ProtocolId_t: Enumeration used to identify the protocol. The following values are reserved by the protocol: PROTOCOL_RTPS”.

Repo: crates/rtps/src/header.rs (RTPS_MAGIC)

Tests: crates/rtps/src/header.rs::tests::header_layout_first_four_bytes_are_rtps_magic, crates/rtps/src/header.rs::tests::header_decode_rejects_invalid_magic

Status: done

§8.3.2 Table 8.13 SubmessageFlag

Spec: §8.3.2, p. 35, Table 8.13 — “A Submessage flag takes a boolean value and affects the parsing of the Submessage by the receiver.”

Repo: crates/rtps/src/submessage_header.rs (SubmessageHeader::flags, FLAG_E_LITTLE_ENDIAN); flag constants in crates/rtps/src/submessages.rs

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_header_is_little_endian_flag, crates/rtps/src/datagram.rs::tests::decode_heartbeat_preserves_final_and_liveliness_flags

Status: done

§8.3.2 Table 8.13 SubmessageKind

Spec: §8.3.2, p. 36, Table 8.13 — reserves “RTPS_HE, DATA, GAP, HEARTBEAT, ACKNACK, PAD, INFO_TS, INFO_REPLY, INFO_DST, INFO_SRC, DATA_FRAG, NACK_FRAG, HEARTBEAT_FRAG”.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId); crates/rtps/src/header_extension.rs (SUBMESSAGE_ID_HEADER_EXTENSION)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_octets_match_spec_table_8_13, crates/rtps/tests/cyclone_he_must_understand.rs::local_encoder_produces_must_understand_bit, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.2 Table 8.13 Time_t

Spec: §8.3.2, p. 36, Table 8.13 — “Type used to hold a timestamp. Should have at least nano-second resolution. The following values are reserved by the protocol: TIME_ZERO, TIME_INVALID, TIME_INFINITE”.

Repo: crates/rtps/src/header_extension.rs (HeTimestamp, TIME_INVALID, TIME_INFINITE); crates/dcps/src/time.rs

Tests: crates/rtps/src/submessages.rs::validity_tests::time_t_seconds_are_unsigned, crates/dcps/src/time.rs::tests::the_reserved_time_t_values_cross_the_wire_as_the_spec_gives_them

Status: done — seconds is unsigned (u32, §9.3.2.1), the three reserved values TIME_ZERO, TIME_INVALID and TIME_INFINITE are constants and go on the wire with the values of the spec. The DCPS Time counts seconds as a long; the octets are the same.

§8.3.2 Table 8.13 Count_t

Spec: §8.3.2, p. 36, Table 8.13 — “Type used to hold a count that is incremented monotonically, used to identify message duplicates.”

Repo: crates/rtps/src/submessages.rs (HeartbeatSubmessage::count, AckNackSubmessage::count, HeartbeatFragSubmessage::count, NackFragSubmessage::count, each i32)

Tests: crates/rtps/src/reliable_writer.rs::tests::heartbeat_count_increments, crates/rtps/src/reliable_writer.rs::tests::heartbeat_count_wraps_around_at_i32_max_per_spec_8_4_15_7

Status: done — the receiver’s use of the counter is listed under §8.3.8.1, §8.3.8.6 and §8.4.15.7.

§8.3.2 Table 8.13 Checksum_t

Spec: §8.3.2, p. 36, Table 8.13 — “Type used to hold a checksum. Used to detect RTPS message corruption by the underlying transport. The following values are reserved by the protocol: CHECKSUM_INVALID.”

Repo: crates/rtps/src/header_extension.rs (ChecksumValue::{None, Crc32c, Crc64, Md5})

Tests: crates/rtps/src/header_extension.rs::tests::checksum_value_kind_matches, crates/rtps/src/header_extension.rs::tests::checksum_kind_wire_size

Status: done — ChecksumValue::None stands for CHECKSUM_INVALID.

§8.3.2 Table 8.13 MessageLength_t

Spec: §8.3.2, p. 36, Table 8.13 — “Type used to hold the length of an RTPS Message. The following values are reserved by the protocol: MESSAGE_LENGTH_INVALID”.

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::message_length: Option<u32>); crates/rtps/src/receiver_state.rs (ReceiverState::message_length)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_message_length_only_le, crates/rtps/src/receiver_state.rs::tests::new_state_has_default_fields

Status: done — None stands for MESSAGE_LENGTH_INVALID.

§8.3.2 Table 8.13 ParameterId_t

Spec: §8.3.2, p. 36, Table 8.13 — “Type used to uniquely identify a parameter in a parameter list. … A range of values is reserved for protocol-defined parameters, while another range can be used for vendor-defined parameters”.

Repo: crates/rtps/src/parameter_list.rs (Parameter::id: u16, VENDOR_SPECIFIC_BIT, MUST_UNDERSTAND_BIT)

Tests: crates/rtps/src/parameter_list.rs::tests::a_vendor_specific_must_understand_pid_of_another_vendor_is_an_error, crates/rtps/src/parameter_list.rs::tests::must_understand_unknown_optional_pid_skips

Status: done — the split into ranges is listed under §8.3.5.9 and §9.4.2.11.

§8.3.2 Table 8.13 FragmentNumber_t

Spec: §8.3.2, p. 36, Table 8.13 — “Type used to hold fragment numbers. Must be possible to represent using 32 bits.”

Repo: crates/rtps/src/wire_types.rs (FragmentNumber(u32))

Tests: crates/rtps/src/wire_types.rs::tests::fragment_number_wire_size_is_four, crates/rtps/src/wire_types.rs::tests::fragment_number_roundtrip_le_be

Status: done

§8.3.2 Table 8.13 GroupDigest_t

Spec: §8.3.2, p. 36, Table 8.13 — “Type used to hold a digest value that uniquely identifies a group of Entities belonging to the same Participant.”

Repo: crates/rtps/src/group_digest.rs (GroupDigest, GroupDigest::of_entities)

Tests: crates/rtps/src/group_digest.rs::tests::two_writers_digest_as_section_9_3_2_5_computes_it, crates/rtps/src/group_digest.rs::tests::the_digest_does_not_depend_on_the_order_given, crates/rtps/src/group_digest.rs::tests::the_empty_group_is_zero_and_not_the_hash_of_an_empty_sequence

Status: done

§8.3.2 Table 8.13 UExtension4_t

Spec: §8.3.2, p. 36, Table 8.13 — “Type used to hold an undefined 4-byte value. It is intended to be used in future revisions of the specification.”

Repo: crates/rtps/src/wire_types.rs (UExtension4)

Tests: crates/rtps/src/wire_types.rs::tests::uextension4_roundtrip

Status: done

§8.3.2 Table 8.13 WExtension8_t

Spec: §8.3.2, p. 36, Table 8.13 — “Type used to hold an undefined 8-byte value. It is intended to be used in future revisions of the specification.”

Repo: crates/rtps/src/wire_types.rs (WExtension8)

Tests: crates/rtps/src/wire_types.rs::tests::wextension8_roundtrip

Status: done

§8.3.3 Message = header + submessages

Spec: §8.3.3, p. 36 — “The overall structure of an RTPS Message consists of a fixed-size leading RTPS Header followed by a variable number of RTPS Submessage parts. Each Submessage in turn consists of a SubmessageHeader and a variable number of SubmessageElements.”

Repo: crates/rtps/src/datagram.rs (decode_datagram, encode_datagram); crates/rtps/src/message_builder.rs (MessageBuilder)

Tests: crates/rtps/src/datagram.rs::tests::encode_decode_two_data_submessages, crates/rtps/tests/vendor_frames.rs::cyclone_datagrams_re_encode_byte_for_byte

Status: done

§8.3.3 Message length from the transport or the HeaderExtension

Spec: §8.3.3, p. 37 — “The length may also be sent by the underlying transport that carries the RTPS message. In this case it may be omitted from the HeaderExtension. … a stream-oriented transport (like TCP) would need to include the length in the RTPS HeaderExtension”.

Repo: crates/rtps/src/datagram.rs (decode_datagram: length from the UDP datagram)

Tests: crates/rtps/src/datagram.rs::tests::decode_handles_last_submessage_zero_length

Status: done — for UDP (§9) the transport carries the length; the TCP mapping is not part of the UDP/IP PSM.

§8.3.3.1 Header at the start of every message

Spec: §8.3.3.1, p. 37 — “The RTPS Header must appear at the beginning of every message.”

Repo: crates/rtps/src/header.rs (RtpsHeader::to_bytes, RtpsHeader::from_bytes); crates/rtps/src/datagram.rs (decode_datagram)

Tests: crates/rtps/src/datagram.rs::tests::decode_rejects_invalid_magic, crates/rtps/src/writer.rs::tests::writer_produces_decodable_datagram

Status: done

§8.3.3.1 Table 8.14 Header.protocol = PROTOCOL_RTPS

Spec: §8.3.3.1, p. 38 — “The protocol identifies the message as an RTPS message. This value is set to PROTOCOL_RTPS.”

Repo: crates/rtps/src/header.rs (RTPS_MAGIC, RtpsHeader::to_bytes)

Tests: crates/rtps/src/header.rs::tests::header_layout_first_four_bytes_are_rtps_magic

Status: done

§8.3.3.1 Table 8.14 Header.version = 2.5

Spec: §8.3.3.1, p. 38 — “Implementations following this version of the document implement protocol version 2.5 (major = 2, minor = 5) and have this field set to PROTOCOLVERSION.”

Repo: crates/rtps/src/header.rs (RtpsHeader::new sets ProtocolVersion::V2_5)

Tests: crates/rtps/src/header.rs::tests::header_protocol_version_at_bytes_4_5

Status: done

§8.3.3.1 Table 8.14 Header.vendorId

Spec: §8.3.3.1, p. 38 — “The vendorId identifies the vendor of the middleware that implemented the RTPS protocol … The possible values for the vendorId are assigned by the OMG.”

Repo: crates/rtps/src/header.rs (RtpsHeader::vendor_id); crates/rtps/src/wire_types.rs (VendorId::ZERODDS = [0x01, 0xF0])

Tests: crates/rtps/src/header.rs::tests::header_vendor_id_at_bytes_6_7, crates/rtps/src/wire_types.rs::tests::vendor_id_zerodds_constant

Status: partial — the field is sent and read; ZeroDDS sends 0x01F0, according to the comment on VendorId::ZERODDS an interim value and not one assigned by the OMG (a blocked item of its own under §8.3.5.2).

§8.3.3.1 Table 8.14 Header.guidPrefix

Spec: §8.3.3.1, p. 38 — “The guidPrefix defines a default prefix that can be used to reconstruct the Globally Unique Identifiers (GUIDs) that appear within the Submessages contained in the message.”

Repo: crates/rtps/src/header.rs (RtpsHeader::guid_prefix); crates/rtps/src/datagram.rs (ParsedDatagram::receiver_walk)

Tests: crates/rtps/src/header.rs::tests::header_guid_prefix_at_bytes_8_to_19, crates/rtps/src/datagram.rs::tests::receiver_walk_without_info_source_attributes_to_header_prefix

Status: done

§8.3.3.1 Header structure fixed in version 2

Spec: §8.3.3.1, p. 38 — “The structure of the RTPS Header cannot be changed in this major version (2) of the protocol.”

Repo: crates/rtps/src/header.rs (RtpsHeader::WIRE_SIZE = 20)

Tests: crates/rtps/src/header.rs::tests::header_total_size_is_20_bytes, crates/rtps/src/header.rs::tests::header_roundtrip

Status: done

§8.3.3.2 HeaderExtension immediately after the header

Spec: §8.3.3.2, p. 38 — “The HeaderExtension may optionally appear immediately following the Header.”

Repo: crates/rtps/src/datagram.rs (decode_datagram: HE only as the first submessage)

Tests: crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension, crates/rtps/src/datagram.rs::tests::decode_rejects_header_extension_after_data_submessage

Status: done

§8.3.3.2 HeaderExtension skippable for versions up to 2.4

Spec: §8.3.3.2, p. 39 — “versions of the protocol that do not understand the HeaderExtension will treat it as ‘unknown messge kind’, skip it, and continue processing the submessages that follow it”.

Repo: crates/rtps/src/datagram.rs (decode_datagram)

Tests: crates/rtps/src/datagram.rs::tests::rtps_2_1_treats_0x80_as_vendor_specific_not_header_extension

Status: n/a (informative) — describes the behaviour of older implementations; for ZeroDDS itself §8.3.4.1 applies.

§8.3.3.2 Table 8.15 HE EndiannessFlag

Spec: §8.3.3.2, p. 39, Table 8.15 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_E, HeaderExtension::little_endian)

Tests: crates/rtps/src/header_extension.rs::tests::empty_he_be_roundtrip, crates/rtps/src/header_extension.rs::tests::wire_layout_be_message_length_correct, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.3.2 Table 8.15 HE LengthFlag

Spec: §8.3.3.2, p. 39, Table 8.15 — “LengthFlag … Indicates the messageLength field is present.”

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_L)

Tests: crates/rtps/src/header_extension.rs::tests::flag_byte_with_message_length, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.3.2 Table 8.15 HE TimestampFlag

Spec: §8.3.3.2, p. 39, Table 8.15 — “TimestampFlag … Indicates the rtpsSendTimestamp field is present.”

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_T, bit 2)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_timestamp_le, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.3.2 Table 8.15 HE UExtensionFlag

Spec: §8.3.3.2, p. 39, Table 8.15 — “UExtensionFlag … Indicates the uExtension4 field is present.”

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_U)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_uextension4_be, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.3.2 Table 8.15 HE WExtensionFlag

Spec: §8.3.3.2, p. 39, Table 8.15 — “WExtensionFlag … Indicates the wExtension8 field is present.”

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_W, bit 4)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_wextension8_le, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.3.2 Table 8.15 HE ChecksumFlags

Spec: §8.3.3.2, p. 39, Table 8.15 — “ChecksumFlags (2 flags) … Indicates the presence and format of the messageChecksum field.”

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_C0, HE_FLAG_C1, ChecksumKind::from_flags, ChecksumKind::to_flag_bits)

Tests: crates/rtps/src/header_extension.rs::tests::checksum_kind_roundtrip, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.3.2 Table 8.15 HE ParametersFlag

Spec: §8.3.3.2, p. 39, Table 8.15 — “ParametersFlag … Indicates the parameters field is present.”

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_P)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_parameter_list, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.3.2 Table 8.15 HE messageLength

Spec: §8.3.3.2, pp. 39–40 — “The messageLength indicates the length of the complete RTPS Message, starting from the beginning of the RTPS Header.”

Repo: crates/rtps/src/datagram.rs (decode_datagram, HeaderExtension); crates/rtps/src/header_extension.rs (validate_message_length, restate_for_rebuilt_message); crates/dcps/src/runtime.rs (unprotect_volatile_datagram, unprotect_user_datagram)

Tests: crates/rtps/src/datagram.rs::tests::a_header_extension_message_length_too_small_for_header_and_extension_is_invalid, crates/rtps/src/datagram.rs::tests::a_header_extension_message_length_counts_from_the_start_of_the_rtps_header, crates/rtps/src/datagram.rs::tests::a_rebuilt_message_takes_the_header_extension_with_its_own_length

Status: done — the decoder refuses a messageLength below header and HeaderExtension and one that differs from the length of the message received, counted from the RTPS header. A message the receiver rebuilds after it opened protected submessages is checked as received, then gets the HeaderExtension with its own length and without the checksum (restate_for_rebuilt_message); kept as it was, every opened message of CoreDX 6.14.1, which sends a messageLength, was refused, its crypto tokens among them (OMG dds-security, Linux test host).

§8.3.3.2 Table 8.15 HE rtpsSendTimestamp

Spec: §8.3.3.2, p. 40 — “The rtpsSendTimestamp indicates the time when the RTPS message was sent by the originating Participant. … shall collected as close as possible to the moment when the RTPS Message is sent … The time origin … shall be the same as the one used in the Timestamp Submessage Element”.

Repo: crates/rtps/src/header_extension.rs, crates/rtps/src/receiver_state.rs (apply_header_extension)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_header_extension_updates_fields, crates/rtps/src/datagram.rs::tests::a_header_extension_timestamp_is_no_source_timestamp, crates/rtps/src/datagram.rs::tests::the_walk_with_a_reception_clock_detects_a_skew_and_corrects_the_timestamp

Status: done — field encoded and read; on reception it sets Receiver.rtpsSendTimestamp (§8.3.7.4), not the source timestamp. ZeroDDS sends no HeaderExtension (it is optional, §8.3.3.2); the rule for the time of collection holds for a sender that writes one.

§8.3.3.2 Table 8.15 HE uExtension4

Spec: §8.3.3.2, p. 40 — “The uExtension4 is undefined in this version of the protocol.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::uextension4)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_uextension4_be, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.3.2 Table 8.15 HE wExtension8

Spec: §8.3.3.2, p. 40 — “The wExtension8 is undefined in this version of the protocol.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::wextension8)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_wextension8_le, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.3.2 Table 8.15 HE messageChecksum

Spec: §8.3.3.2, p. 40 — “The messageChecksum provides a checksum computed over the complete of the RTPS Message, which includes the RTPS Header, the HeaderExtension, and all Submessages that may follow.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::message_checksum, seal_message, verify_message, encode_body, decode_body); crates/rtps/src/datagram.rs (decode_submessage)

Tests: crates/rtps/src/header_extension.rs::tests::a_sealed_message_verifies_and_a_changed_one_does_not, crates/rtps/src/header_extension.rs::tests::the_checksum_is_big_endian_in_a_little_endian_header_extension, crates/rtps/src/datagram.rs::tests::a_message_with_a_wrong_checksum_is_refused_and_counted

Status: done — the checksum of the whole message with the field zeroed is computed (seal_message) and checked on receipt; a mismatch refuses the message and is counted (refused_messages). The runtime has no send path that writes a HeaderExtension with a checksum.

§8.3.3.2 Table 8.15 HE parameters

Spec: §8.3.3.2, p. 40 — “The parameters provide an extensibility mechanism. It enables revisions of the protocol to add information to the HeaderExtension without breaking interoperability”.

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::parameters)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_parameter_list, crates/rtps/src/header_extension.rs::tests::decode_rejects_malformed_parameter_list_when_p_flag_set, crates/rtps/src/header_extension.rs::tests::decode_takes_a_parameter_list_without_sentinel

Status: done

§8.3.3.3 Table 8.16 SubmessageHeader.submessageId

Spec: §8.3.3.3, p. 41, Table 8.16 — “submessageId: SubmessageKind — Identifies the kind of Submessage.”

Repo: crates/rtps/src/submessage_header.rs (SubmessageHeader::submessage_id)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_header_layout_le, crates/rtps/src/submessage_header.rs::tests::submessage_id_roundtrip_for_known_ids

Status: done

§8.3.3.3 Table 8.16 SubmessageHeader.flags (bit 0 = endianness)

Spec: §8.3.3.3, pp. 41–42 — “The first flag, the EndiannessFlag, is present and located in the same position in all Submessages … If the EndiannessFlag is set to FALSE, the Submessage is encoded in big-endian format, EndiannessFlag set to TRUE means little-endian.”

Repo: crates/rtps/src/submessage_header.rs (FLAG_E_LITTLE_ENDIAN, SubmessageHeader::is_little_endian); crates/rtps/src/datagram.rs (SubmessageFrame::little_endian)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_header_roundtrip_be, crates/rtps/src/submessage_header.rs::tests::submessage_header_roundtrip_le

Status: done

§8.3.3.3 Table 8.16 SubmessageHeader.submessageLength

Spec: §8.3.3.3, p. 42 — “In case submessageLength > 0, it is either: The length from the start of the contents of the Submessage until the start of the header of the next Submessage … Or else it is the remaining Message length”.

Repo: crates/rtps/src/datagram.rs (decode_datagram: body_end = body_start + octets)

Tests: crates/rtps/src/datagram.rs::tests::encode_decode_two_data_submessages, crates/rtps/src/datagram.rs::tests::pad_submessage_is_skipped_and_the_data_behind_it_still_decodes

Status: done

§8.3.3.3 submessageLength == 0: last submessage

Spec: §8.3.3.3, p. 42 — “In case submessageLength==0, the Submessage is the last Submessage in the Message and extends up to the end of the Message.”

Repo: crates/rtps/src/datagram.rs (decode_datagram, SubmessageFrame::octets_elided, encode_datagram)

Tests: crates/rtps/src/datagram.rs::tests::decode_handles_last_submessage_zero_length, crates/rtps/src/datagram.rs::tests::an_info_ts_without_a_body_is_not_the_last_submessage, crates/rtps/tests/vendor_frames.rs::opendds_datagrams_re_encode_byte_for_byte

Status: done — the exception for PAD and INFO_TS is in §9.4.5.1.3.

§8.3.3.3 Submessage structure fixed in version 2

Spec: §8.3.3.3, p. 41 — “The structure of the RTPS Submessage cannot be changed in this major version (2) of the protocol.”

Repo: crates/rtps/src/submessage_header.rs (SubmessageHeader::WIRE_SIZE = 4)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_header_layout_be

Status: done

§8.3.4 Receiver state reset for every message

Spec: §8.3.4, p. 42 — “This state is modeled as the state of an RTPS Receiver that is reset each time a new message is processed and provides context for the interpretation of each Submessage.”

Repo: crates/rtps/src/datagram.rs (ParsedDatagram::receiver_walk creates a new ReceiverState per datagram)

Tests: crates/rtps/src/datagram.rs::tests::receiver_walk_attributes_submessages_after_info_source_to_the_new_prefix

Status: done

§8.3.4 Table 8.17 initial sourceVersion

Spec: §8.3.4, p. 43, Table 8.17 — “sourceVersion: PROTOCOLVERSION”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::new, source_version)

Tests: crates/rtps/src/receiver_state.rs::tests::the_initial_source_values_and_parameters_are_those_of_table_8_17

Status: done — initial value PROTOCOLVERSION (2.5).

§8.3.4 Table 8.17 initial sourceVendorId

Spec: §8.3.4, p. 43, Table 8.17 — “sourceVendorId: VENDORID_UNKNOWN”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::new, source_vendor_id)

Tests: crates/rtps/src/receiver_state.rs::tests::the_initial_source_values_and_parameters_are_those_of_table_8_17

Status: done — initial value VENDORID_UNKNOWN.

§8.3.4 Table 8.17 initial sourceGuidPrefix

Spec: §8.3.4, p. 43, Table 8.17 — “sourceGuidPrefix: GUIDPREFIX_UNKNOWN”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::new, source_guid_prefix)

Tests: crates/rtps/src/receiver_state.rs::tests::the_initial_source_values_and_parameters_are_those_of_table_8_17

Status: done — initial value GUIDPREFIX_UNKNOWN.

§8.3.4 Table 8.17 initial destGuidPrefix

Spec: §8.3.4, p. 43, Table 8.17 — “destGuidPrefix: GUID prefix of the participant receiving the message”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::new); crates/rtps/src/datagram.rs (ParsedDatagram::receiver_walk)

Tests: crates/rtps/src/receiver_state.rs::tests::new_state_has_default_fields, crates/rtps/src/datagram.rs::tests::receiver_walk_without_info_source_attributes_to_header_prefix

Status: done

§8.3.4 Table 8.17 initial unicastReplyLocatorList

Spec: §8.3.4, p. 43, Table 8.17 — “The list is initialized to contain a single Locator_t with the LocatorKind, Address, and Port fields specified below: The LocatorKind is set to the kind that identifies the transport that received the message … The Address is set to the Address of the source of the message … The port is set to LOCATOR_PORT_INVALID.”

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::set_initial_reply_locators); crates/rtps/src/datagram.rs (ReceiveContext, ParsedDatagram::receiver_walk_in); crates/dcps/src/runtime.rs (receive_context, receiver_walk_of, reply_targets_of); crates/discovery/src/spdp.rs (samples_in), crates/discovery/src/sedp/stack.rs (handle_datagram_in); crates/dcps/src/wlp.rs, crates/dcps/src/type_lookup_transport.rs

Tests: crates/rtps/src/receiver_state.rs::tests::the_initial_state_is_the_one_of_table_8_17, crates/rtps/src/datagram.rs::tests::receiver_walk_from_starts_the_reply_lists_at_the_transport_values, crates/rtps/src/datagram.rs::tests::receiver_walk_in_applies_the_source_and_the_clock_of_the_context, crates/dcps/src/runtime.rs::tests::a_reader_proxy_without_locators_takes_the_info_reply_of_its_acknack

Status: done — initial value per Table 8.17 (transport kind, source address, LOCATOR_PORT_INVALID). Every receive path goes through receiver_walk_in with the datagram’s source and the reception clock: user data, SPDP, SEDP, WLP, TypeLookup and the security builtins. The reply side uses the list: a reader proxy with no locator of its own takes the entries of the unicast list that carry a port (which an InfoReply supplies; the initial values have LOCATOR_PORT_INVALID) and keeps them for later answers.

§8.3.4 Table 8.17 initial multicastReplyLocatorList

Spec: §8.3.4, p. 43, Table 8.17 — “The list is initialized to contain a single Locator_t … The LocatorKind is set to the kind that identifies the transport that received the message … The address is set to LOCATOR_ADDRESS_INVALID. The port is set to LOCATOR_PORT_INVALID.”

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::set_initial_reply_locators); crates/rtps/src/datagram.rs (ReceiveContext, ParsedDatagram::receiver_walk_in); crates/dcps/src/runtime.rs (receive_context, receiver_walk_of, reply_targets_of); crates/discovery/src/spdp.rs (samples_in), crates/discovery/src/sedp/stack.rs (handle_datagram_in); crates/dcps/src/wlp.rs, crates/dcps/src/type_lookup_transport.rs

Tests: crates/rtps/src/receiver_state.rs::tests::the_initial_state_is_the_one_of_table_8_17, crates/rtps/src/datagram.rs::tests::receiver_walk_from_starts_the_reply_lists_at_the_transport_values, crates/rtps/src/datagram.rs::tests::receiver_walk_in_applies_the_source_and_the_clock_of_the_context, crates/dcps/src/runtime.rs::tests::a_reader_proxy_without_locators_takes_the_info_reply_of_its_acknack

Status: done — initial value per Table 8.17 (transport kind, LOCATOR_ADDRESS_INVALID, LOCATOR_PORT_INVALID). Every receive path goes through receiver_walk_in with the datagram’s source and the reception clock: user data, SPDP, SEDP, WLP, TypeLookup and the security builtins. The reply side uses the list: a reader proxy with no locator of its own takes the entries of the unicast list that carry a port (which an InfoReply supplies; the initial values have LOCATOR_PORT_INVALID) and keeps them for later answers.

§8.3.4 Table 8.17 initial haveTimestamp

Spec: §8.3.4, p. 43, Table 8.17 — “haveTimestamp: FALSE”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::new)

Tests: crates/rtps/src/receiver_state.rs::tests::new_state_has_default_fields

Status: done

§8.3.4 Table 8.17 initial timestamp

Spec: §8.3.4, p. 43, Table 8.17 — “timestamp: TIME_INVALID”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::new); crates/rtps/src/header_extension.rs (HeTimestamp::TIME_INVALID)

Tests: crates/rtps/src/receiver_state.rs::tests::the_initial_state_is_the_one_of_table_8_17

Status: done — {0xffffffff, 0xffffffff}; also after InfoSource and an InfoTimestamp with the I flag.

§8.3.4 Table 8.17 initial messageLength

Spec: §8.3.4, p. 43, Table 8.17 — “messageLength: MESSAGE_LENGTH_INVALID”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::new: message_length: None)

Tests: crates/rtps/src/receiver_state.rs::tests::new_state_has_default_fields

Status: done

§8.3.4 Table 8.17 initial messageChecksum

Spec: §8.3.4, p. 43, Table 8.17 — “messageChecksum: CHECKSUM_INVALID”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::new: ChecksumValue::None)

Tests: crates/rtps/src/receiver_state.rs::tests::new_state_has_default_fields

Status: done

§8.3.4 Table 8.17 initial rtpsSendTimestamp

Spec: §8.3.4, p. 43, Table 8.17 — “rtpsSendTimestamp: TIME_INVALID”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::rtps_send_timestamp)

Tests: crates/rtps/src/receiver_state.rs::tests::new_state_has_default_fields, crates/rtps/src/receiver_state.rs::tests::apply_header_extension_updates_fields

Status: done

§8.3.4 Table 8.17 initial rtpsReceptionTimestamp

Spec: §8.3.4, p. 43, Table 8.17 — “rtpsReceptionTimestamp: TIME_INVALID”.

Repo: crates/rtps/src/receiver_state.rs (rtps_reception_timestamp)

Tests: crates/rtps/src/receiver_state.rs::tests::the_initial_state_is_the_one_of_table_8_17

Status: done — the field starts as TIME_INVALID (None).

§8.3.4 Table 8.17 initial clockSkewDetected

Spec: §8.3.4, p. 43, Table 8.17 — “clockSkewDetected: FALSE”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::new)

Tests: crates/rtps/src/receiver_state.rs::tests::new_state_has_default_fields

Status: done

§8.3.4 Table 8.17 initial parameters

Spec: §8.3.4, p. 43, Table 8.17 — “parameters: The list is initialized as an empty list.”

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::new, parameters)

Tests: crates/rtps/src/receiver_state.rs::tests::the_initial_source_values_and_parameters_are_those_of_table_8_17

Status: done — initial value an empty list.

§8.3.4.1 Rule 1: unreadable submessage header

Spec: §8.3.4.1, p. 43 — “If the full Submessage header cannot be read, the rest of the Message is considered invalid.”

Repo: crates/rtps/src/datagram.rs (decode_datagram: UnexpectedEof)

Tests: crates/rtps/src/datagram.rs::tests::a_truncated_submessage_header_invalidates_the_rest

Status: done — the rest of the message is discarded, the error is in ParsedDatagram::invalid_rest; the submessages before it stay.

§8.3.4.1 Rule 2: invalid submessageLength

Spec: §8.3.4.1, p. 43 — “The submessageLength field defines where the next Submessage starts … If this field is invalid, the rest of the Message is invalid.”

Repo: crates/rtps/src/datagram.rs (decode_datagram: body_end > bytes.len() gives UnexpectedEof)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest, crates/rtps/tests/fuzz_smoke.rs::fuzz_decode_datagram_does_not_panic

Status: done — as rule 1: the rest is discarded, the submessages before it stay.

§8.3.4.1 Rule 3: ignore an unknown SubmessageId

Spec: §8.3.4.1, p. 43 — “A Submessage with an unknown SubmessageId must be ignored and parsing must continue with the next Submessage. … SubmessageIds in the vendor-specific range coming from a vendorId that is unknown must also be ignored”.

Repo: crates/rtps/src/datagram.rs (decode_datagram, ParsedSubmessage::Unknown)

Tests: crates/rtps/src/datagram.rs::tests::decode_skips_unknown_submessage_without_must_understand, crates/rtps/src/datagram.rs::tests::decode_marks_unknown_submessage_id_without_failing, crates/rtps/src/datagram.rs::tests::decode_skips_an_unknown_submessage_whatever_its_flags

Status: done

§8.3.4.1 Rule 3: no must-understand at the submessage level

Spec: §8.3.4.1, pp. 43–44 — rules 3 and 4: unknown submessages and unknown flags are ignored; RTPS 2.5 knows must-understand only per ParameterId (Table 9.6, p. 165).

Repo: crates/rtps/src/datagram.rs (decode_datagram, ParsedSubmessage::Unknown)

Tests: crates/rtps/src/datagram.rs::tests::decode_skips_an_unknown_submessage_whatever_its_flags

Status: done — an unknown submessage is skipped whatever its flags.

§8.3.4.1 Rule 4: ignore unknown flags

Spec: §8.3.4.1, p. 44 — “The receiver of a Submessage should ignore unknown flags. An implementation of RTPS 2.5 should skip all flags that are marked as ‘X’ (unused) in the protocol.”

Repo: crates/rtps/src/datagram.rs (decode_datagram)

Tests: crates/rtps/src/datagram.rs::tests::unknown_flags_of_a_known_submessage_are_ignored, crates/rtps/src/datagram.rs::tests::decode_skips_an_unknown_submessage_whatever_its_flags

Status: done — for known submessages the top three flag bits, which no submessage defines, change nothing in what is read; an unknown submessage is skipped whatever flags it carries.

§8.3.4.1 Rule 5: submessageLength also for known ids

Spec: §8.3.4.1, p. 44 — “A valid submessageLength field must always be used to find the next Submessage, even for Submessages with known IDs.”

Repo: crates/rtps/src/datagram.rs (decode_datagram: pos = body_end for every submessage)

Tests: crates/rtps/src/datagram.rs::tests::pad_submessage_is_skipped_and_the_data_behind_it_still_decodes, crates/rtps/tests/vendor_frames.rs::rti_datagrams_re_encode_byte_for_byte

Status: done

§8.3.4.1 Rule 6: a known but invalid submessage

Spec: §8.3.4.1, p. 44 — “A known but invalid Submessage invalidates the rest of the Message.”

Repo: crates/rtps/src/datagram.rs (decode_datagram, ParsedDatagram::invalid_rest)

Tests: crates/rtps/src/datagram.rs::tests::the_submessages_before_an_invalid_one_stand, crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/submessages.rs::validity_tests::data_with_writer_sn_not_positive_or_with_d_and_k_is_invalid

Status: done — a submessage its decoder cannot read, or whose “Validity” condition (§8.3.8) is violated, invalidates the rest of the message; the submessages before it stand (invalid_rest, counted). The one condition that contradicts the definition of currentGSN is under §8.3.8.6 “Heartbeat invalid: group fields”.

§8.3.4.1 Valid submessages before an invalid one

Spec: §8.3.4.1, pp. 43–44 — rules 1, 2 and 6 declare only “the rest of the Message” invalid.

Repo: crates/rtps/src/datagram.rs (decode_datagram, ParsedDatagram::invalid_rest)

Tests: crates/rtps/src/datagram.rs::tests::the_submessages_before_an_invalid_one_stand, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — decode_datagram returns the submessages read as valid before an invalid one and notes the error in invalid_rest; the receive paths process them.

§8.3.4.1 Rule 6 for submessages invalid in content

Spec: §8.3.4.1, p. 44 — “A known but invalid Submessage invalidates the rest of the Message.” The validity conditions per submessage are in §8.3.8 under “Validity”.

Repo: crates/rtps/src/submessages.rs (decoder per submessage); crates/rtps/src/datagram.rs (ParsedDatagram::invalid_rest)

Tests: crates/rtps/src/submessages.rs::validity_tests::data_with_writer_sn_not_positive_or_with_d_and_k_is_invalid, crates/rtps/src/submessages.rs::validity_tests::data_frag_validity_rules, crates/rtps/src/submessages.rs::validity_tests::heartbeat_validity_rules, crates/rtps/src/submessages.rs::validity_tests::gap_and_sequence_number_set_validity_rules, crates/rtps/src/submessages.rs::validity_tests::fragment_submessages_validity_rules, crates/rtps/src/datagram.rs::tests::the_submessages_before_an_invalid_one_stand, crates/dcps/src/runtime.rs::tests::the_empty_acknack_setting_is_off_by_default

Status: done — the decoders of the submessages check the conditions of the “Validity” sections of §8.3.8; a violation is a decoder error and makes the rest of the message invalid, the submessages before it stand. Counted, not dropped silently: zerodds_rtps::datagram::invalid_message_rests(), refused_messages() and skipped_must_understand_submessages() (process-wide), on the runtime as DcpsRuntime::invalid_message_rests, refused_messages, skipped_must_understand_submessages.

§8.3.4.1 Submessages that change the receiver state

Spec: §8.3.4.1, p. 44 — “In this version of the protocol, only the Header and the Submessages HeaderExtension, InfoSource, InfoReply, InfoDestination, and InfoTimestamp change the state of the Receiver.”

Repo: crates/rtps/src/datagram.rs (ReceiverWalk::next)

Tests: crates/rtps/src/datagram.rs::tests::receiver_walk_yields_every_submessage_including_info_ones, crates/rtps/src/datagram.rs::tests::receiver_walk_info_reply_ip4_sets_reply_locators

Status: done — InfoReplyIp4 (PSM §9.4.5.15) also changes the state as InfoReply does.

§8.3.5 SubmessageElements

Spec: §8.3.5, p. 44 — “Each RTPS Submessage in turn is built from a set of predefined atomic building blocks called SubmessageElements.”

Repo: —

Tests: —

Status: n/a (informative) — introduction; the elements are listed one by one under §8.3.5.1–§8.3.5.19.

§8.3.5.1 Table 8.18 GuidPrefix element

Spec: §8.3.5.1, p. 44, Table 8.18 — “value: GuidPrefix_t — Identifies the GuidPrefix_t part of the GUID_t of the Entity that is the source or target of the message.”

Repo: crates/rtps/src/submessages.rs (InfoSourceSubmessage::guid_prefix); crates/rtps/src/datagram.rs (ParsedSubmessage::InfoDestination)

Tests: crates/rtps/src/datagram.rs::tests::decode_info_source_via_datagram, crates/rtps/src/datagram.rs::tests::info_dst_body_of_exactly_twelve_decodes

Status: done

§8.3.5.1 Table 8.19 EntityId element

Spec: §8.3.5.1, p. 45, Table 8.19 — “value: EntityId_t — Identifies the EntityId_t part of the GUID_t of the Entity that is the source or target of the message.”

Repo: crates/rtps/src/submessages.rs (fields reader_id, writer_id of every entity submessage)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_roundtrip_le, crates/rtps/src/wire_types.rs::tests::entity_id_roundtrip

Status: done

§8.3.5.2 Table 8.20 VendorId element

Spec: §8.3.5.2, p. 45, Table 8.20 — “value: VendorId_t — Identifies the vendor of the middleware that implements the protocol.”

Repo: crates/rtps/src/submessages.rs (InfoSourceSubmessage::vendor_id); crates/rtps/src/header.rs (RtpsHeader::vendor_id)

Tests: crates/rtps/src/datagram.rs::tests::decode_info_source_via_datagram

Status: done

§8.3.5.2 VendorId assigned by the OMG

Spec: §8.3.5.2, p. 45 — “The following values are reserved by the protocol: VENDORID_UNKNOWN. Other values must be assigned by the OMG.”

Repo: —

Tests: —

Status: blocked — assignment of a VendorId by the OMG (applied for); lifted once the OMG assigns the value and VendorId::ZERODDS carries it. Until then ZeroDDS sends 0x01F0 (crates/rtps/src/wire_types.rs, by its comment an interim value), a value the OMG list does not hold (assigned up to {0x01,0x1C}, {0x01,0x1D} and {0x01,0x1E} reserved).

§8.3.5.3 Table 8.21 ProtocolVersion element

Spec: §8.3.5.3, p. 45, Table 8.21 — “value: ProtocolVersion_t — Identifies the major and minor version of the RTPS protocol.” Special values PROTOCOLVERSION_1_0 … PROTOCOLVERSION_2_4.

Repo: crates/rtps/src/wire_types.rs (ProtocolVersion); crates/rtps/src/submessages.rs (InfoSourceSubmessage::protocol_version)

Tests: crates/rtps/src/wire_types.rs::tests::protocol_version_all_aliases_roundtrip, crates/rtps/src/datagram.rs::tests::decode_info_source_via_datagram

Status: done

§8.3.5.4 Table 8.22 SequenceNumber: 64 bits signed

Spec: §8.3.5.4, p. 45 — “A sequence number is a 64-bit signed integer, that can take values in the range: -2^63 <= N <= 2^63-1.”

Repo: crates/rtps/src/wire_types.rs (SequenceNumber(i64), SequenceNumber::split, SequenceNumber::from_high_low)

Tests: crates/rtps/src/wire_types.rs::tests::sequence_number_split_high_low, crates/rtps/src/wire_types.rs::tests::sequence_number_roundtrip_be

Status: done

§8.3.5.4 Sequence numbers begin at 1

Spec: §8.3.5.4, p. 45 — “Sequence numbers begin at 1.”

Repo: crates/rtps/src/writer.rs (BestEffortWriter); crates/rtps/src/reliable_writer.rs (ReliableWriter::write)

Tests: crates/rtps/src/writer.rs::tests::writer_starts_at_sequence_number_one, crates/rtps/src/reliable_stateless_writer.rs::tests::new_change_assigns_monotonic_sn

Status: done

§8.3.5.4 SEQUENCENUMBER_UNKNOWN

Spec: §8.3.5.4, p. 46 — “The protocol reserves the following value: SEQUENCENUMBER_UNKNOWN”.

Repo: crates/rtps/src/wire_types.rs (SequenceNumber::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::sequence_number_unknown_high_minus_one_low_zero

Status: done

§8.3.5.5 Table 8.23 SequenceNumberSet base/set

Spec: §8.3.5.5, p. 46, Table 8.23 — “base: SequenceNumber_t — Identifies the first sequence number in the set. set: SequenceNumber_t[*] — A set of sequence numbers, each verifying that: base <= element(set) <= base+255”.

Repo: crates/rtps/src/submessages.rs (SequenceNumberSet, from_missing, iter_set)

Tests: crates/rtps/tests/proptest_roundtrip.rs::seqnum_set_iter_matches_missing, crates/rtps/tests/proptest_roundtrip.rs::seqnum_set_roundtrip_le

Status: done

§8.3.5.5 Validity of a SequenceNumberSet

Spec: §8.3.5.5, p. 46 — “a valid SequenceNumberSet must verify that: maximum(SequenceNumberSet) - minimum(SequenceNumberSet) < 256, minimum(SequenceNumberSet) >= 1”.

Repo: crates/rtps/src/submessages.rs (SequenceNumberSet::read_from: numBits <= 256, bitmapBase >= 1; from_missing caps the window at 256)

Tests: crates/rtps/tests/fuzz_smoke.rs::fuzz_sequence_number_set_read_from_does_not_panic, crates/rtps/tests/proptest_roundtrip.rs::seqnum_set_wire_size_matches_encoded, crates/rtps/src/submessages.rs::validity_tests::gap_and_sequence_number_set_validity_rules, crates/rtps/tests/vendor_frames.rs::the_empty_acknack_of_opendds_and_rti_is_invalid_by_default, crates/rtps/tests/vendor_frames.rs::opendds_session_re_encodes_byte_for_byte, crates/rtps/tests/vendor_frames.rs::rti_session_re_encodes_byte_for_byte, crates/rtps/src/submessages.rs::validity_tests::the_empty_set_with_base_zero_is_accepted_only_on_request

Status: done — the span is limited to 256, the decoder checks minimum >= 1. Vendor form: OpenDDS 3.34.0 and RTI Connext 7.7.0 send readerSNState 0/0: (bitmapBase 0, numBits 0) as the ACKNACK of a reader without samples (measured in tools/wire-capture/rtps-sessions: 40 and 8 ACKNACKs). Default: invalid. The setting wire.accept_empty_acknack_base_zero (env ZERODDS_WIRE_ACCEPT_EMPTY_ACKNACK_BASE_ZERO, default false) accepts exactly this empty set in an ACKNACK, for the process.

§8.3.5.6 Table 8.24 FragmentNumber

Spec: §8.3.5.6, p. 46 — “A fragment number is a 32-bit unsigned integer … Fragment numbers start at 1.”

Repo: crates/rtps/src/wire_types.rs (FragmentNumber(u32)); crates/rtps/src/reliable_writer.rs (fragmentation from number 1)

Tests: crates/rtps/src/wire_types.rs::tests::fragment_number_roundtrip_le_be, crates/rtps/src/reliable_writer.rs::tests::write_above_fragment_size_packs_the_fragments_a_message_carries

Status: done

§8.3.5.7 Table 8.25 FragmentNumberSet

Spec: §8.3.5.7, p. 46, Table 8.25 — “base: FragmentNumber_t … set: FragmentNumber_t[*] — A set of fragment numbers, each verifying that: base <= element(set) <= base+255”. Valid only with “maximum - minimum < 256, minimum >= 1”.

Repo: crates/rtps/src/submessages.rs (FragmentNumberSet, from_missing, read_from)

Tests: crates/rtps/tests/proptest_roundtrip.rs::frag_set_roundtrip_le, crates/rtps/tests/fuzz_smoke.rs::fuzz_fragment_number_set_read_from_does_not_panic, crates/rtps/src/submessages.rs::validity_tests::fragment_submessages_validity_rules

Status: done — span limited to 256, bitmapBase >= 1 is checked.

§8.3.5.8 Table 8.26 Timestamp

Spec: §8.3.5.8, p. 47 — “Timestamp is used to represent time. The representation should be capable of having a resolution of nano-seconds or better.” Special values TIME_ZERO, TIME_INVALID, TIME_INFINITE.

Repo: crates/rtps/src/header_extension.rs (HeTimestamp); crates/rtps/src/submessages.rs (InfoTimestampSubmessage); crates/dcps/src/time.rs

Tests: crates/rtps/src/submessages.rs::tests::info_timestamp_roundtrip_le, crates/rtps/src/submessages.rs::validity_tests::time_t_seconds_are_unsigned, crates/rtps/tests/reliable_e2e.rs::e2e_source_timestamp_round_trips

Status: done — resolution 2⁻³² s, unsigned seconds, TIME_INVALID and TIME_INFINITE as constants.

§8.3.5.9 Table 8.27/8.28 ParameterList and Parameter

Spec: §8.3.5.9, p. 47, Tables 8.27 and 8.28 — “parameter: Parameter[*]”; per parameter “parameterId: ParameterId_t”, “length: short”, “value: octet[length]”.

Repo: crates/rtps/src/parameter_list.rs (ParameterList, Parameter, to_bytes, from_bytes_with_consumed)

Tests: crates/rtps/src/parameter_list.rs::tests::single_parameter_encodes_id_length_value, crates/rtps/src/parameter_list.rs::tests::roundtrip_multiple_parameters, crates/rtps/src/parameter_list.rs::tests::roundtrip_be_endianness

Status: done

§8.3.5.9 At most 2^16 ParameterIds

Spec: §8.3.5.9, p. 47 — “There shall be no more than 2^16 possible values of the ParameterId_t parameterId.”

Repo: crates/rtps/src/parameter_list.rs (Parameter::id: u16)

Tests: crates/rtps/src/parameter_list.rs::tests::single_parameter_encodes_id_length_value

Status: done

§8.3.5.9 2^15 values for protocol-defined parameters

Spec: §8.3.5.9, p. 47 — “A range of 2^15 values is reserved for protocol-defined parameters. All the parameter_id values defined by the 2.5 version of the protocol and all future revisions of the same major version must use values in this range.”

Repo: crates/rtps/src/parameter_list.rs (pid, is_standard_pid)

Tests: crates/rtps/src/parameter_list.rs::tests::is_standard_pid_recognises_dds_security_pids, crates/rtps/src/parameter_list.rs::tests::is_standard_pid_unknown_pid_returns_false

Status: done

§8.3.5.9 2^15 values for vendor-defined parameters

Spec: §8.3.5.9, p. 47 — “A range of 2^15 values is reserved for vendor-defined parameters.”

Repo: crates/rtps/src/parameter_list.rs (VENDOR_SPECIFIC_BIT, pid::SHM_LOCATOR, pid::ZERODDS_TYPE_ID)

Tests: crates/rtps/src/publication_data.rs::tests::a_foreign_vendors_0x8002_is_not_read_as_a_type_identifier, crates/rtps/src/publication_data.rs::tests::a_zerodds_0x8002_is_read_and_the_announcement_states_the_vendor

Status: done

§8.3.5.9 Parameter length at most 2^16 octets

Spec: §8.3.5.9, p. 47 — “The maximum length of any parameter is limited to 2^16 octets.”

Repo: crates/rtps/src/parameter_list.rs (length as u16)

Tests: crates/rtps/tests/user_data_propagation.rs::user_data_large_payload_32kib

Status: done

§8.3.5.10 Table 8.29 Count

Spec: §8.3.5.10, pp. 47–48 — “Count is used by several Submessages and enables a receiver to detect duplicates of the same Submessage.”

Repo: crates/rtps/src/submessages.rs (count fields)

Tests: crates/rtps/src/reliable_writer.rs::tests::heartbeat_count_increments

Status: done — the element exists; its use by the receiver is listed under §8.3.8.1 and §8.3.8.6.

§8.3.5.11 Table 8.30 ChangeCount

Spec: §8.3.5.11, p. 48 — “ChangeCount is used in the Gap Submessage and enables the sender to indicate the number of changes within the Gap that belong to a certain category.”

Repo: crates/rtps/src/submessages.rs (GapSubmessage::filtered_count)

Tests: crates/rtps/src/submessages.rs::tests::gap_filtered_count_is_eight_octets_high_then_low, crates/rtps/src/submessages.rs::tests::gap_with_filtered_count_roundtrip_le

Status: done — in the GAP submessage 64 bits (eight octets, high and low).

§8.3.5.12 Table 8.31 Checksum

Spec: §8.3.5.12, p. 48, Table 8.31 — “value: Checksum32_t, or Checksum64_t, or Checksum128_t — A checksum of the RTPS Message, including the RTPS Header.”

Repo: crates/rtps/src/header_extension.rs (ChecksumValue, ChecksumKind)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_crc32c_le, crates/rtps/src/header_extension.rs::tests::roundtrip_with_crc64_be, crates/rtps/src/header_extension.rs::tests::roundtrip_with_md5_le, crates/rtps/src/header_extension.rs::tests::the_checksum_is_big_endian_in_a_little_endian_header_extension

Status: done — the three formats, the CRCs in big endian.

§8.3.5.12 Checksum defined per transport PSM

Spec: §8.3.5.12, p. 48 — “the Checksum may be omitted from the HeaderExtension. The specific behavior shall be defined for each Transport PSM.”

Repo: —

Tests: —

Status: n/a (informative) — a task for the PSMs; the UDP/IP PSM defines the checksum in §9.4.2.15.

§8.3.5.13 Table 8.32 MessageLength

Spec: §8.3.5.13, p. 48 — “MessageLength is used in the HeaderExtension Submessage and enables the sender to indicate the length of the RTPS message.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::message_length)

Tests: crates/rtps/src/header_extension.rs::tests::wire_layout_le_message_length_correct, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.5.14 Table 8.33 UExtension4

Spec: §8.3.5.14, pp. 48–49 — “UExtension4 is used in the HeaderExtension Submessage and enables the sender to add 4 octets of information to the header.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::uextension4)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_uextension4_be, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.5.15 Table 8.34 WExtension8

Spec: §8.3.5.15, p. 49 — “WExtension8 is used in the HeaderExtension Submessage and enables the sender to add 8 octets of information to the header.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::wextension8)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_wextension8_le, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.5.16 Table 8.35 LocatorList

Spec: §8.3.5.16, p. 49 — “LocatorList is used to specify a list of locators.”

Repo: crates/rtps/src/submessages.rs (InfoReplySubmessage::unicast_locators, multicast_locators)

Tests: crates/rtps/src/datagram.rs::tests::decode_info_reply_with_multicast_via_datagram

Status: done

§8.3.5.17 Table 8.36 SerializedData

Spec: §8.3.5.17, p. 49 — “The RTPS protocol does not interpret the serialized data-stream. Therefore, it is represented as opaque data.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::serialized_payload); crates/rtps/src/payload.rs (Payload)

Tests: crates/rtps/src/datagram.rs::tests::the_shared_decode_gives_ranges_of_the_datagram, crates/rtps/tests/cyclone_compliance.rs::cyclone_data_cdr2_roundtrip_bit_identical

Status: done

§8.3.5.18 Table 8.37 SerializedDataFragment

Spec: §8.3.5.18, p. 49 — “SerializedDataFragment contains the serialized representation of a data-object that has been fragmented. … the RTPS protocol does not interpret the fragmented serialized data-stream.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::serialized_payload)

Tests: crates/rtps/src/datagram.rs::tests::decode_data_frag_preserves_flags_and_payload

Status: done

§8.3.5.19 Table 8.38 GroupDigest

Spec: §8.3.5.19, pp. 49–50 — “GroupDigest is used to communicate a set of EntityId_t in a compact manner.”

Repo: crates/rtps/src/group_digest.rs (GroupDigest, GroupDigest::of_entities)

Tests: crates/rtps/src/group_digest.rs::tests::two_writers_digest_as_section_9_3_2_5_computes_it, crates/rtps/src/group_digest.rs::tests::the_digest_does_not_depend_on_the_order_given, crates/rtps/src/group_digest.rs::tests::the_empty_group_is_zero_and_not_the_hash_of_an_empty_sequence

Status: done

§8.3.6.1 Header: Purpose

Spec: §8.3.6.1, p. 50 — “The Header is used to identify the message as belonging to the RTPS protocol, to identify the version of the RTPS protocol used, and to provide context information”.

Repo: —

Tests: —

Status: n/a (informative) — statement of purpose; the fields are listed under §8.3.3.1.

§8.3.6.2 Header: Content

Spec: §8.3.6.2, p. 50 — “The structure of the Header can only be changed if the major version of the protocol is also changed.”

Repo: —

Tests: —

Status: n/a (informative) — repeats §8.3.3.1; listed there as the item “Header structure fixed in version 2”.

§8.3.6.3 Header invalid: too few octets

Spec: §8.3.6.3, p. 50 — “The Message has less than the required number of octets to contain a full Header. The number required is defined by the PSM.”

Repo: crates/rtps/src/header.rs (RtpsHeader::from_bytes: UnexpectedEof below 20 octets)

Tests: crates/rtps/src/datagram.rs::tests::decode_rejects_datagram_shorter_than_the_header, crates/rtps/src/header.rs::tests::header_decode_rejects_truncated_input

Status: done

§8.3.6.3 Header invalid: protocol ≠ PROTOCOL_RTPS

Spec: §8.3.6.3, p. 50 — “Its protocol value does not match the value of PROTOCOL_RTPS.”

Repo: crates/rtps/src/header.rs (RtpsHeader::from_bytes: InvalidMagic)

Tests: crates/rtps/src/header.rs::tests::header_decode_rejects_invalid_magic, crates/rtps/src/datagram.rs::tests::decode_rejects_invalid_magic

Status: done

§8.3.6.3 Header invalid: major version too high

Spec: §8.3.6.3, p. 50 — “The major protocol version is larger than the major protocol version supported by the implementation.”

Repo: crates/rtps/src/datagram.rs (decode_datagram_into: comparison with ProtocolVersion::CURRENT.major)

Tests: crates/rtps/src/datagram.rs::tests::decode_rejects_major_version_above_supported, crates/rtps/src/datagram.rs::tests::decode_accepts_minor_version_above_supported

Status: done

§8.3.6.4 Receiver.sourceGuidPrefix = Header.guidPrefix

Spec: §8.3.6.4, p. 50 — “Receiver.sourceGuidPrefix = Header.guidPrefix”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::init_from_header)

Tests: crates/rtps/src/receiver_state.rs::tests::init_from_header_overrides_source_fields, crates/rtps/src/datagram.rs::tests::receiver_walk_without_info_source_attributes_to_header_prefix

Status: done

§8.3.6.4 Receiver.sourceVersion = Header.version

Spec: §8.3.6.4, p. 50 — “Receiver.sourceVersion = Header.version”.

Repo: crates/rtps/src/receiver_state.rs (init_from_header)

Tests: crates/rtps/src/receiver_state.rs::tests::the_header_sets_the_source_and_clears_have_timestamp

Status: done — the header sets sourceVersion, sourceVendorId and sourceGuidPrefix.

§8.3.6.4 Receiver.sourceVendorId = Header.vendorId

Spec: §8.3.6.4, p. 50 — “Receiver.sourceVendorId = Header.vendorId”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::init_from_header)

Tests: crates/rtps/src/receiver_state.rs::tests::init_from_header_overrides_source_fields

Status: done

§8.3.6.4 Receiver.haveTimestamp = false

Spec: §8.3.6.4, p. 50 — “Receiver.haveTimestamp = false”.

Repo: crates/rtps/src/receiver_state.rs (init_from_header)

Tests: crates/rtps/src/receiver_state.rs::tests::the_header_sets_the_source_and_clears_have_timestamp

Status: done — the header sets haveTimestamp = false.

§8.3.6.5 Header: Logical Interpretation

Spec: §8.3.6.5, p. 50 — “None”.

Repo: —

Tests: —

Status: n/a (informative) — no requirement.

§8.3.7.1 HeaderExtension immediately after the header

Spec: §8.3.7.1, p. 50 — “This submessage, if present, shall appear immediately after the RTPS Header.”

Repo: crates/rtps/src/datagram.rs (decode_datagram)

Tests: crates/rtps/src/datagram.rs::tests::decode_rejects_header_extension_after_data_submessage, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.7.2 HeaderExtension: Content

Spec: §8.3.7.2, p. 50 — “The elements that form the structure of the HeaderExtension were described in 8.3.3.2.”

Repo: —

Tests: —

Status: n/a (informative) — reference; items under §8.3.3.2.

§8.3.7.3 HE invalid: not directly after the header

Spec: §8.3.7.3, p. 51 — “The submessage is present but does not immediately follow the RTPS Header.”

Repo: crates/rtps/src/datagram.rs (decode_datagram)

Tests: crates/rtps/src/datagram.rs::tests::decode_rejects_header_extension_after_data_submessage

Status: done — a HeaderExtension behind another submessage is invalid and the rest of the message with it; the submessages before it stand.

§8.3.7.3 HE invalid: submessageLength too small for the fields

Spec: §8.3.7.3, p. 51 — “The submessageLength in the Submessage header is too small to fit the fields that are present as indicated by the submessage flags.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::decode_body)

Tests: crates/rtps/src/header_extension.rs::tests::decode_rejects_truncated_uextension4_body, crates/rtps/src/header_extension.rs::tests::decode_rejects_truncated_md5_checksum_body, crates/rtps/src/header_extension.rs::tests::decode_rejects_truncated_body_before_message_length, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.7.3 HE invalid: messageLength too small

Spec: §8.3.7.3, p. 51 — “The messageLength is too small to fit the RTPS Header and the HeaderExtension.”

Repo: crates/rtps/src/datagram.rs (decode_datagram)

Tests: crates/rtps/src/datagram.rs::tests::a_header_extension_message_length_too_small_for_header_and_extension_is_invalid

Status: done — a messageLength below header and HeaderExtension (28 octets) makes the message invalid.

§8.3.7.3 HE invalid: malformed parameters

Spec: §8.3.7.3, p. 51 — “The parameters are malformed.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::decode_body through ParameterList::from_bytes)

Tests: crates/rtps/src/header_extension.rs::tests::decode_rejects_malformed_parameter_list_when_p_flag_set, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.7.4 LengthFlag: Receiver.messageLength

Spec: §8.3.7.4, p. 51 — “IF ( LengthFlag ) { Receiver.messageLength = HeaderExtension.messageLength }”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_header_extension)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_header_extension_updates_fields, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.7.4 TimestampFlag: rtpsSendTimestamp, rtpsReceptionTimestamp, clockSkewDetected

Spec: §8.3.7.4, p. 51 — “IF ( TimestampFlag ) { Receiver.rtpsSendTimestamp = HeaderExtension.rtpsSendTimestamp; Receiver.rtpsReceptionTimestamp = GetCurrentTime(); RECEIVER.clockSkewDetected = CLOCK_SKEW_DETECTED(receptionTime, Receiver.rtpsSendTimestamp) }”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::note_reception, note_clock_skew, apply_info_timestamp); crates/rtps/src/datagram.rs (ReceptionClock, ReceiveContext); crates/dcps/src/runtime.rs (receive_context, RuntimeConfig::clock_skew_threshold_s)

Tests: crates/rtps/src/receiver_state.rs::tests::the_reception_time_is_kept_and_checked_against_the_send_time, crates/rtps/src/receiver_state.rs::tests::an_info_timestamp_is_corrected_by_the_clock_skew, crates/rtps/src/datagram.rs::tests::the_walk_with_a_reception_clock_detects_a_skew_and_corrects_the_timestamp, crates/dcps/tests/runtime_config_layering.rs::the_clock_skew_threshold_is_a_setting_and_off_by_default

Status: done — every receive path sets rtpsReceptionTimestamp (wall clock) for a HeaderExtension with a timestamp. The spec gives CLOCK_SKEW_DETECTED no threshold; it is the setting wire.clock_skew_threshold_s (seconds). Default 0 = off: clockSkewDetected then stays FALSE. There is no default threshold.

§8.3.7.4 uExtensionFlag: Receiver.uExtension4

Spec: §8.3.7.4, p. 51 — “IF ( uExtensionFlag ) { Receiver.uExtension4 = HeaderExtension.uExtension4 }”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_header_extension)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_header_extension_updates_fields

Status: done

§8.3.7.4 wExtensionFlag: Receiver.wExtension8

Spec: §8.3.7.4, p. 51 — “IF ( wExtensionFlag ) { Receiver.wExtension8 = HeaderExtension.wExtension8 }”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_header_extension)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_header_extension_updates_fields

Status: done

§8.3.7.4 ChecksumFlags: Receiver.messageChecksum

Spec: §8.3.7.4, p. 51 — “IF ( ChecksumFlags != 00 ) { Receiver.messageChecksum = HeaderExtension.messageChecksum }”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_header_extension)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_header_extension_updates_fields, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.7.4 ParametersFlag: Receiver.parameters

Spec: §8.3.7.4, p. 51 — “IF ( ParamatersFlag) { Receiver.parameters = HeaderExtension.parameters }”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_header_extension)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_header_extension_with_parameters_sets_pl, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.7.5 messageLength from the start of the RTPS header

Spec: §8.3.7.5, p. 51 — “The value of the messageLength shall indicate the length of the entire RTPS Message starting from the beginning of the RTPS Header.”

Repo: crates/rtps/src/datagram.rs, crates/rtps/src/header_extension.rs (validate_message_length)

Tests: crates/rtps/src/datagram.rs::tests::a_header_extension_message_length_counts_from_the_start_of_the_rtps_header

Status: done — the length is counted from the first octet of the RTPS Header and compared with the message received.

§8.3.7.5 rtpsSendTimestamp and rtpsReceptionTimestamp

Spec: §8.3.7.5, p. 51 — “The rtpsSendTimestamp represents the time the RTPS message was sent. It is measured using the clock of the sending Participant. The rtpsReceptionTimestamp represents the time when the RTPS message was received.”

Repo: —

Tests: —

Status: n/a (informative) — definition; the assignments are listed under §8.3.7.4 TimestampFlag.

§8.3.7.5 CLOCK_SKEW_DETECTED

Spec: §8.3.7.5, pp. 51–52 — “The function CLOCK_SKEW_DETECTED() represents an implementation-specific function used to determine whether the sending and receiving participant clocks are not synchronized or have too large a skew.”

Repo: crates/rtps/src/receiver_state.rs (note_reception, note_clock_skew); crates/dcps/src/runtime.rs (receive_context, wire.clock_skew_threshold_s)

Tests: crates/rtps/src/receiver_state.rs::tests::the_reception_time_is_kept_and_checked_against_the_send_time, crates/rtps/src/datagram.rs::tests::the_walk_with_a_reception_clock_detects_a_skew_and_corrects_the_timestamp, crates/dcps/tests/runtime_config_layering.rs::the_clock_skew_threshold_is_a_setting_and_off_by_default

Status: done — the spec calls the function implementation specific; ZeroDDS compares reception and send time against the threshold wire.clock_skew_threshold_s (default 0 = off, no default threshold).

§8.3.7.5 messageChecksum with the checksum field zeroed

Spec: §8.3.7.5, p. 52 — “It shall be computed over the entire RTPS Message. For the purpose of computing the checksum, the value of the messageChecksum field in the RTPS HeaderExtension shall be set to zero.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::message_checksum, seal_message, verify_message, encode_body, decode_body); crates/rtps/src/datagram.rs (decode_submessage)

Tests: crates/rtps/src/header_extension.rs::tests::a_sealed_message_verifies_and_a_changed_one_does_not, crates/rtps/src/header_extension.rs::tests::the_checksum_is_big_endian_in_a_little_endian_header_extension, crates/rtps/src/datagram.rs::tests::a_message_with_a_wrong_checksum_is_refused_and_counted

Status: done — message_checksum computes over the whole message with the field zeroed.

§8.3.7.5 uExtension4, wExtension8, parameters without meaning

Spec: §8.3.7.5, p. 52 — “The uExtension4 and wExtension8 may be useful to communicate additional data on the header in a future version … This version of the specification does not define any parameters in the HeaderExtension.”

Repo: —

Tests: —

Status: n/a (informative) — no requirement on this version.

§8.3.8 Entity and interpreter submessages

Spec: §8.3.8, pp. 52–53, Table 8.39 — division into entity submessages (Data, DataFrag, Heartbeat, HeartbeatFrag, Gap, AckNack, NackFrag) and interpreter submessages (HeaderExtension, InfoSource, InfoDestination, InfoReply, InfoTimestamp, Pad); outline of every description.

Repo: —

Tests: —

Status: n/a (informative) — overview; the submessages are listed one by one under §8.3.8.1–§8.3.8.13.

§8.3.8.1 AckNack: Purpose

Spec: §8.3.8.1, p. 54 — “This Submessage is used to communicate the state of a Reader to a Writer. … This Submessage can be used to do both positive and negative acknowledgments.”

Repo: —

Tests: —

Status: n/a (informative) — statement of purpose; the contents follow.

§8.3.8.1 Table 8.40 AckNack EndiannessFlag

Spec: §8.3.8.1, p. 54, Table 8.40 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/submessages.rs (AckNackSubmessage::write_body, AckNackSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::tests::acknack_submessage_roundtrip_le, crates/rtps/tests/vendor_frames.rs::fastdds_datagrams_re_encode_byte_for_byte

Status: done

§8.3.8.1 Table 8.40 AckNack FinalFlag

Spec: §8.3.8.1, p. 54, Table 8.40 — “FinalFlag … Indicates to the Writer whether a response is mandatory.”

Repo: crates/rtps/src/submessages.rs (AckNackSubmessage::final_flag, ACKNACK_FLAG_FINAL); crates/rtps/src/reliable_reader.rs (build_acknack_datagram)

Tests: crates/rtps/src/submessages.rs::tests::acknack_submessage_with_final_flag, crates/rtps/src/datagram.rs::tests::decode_acknack_preserves_final_flag

Status: done — the writer’s duty to respond is listed under §9.4.5.3.

§8.3.8.1 Table 8.40 AckNack readerId

Spec: §8.3.8.1, p. 54, Table 8.40 — “readerId: EntityId — Identifies the Reader entity that acknowledges receipt of certain sequence numbers and/or requests to receive certain sequence numbers.”

Repo: crates/rtps/src/submessages.rs (AckNackSubmessage::reader_id)

Tests: crates/rtps/src/submessages.rs::tests::acknack_submessage_roundtrip_le

Status: done

§8.3.8.1 Table 8.40 AckNack writerId

Spec: §8.3.8.1, p. 54, Table 8.40 — “writerId: EntityId — Identifies the Writer entity that is the target of the AckNack message.”

Repo: crates/rtps/src/submessages.rs (AckNackSubmessage::writer_id); crates/dcps/src/runtime.rs (handle_user_datagram_from: rt.writer_slot(ack.writer_id))

Tests: crates/rtps/src/submessages.rs::tests::acknack_submessage_roundtrip_le, crates/rtps/src/reliable_writer.rs::tests::acknack_dispatches_to_matching_proxy_only

Status: done

§8.3.8.1 Table 8.40 AckNack readerSNState

Spec: §8.3.8.1, p. 54, Table 8.40 — “All sequence numbers up to the one prior to readerSNState.base are confirmed as received by the reader. The sequence numbers that appear in the set indicate missing sequence numbers on the reader side.”

Repo: crates/rtps/src/submessages.rs (AckNackSubmessage::reader_sn_state); crates/rtps/src/reliable_writer.rs (handle_acknack_set_at)

Tests: crates/rtps/src/reliable_writer.rs::tests::handle_acknack_updates_proxy_state, crates/rtps/src/reliable_writer.rs::tests::handle_acknack_with_lower_base_leaves_requested

Status: done

§8.3.8.1 Table 8.40 AckNack count

Spec: §8.3.8.1, p. 54, Table 8.40 — “count: Count — A counter that is incremented each time a new AckNack message is sent.”

Repo: crates/rtps/src/reliable_reader.rs (build_acknack_datagram)

Tests: crates/rtps/src/reliable_reader.rs::tests::the_counts_of_acknack_and_nack_frag_rise_with_each_message

Status: done — successive ACKNACKs carry the counts 1, 2, 3.

§8.3.8.1 AckNack invalid: submessageLength too small

Spec: §8.3.8.1, p. 54 — “submessageLength in the Submessage header is too small.”

Repo: crates/rtps/src/submessages.rs (AckNackSubmessage::read_body)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — the shortening is recognised; the submessage is invalid and the rest of the message with it, the submessages before it stand (ParsedDatagram::invalid_rest, counted).

§8.3.8.1 AckNack invalid: invalid readerSNState

Spec: §8.3.8.1, p. 54 — “readerSNState is invalid (as defined in Section 8.3.5.5).”

Repo: crates/rtps/src/submessages.rs (SequenceNumberSet::read_from)

Tests: crates/rtps/src/submessages.rs::validity_tests::gap_and_sequence_number_set_validity_rules, crates/rtps/src/submessages.rs::tests::seqnumset_rejects_num_bits_above_256, crates/rtps/tests/vendor_frames.rs::the_empty_acknack_of_opendds_and_rti_is_invalid_by_default, crates/rtps/tests/vendor_frames.rs::opendds_session_re_encodes_byte_for_byte, crates/rtps/tests/vendor_frames.rs::rti_session_re_encodes_byte_for_byte, crates/rtps/src/submessages.rs::validity_tests::the_empty_set_with_base_zero_is_accepted_only_on_request

Status: done — numBits > 256 and bitmapBase < 1 are refused, with the rest of the message. Vendor form: OpenDDS 3.34.0 and RTI Connext 7.7.0 send readerSNState 0/0: (bitmapBase 0, numBits 0) as the ACKNACK of a reader without samples (measured in tools/wire-capture/rtps-sessions: 40 and 8 ACKNACKs). Default: invalid. The setting wire.accept_empty_acknack_base_zero (env ZERODDS_WIRE_ACCEPT_EMPTY_ACKNACK_BASE_ZERO, default false) accepts exactly this empty set in an ACKNACK, for the process.

§8.3.8.1 AckNack: writerGUID = {destGuidPrefix, writerId}

Spec: §8.3.8.1, p. 54 — “writerGUID = { Receiver.destGuidPrefix, AckNack.writerId }”.

Repo: crates/dcps/src/runtime.rs (handle_user_datagram_from: lookup by ack.writer_id)

Tests: crates/dcps/src/runtime.rs::tests::the_submessages_after_an_info_destination_for_another_participant_are_not_ours

Status: done

§8.3.8.1 AckNack: readerGUID = {sourceGuidPrefix, readerId}

Spec: §8.3.8.1, p. 55 — “readerGUID = { Receiver.sourceGuidPrefix, AckNack.readerId }”.

Repo: crates/dcps/src/runtime.rs (handle_user_datagram_from: Guid::new(src_prefix, ack.reader_id)); crates/rtps/src/reliable_writer.rs (handle_acknack_window)

Tests: crates/rtps/src/reliable_writer.rs::tests::handle_acknack_unknown_source_counts_but_noops, crates/rtps/src/reliable_writer.rs::tests::acknack_dispatches_to_matching_proxy_only

Status: done

§8.3.8.1 AckNack: positive acknowledgement up to base − 1

Spec: §8.3.8.1, p. 55 — “The Submessage acknowledges all sequence numbers up to and including the one just before the lowest sequence number in the SequenceNumberSet (that is readerSNState.base -1).”

Repo: crates/rtps/src/reliable_writer.rs (handle_acknack_window: acked_changes_set(base)); crates/rtps/src/reader_proxy.rs (ReaderProxy::acked_changes_set)

Tests: crates/rtps/src/reader_proxy.rs::tests::acked_changes_set_monotonic, crates/rtps/src/reliable_writer.rs::tests::is_acked_by_all_follows_the_slowest_reader_proxy

Status: done

§8.3.8.1 AckNack: negative acknowledgement of the set

Spec: §8.3.8.1, p. 55 — “The Submessage negatively-acknowledges (requests) the sequence numbers that appear explicitly in the set.”

Repo: crates/rtps/src/reliable_writer.rs (handle_acknack_window: requested_changes_set)

Tests: crates/rtps/src/reliable_writer.rs::tests::tick_resends_requested_as_data_aggregated_with_hb, crates/rtps/src/reader_proxy.rs::tests::a_request_for_an_acknowledged_change_is_kept

Status: done

§8.3.8.2 Data: Purpose

Spec: §8.3.8.2, p. 55 — “The Submessage notifies the RTPS Reader of a change to a data-object belonging to the RTPS Writer.”

Repo: —

Tests: —

Status: n/a (informative) — statement of purpose.

§8.3.8.2 Table 8.41 Data EndiannessFlag

Spec: §8.3.8.2, p. 55, Table 8.41 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::write_body, DataSubmessage::read_body_with_flags)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_roundtrip_be_with_empty_payload, crates/rtps/src/submessages.rs::tests::data_submessage_roundtrip_le

Status: done

§8.3.8.2 Table 8.41 Data InlineQosFlag

Spec: §8.3.8.2, p. 55, Table 8.41 — “InlineQosFlag … Indicates to the Reader the presence of a ParameterList containing QoS parameters that should be used to interpret the message.”

Repo: crates/rtps/src/submessages.rs (DATA_FLAG_INLINE_QOS, DataSubmessage::inline_qos)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_all_valid_flags_combined_roundtrip, crates/rtps/src/submessages.rs::tests::a_pid_ignore_in_the_inline_qos_does_not_move_the_payload

Status: done

§8.3.8.2 Table 8.41 Data DataFlag

Spec: §8.3.8.2, p. 55, Table 8.41 — “DataFlag … Indicates to the Reader that the dataPayload submessage element contains the serialized value of the data-object.”

Repo: crates/rtps/src/submessages.rs (DATA_FLAG_DATA, DataSubmessage::data_flag)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_roundtrip_le, crates/rtps/src/reliable_reader.rs::tests::alive_data_yields_alive_changekind

Status: done

§8.3.8.2 Table 8.41 Data KeyFlag

Spec: §8.3.8.2, p. 55, Table 8.41 — “KeyFlag … Indicates to the Reader that the dataPayload submessage element contains the serialized value of the key of the data-object.”

Repo: crates/rtps/src/submessages.rs (DATA_FLAG_KEY, DataSubmessage::key_flag)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_key_flag_roundtrip, crates/rtps/src/reliable_writer.rs::tests::lifecycle_with_a_key_sets_k_and_carries_it

Status: done

§8.3.8.2 Table 8.41 Data NonStandardPayloadFlag

Spec: §8.3.8.2, p. 55, Table 8.41 — “NonStandardPayloadFlag … Indicates to the Reader that the serializedPayload submessage element is not formatted according to Section 10.”

Repo: crates/rtps/src/submessages.rs (DATA_FLAG_NON_STANDARD, DataSubmessage::non_standard_flag)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_non_standard_flag_roundtrip

Status: done

§8.3.8.2 Table 8.41 Data readerId

Spec: §8.3.8.2, p. 55, Table 8.41 — “readerId: EntityId — Identifies the RTPS Reader entity that is being informed of the change to the data-object.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::reader_id)

Tests: crates/rtps/src/reader.rs::tests::reader_drops_data_addressed_to_other_reader, crates/rtps/src/reader.rs::tests::reader_delivers_data_addressed_to_us

Status: done

§8.3.8.2 Table 8.41 Data writerId

Spec: §8.3.8.2, p. 55, Table 8.41 — “writerId: EntityId — Identifies the RTPS Writer entity that made the change to the data-object.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::writer_id)

Tests: crates/rtps/src/reliable_reader.rs::tests::mismatched_writer_id_is_counted

Status: done

§8.3.8.2 Table 8.41 Data writerSN

Spec: §8.3.8.2, p. 56, Table 8.41 — “writerSN: SequenceNumber — Uniquely identifies the change and the relative order for all changes made by the RTPS Writer … Each change gets a consecutive sequence number.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::writer_sn); crates/rtps/src/reliable_writer.rs (ReliableWriter::write)

Tests: crates/rtps/src/writer.rs::tests::writer_three_writes_have_increasing_sn_in_decoded, crates/rtps/src/reliable_reader.rs::tests::out_of_order_data_buffered_until_gap_filled

Status: done

§8.3.8.2 Table 8.41 Data inlineQos

Spec: §8.3.8.2, p. 56, Table 8.41 — “inlineQos: ParameterList — Present only if the InlineQosFlag is set in the header.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::read_body_into: ParameterList only with Q)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_all_valid_flags_combined_roundtrip, crates/rtps/src/inline_qos.rs::tests::coherent_set_survives_data_submessage_roundtrip

Status: done

§8.3.8.2 Table 8.41 Data serializedPayload

Spec: §8.3.8.2, p. 56, Table 8.41 — “serializedPayload: SerializedPayload — Present only if either the DataFlag or the KeyFlag are set in the header.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::serialized_payload)

Tests: crates/rtps/src/reliable_writer.rs::tests::lifecycle_without_a_key_clears_k_and_sends_no_payload, crates/rtps/tests/cyclone_compliance.rs::cyclone_data_empty_payload_decodes

Status: done

§8.3.8.2 Data invalid: submessageLength too small

Spec: §8.3.8.2, p. 56 — “submessageLength in the Submessage header is too small.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::read_body_into)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — the shortening is recognised; the submessage is invalid and the rest of the message with it, the submessages before it stand (ParsedDatagram::invalid_rest, counted).

§8.3.8.2 Data invalid: writerSN ≤ 0 or SEQUENCENUMBER_UNKNOWN

Spec: §8.3.8.2, p. 56 — “writerSN.value is not strictly positive (1, 2, …) or is SEQUENCENUMBER_UNKNOWN.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::read_body_into)

Tests: crates/rtps/src/submessages.rs::validity_tests::data_with_writer_sn_not_positive_or_with_d_and_k_is_invalid

Status: done — a writerSN below 1 and SEQUENCENUMBER_UNKNOWN ({-1, 0}) are refused; the submessage is invalid and the rest of the message with it.

§8.3.8.2 Data invalid: invalid inlineQos

Spec: §8.3.8.2, p. 56 — “inlineQos is invalid.”

Repo: crates/rtps/src/parameter_list.rs (ParameterList::from_bytes_with_consumed); crates/rtps/src/datagram.rs (validate_must_understand_in_data_pipeline)

Tests: crates/rtps/src/parameter_list.rs::tests::decode_rejects_truncated_value, crates/rtps/src/datagram.rs::tests::a_data_with_an_unknown_must_understand_pid_is_skipped, crates/rtps/src/datagram.rs::tests::the_submessages_before_an_invalid_one_stand

Status: done — a malformed ParameterList makes the DATA invalid and discards the rest of the message, the submessages before it stay (§8.3.4.1 rule 6); an unknown must-understand PID skips only the DATA (Table 9.6).

§8.3.8.2 Data: DataFlag without KeyFlag is the value

Spec: §8.3.8.2, p. 56 — “If the DataFlag is set and the KeyFlag is not set, the serializedPayload element is interpreted as the value of the data-object.”

Repo: crates/rtps/src/reliable_reader.rs (classify_change_kind, handle_data_into)

Tests: crates/rtps/src/reliable_reader.rs::tests::alive_data_yields_alive_changekind, crates/rtps/src/reliable_reader.rs::tests::in_order_data_delivered_immediately

Status: done

§8.3.8.2 Data: KeyFlag without DataFlag is the key

Spec: §8.3.8.2, p. 56 — “If the KeyFlag is set and the DataFlag is not set, the serializedPayload element is interpreted as the value of the key that identifies the registered instance of the data-object.”

Repo: crates/rtps/src/reliable_reader.rs (handle_data_into: a key-only DATA without lifecycle status as a registration)

Tests: crates/rtps/src/reliable_reader.rs::tests::key_only_alive_registration_is_acked_but_not_delivered, crates/rtps/src/reliable_reader.rs::tests::dispose_data_yields_not_alive_disposed

Status: done

§8.3.8.2 Data: inline QoS overrides the writer’s QoS

Spec: §8.3.8.2, p. 56 — “If the InlineQosFlag is set, the inlineQos element contains QoS values that override those of the RTPS Writer and should be used to process the update. For a complete list of possible in-line QoS parameters, see Table 8.85.”

Repo: crates/rtps/src/inline_qos.rs (InlineQosOverride); crates/rtps/src/reliable_reader.rs (DeliveredSample::inline_qos_override); crates/dcps/src/runtime.rs (sample_strength, sample_lifespan_nanos)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_data_hands_on_the_in_line_strength_and_lifespan, crates/dcps/src/runtime.rs::tests::the_in_line_strength_and_lifespan_of_a_sample_override_the_writers

Status: done — OWNERSHIP_STRENGTH and LIFESPAN that a DATA carries in-line apply to that sample instead of the values the writer announced. The other policies of Table 8.85 do not act on a single sample (they enter the match: DURABILITY, RELIABILITY, PRESENTATION, PARTITION, DEADLINE, LATENCY_BUDGET, DESTINATION_ORDER, LIVELINESS), TRANSPORT_PRIORITY is the sender’s.

§8.3.8.2 Data: NonStandardPayloadFlag informational only

Spec: §8.3.8.2, p. 56 — “This flag is informational. It indicates that the SerializedPayload has been transformed as described in another specification. For example, this flag should be set when the SerializedPayload is transformed as described in the DDS-Security specification.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::non_standard_flag is read, not interpreted)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_non_standard_flag_roundtrip

Status: done — whether ZeroDDS sets the flag on payloads transformed by DDS-Security was not checked.

§8.3.8.2 Data: writerGUID = {sourceGuidPrefix, writerId}

Spec: §8.3.8.2, p. 56 — “writerGUID = { Receiver.sourceGuidPrefix, Data.writerId }”.

Repo: crates/rtps/src/reliable_reader.rs (proxy_index_by_writer); crates/dcps/src/runtime.rs (handle_user_datagram_from: src_prefix from receiver_walk)

Tests: crates/rtps/src/reliable_reader.rs::tests::same_entity_id_different_prefix_not_confused, crates/discovery/tests/opensplice_infosrc_regression.rs::opensplice_bundled_infosrc_datagrams_attribute_to_the_real_source

Status: done

§8.3.8.2 Data: readerGUID = {destGuidPrefix, readerId}

Spec: §8.3.8.2, p. 56 — “readerGUID = { Receiver.destGuidPrefix, Data.readerId }”.

Repo: crates/dcps/src/runtime.rs (handle_user_datagram_from: rt.reader_slot(d.reader_id))

Tests: crates/dcps/src/runtime.rs::tests::the_submessages_after_an_info_destination_for_another_participant_are_not_ours

Status: done

§8.3.8.2 Data: readerId ENTITYID_UNKNOWN

Spec: §8.3.8.2, p. 56 — “The Data.readerId can be ENTITYID_UNKNOWN, in which case the Data applies to all Readers of that writerGUID within the Participant identified by the GuidPrefix_t Receiver.destGuidPrefix.”

Repo: crates/dcps/src/runtime.rs (handle_user_datagram_from: with EntityId::UNKNOWN to every reader slot, filtered by the writer proxy)

Tests: crates/rtps/src/reader.rs::tests::reader_accepts_unknown_wildcard_target

Status: done — the restriction to the participant of destGuidPrefix depends on the item under §8.3.8.8.

§8.3.8.3 DataFrag: Purpose

Spec: §8.3.8.3, p. 57 — “The DataFrag Submessage extends the Data Submessage by enabling the serializedData to be fragmented and sent as multiple DataFrag Submessages.”

Repo: —

Tests: —

Status: n/a (informative) — statement of purpose.

§8.3.8.3 Table 8.42 DataFrag EndiannessFlag

Spec: §8.3.8.3, p. 57, Table 8.42 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::write_body, DataFragSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::tests::data_frag_roundtrip_be, crates/rtps/src/submessages.rs::tests::data_frag_roundtrip_le

Status: done

§8.3.8.3 Table 8.42 DataFrag InlineQosFlag

Spec: §8.3.8.3, p. 57, Table 8.42 — “InlineQosFlag … Indicates to the Reader the presence of a ParameterList containing QoS parameters”.

Repo: crates/rtps/src/submessages.rs (DATA_FRAG_FLAG_INLINE_QOS)

Tests: crates/rtps/src/submessages.rs::tests::data_frag_flags_survive_roundtrip, crates/rtps/src/datagram.rs::tests::data_frag_spec_and_cyclone_flag_oracle

Status: done

§8.3.8.3 Table 8.42 DataFrag NonStandardPayloadFlag

Spec: §8.3.8.3, p. 57, Table 8.42 — “NonStandardPayloadFlag … Indicates to the Reader that the serializedPayload submessage element is not formatted according to Section 10.”

Repo: crates/rtps/src/submessages.rs (DATA_FRAG_FLAG_NON_STANDARD)

Tests: crates/rtps/src/submessages.rs::tests::data_frag_flags_survive_roundtrip

Status: done

§8.3.8.3 Table 8.42 DataFrag KeyFlag

Spec: §8.3.8.3, p. 57, Table 8.42 — “KeyFlag … Indicates to the Reader that the dataPayload submessage element contains the serialized value of the key of the data-object.”

Repo: crates/rtps/src/submessages.rs (DATA_FRAG_FLAG_KEY, DataFragSubmessage::key_flag)

Tests: crates/rtps/src/datagram.rs::tests::decode_data_frag_preserves_flags_and_payload

Status: done

§8.3.8.3 Table 8.42 DataFrag readerId

Spec: §8.3.8.3, p. 57, Table 8.42 — “readerId: EntityId — Identifies the RTPS Reader entity that is being informed of the change”.

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::reader_id)

Tests: crates/rtps/src/submessages.rs::tests::data_frag_roundtrip_le

Status: done

§8.3.8.3 Table 8.42 DataFrag writerId

Spec: §8.3.8.3, p. 57, Table 8.42 — “writerId: EntityId — Identifies the RTPS Writer entity that made the change”.

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::writer_id)

Tests: crates/rtps/src/submessages.rs::tests::data_frag_roundtrip_le

Status: done

§8.3.8.3 Table 8.42 DataFrag writerSN

Spec: §8.3.8.3, p. 57, Table 8.42 — “writerSN: SequenceNumber — Uniquely identifies the change and the relative order for all changes made by the RTPS Writer”.

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::writer_sn); crates/rtps/src/fragment_assembler.rs (buffer per writer_sn)

Tests: crates/rtps/src/fragment_assembler.rs::tests::incomplete_sns_enumerates_in_order

Status: done

§8.3.8.3 Table 8.42 DataFrag fragmentStartingNum

Spec: §8.3.8.3, p. 57, Table 8.42 — “fragmentStartingNum: FragmentNumber — Indicates the starting fragment for the series of fragments in serializedData. Fragment numbering starts with number 1.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::fragment_starting_num)

Tests: crates/rtps/src/fragment_assembler.rs::tests::fragment_index_zero_dropped, crates/rtps/src/fragment_assembler.rs::tests::two_fragments_complete_in_order

Status: done

§8.3.8.3 Table 8.42 DataFrag fragmentsInSubmessage

Spec: §8.3.8.3, p. 58, Table 8.42 — “fragmentsInSubmessage: ushort — The number of consecutive fragments contained in this Submessage, starting at fragmentStartingNum.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::fragments_in_submessage)

Tests: crates/rtps/src/fragment_assembler.rs::tests::bundled_fragments_all_full, crates/rtps/src/fragment_assembler.rs::tests::bundled_fragments_including_last_with_tail

Status: done

§8.3.8.3 Table 8.42 DataFrag dataSize

Spec: §8.3.8.3, p. 58, Table 8.42 — “dataSize: ulong — The total size in bytes of the original data before fragmentation.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::sample_size)

Tests: crates/rtps/src/fragment_assembler.rs::tests::inconsistent_sample_size_drops_fragment

Status: done

§8.3.8.3 Table 8.42 DataFrag fragmentSize

Spec: §8.3.8.3, p. 58, Table 8.42 — “fragmentSize: ushort — The size of an individual fragment in bytes. The maximum fragment size equals 64K.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::fragment_size, type u16)

Tests: crates/rtps/src/fragment_assembler.rs::tests::fragment_size_zero_dropped, crates/rtps/src/submessages.rs::tests::data_frag_last_fragment_shorter_than_fragment_size

Status: done

§8.3.8.3 Table 8.42 DataFrag inlineQos

Spec: §8.3.8.3, p. 58, Table 8.42 — “inlineQos: ParameterList — Present only if the InlineQosFlag is set in the header.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::inline_qos)

Tests: crates/rtps/src/submessages.rs::tests::data_frag_key_hash_roundtrips_both_byte_orders, crates/rtps/src/submessages.rs::tests::data_frag_ignored_parameter_does_not_become_payload

Status: done

§8.3.8.3 Table 8.42 DataFrag serializedPayload

Spec: §8.3.8.3, p. 58, Table 8.42 — “A consecutive series of fragments, starting at fragmentStartingNum for a total of fragmentsInSubmessage. … If the KeyFlag is set, then it contains a consecutive set of fragments of the key”.

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::serialized_payload); crates/rtps/src/fragment_assembler.rs (FragmentAssembler::insert)

Tests: crates/rtps/src/fragment_assembler.rs::tests::fragments_complete_out_of_order, crates/rtps/src/fragment_assembler.rs::tests::last_fragment_shorter_than_fragment_size

Status: done

§8.3.8.3 DataFrag invalid: submessageLength too small

Spec: §8.3.8.3, p. 58 — “submessageLength in the Submessage header is too small.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::read_body)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — the shortening is recognised; the submessage is invalid and the rest of the message with it, the submessages before it stand (ParsedDatagram::invalid_rest, counted).

§8.3.8.3 DataFrag invalid: writerSN ≤ 0 or SEQUENCENUMBER_UNKNOWN

Spec: §8.3.8.3, p. 58 — “writerSN.value is not strictly positive (1, 2, …) or is SEQUENCENUMBER_UNKNOWN.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::validity_tests::data_frag_validity_rules

Status: done — as for DATA.

§8.3.8.3 DataFrag invalid: fragmentStartingNum out of range

Spec: §8.3.8.3, p. 58 — “fragmentStartingNum.value is not strictly positive (1, 2, …) or exceeds the total number of fragments”.

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::read_body); crates/rtps/src/fragment_assembler.rs (FragmentAssembler::insert: FragmentIndexZero, FragmentIndexOutOfRange)

Tests: crates/rtps/src/submessages.rs::validity_tests::data_frag_validity_rules, crates/rtps/src/fragment_assembler.rs::tests::fragment_index_zero_dropped, crates/rtps/src/fragment_assembler.rs::tests::fragment_index_out_of_range_dropped

Status: done — a fragmentStartingNum below 1 or above the number of fragments (dataSize / fragmentSize, rounded up) makes the submessage and the rest of the message invalid.

§8.3.8.3 DataFrag invalid: fragmentSize > dataSize

Spec: §8.3.8.3, p. 58 — “fragmentSize exceeds dataSize.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::validity_tests::data_frag_validity_rules

Status: done — a fragmentSize above dataSize and a fragmentSize of 0 are refused.

§8.3.8.3 DataFrag invalid: serializedData too large

Spec: §8.3.8.3, p. 58 — “The size of serializedData exceeds fragmentsInSubmessage * fragmentSize.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::read_body); crates/rtps/src/fragment_assembler.rs (FragmentAssembler::insert: PayloadSizeMismatch)

Tests: crates/rtps/src/submessages.rs::validity_tests::data_frag_validity_rules, crates/rtps/src/fragment_assembler.rs::tests::payload_size_mismatch_dropped, crates/rtps/src/fragment_assembler.rs::tests::bundled_fragments_payload_size_mismatch_rejected

Status: done — more octets than fragmentsInSubmessage * fragmentSize make the submessage invalid. The last fragment of the sample is as long as the sample leaves, rounded up to 4 octets: Cyclone DDS and Fast DDS pad it to the alignment of the submessage (72 octets for 71, measured).

§8.3.8.3 DataFrag invalid: invalid inlineQos

Spec: §8.3.8.3, p. 58 — “inlineQos is invalid.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::validity_tests::data_frag_with_an_invalid_inline_qos_is_invalid

Status: done — a parameter list that runs past the body or has no sentinel makes the submessage invalid.

§8.3.8.3 DataFrag: reassembly, offset and number of fragments

Spec: §8.3.8.3, pp. 58–59 — offset “(fragmentStartingNum - 1) * fragmentSize”; “The data is fully re-assembled when all fragments have been received. The total number of fragments to expect equals: (dataSize / fragmentSize) + ((dataSize % fragmentSize) ? 1 : 0)”.

Repo: crates/rtps/src/fragment_assembler.rs (FragmentAssembler::insert: byte_start, total_fragments = sample_size.div_ceil(fragment_size))

Tests: crates/rtps/src/fragment_assembler.rs::tests::fragments_complete_out_of_order, crates/rtps/src/fragment_assembler.rs::tests::missing_fragments_enumerates_gaps, crates/rtps/tests/reliable_e2e.rs::e2e_frag_large_sample_10_percent_loss

Status: done

§8.3.8.3 DataFrag: once reassembled, interpreted as Data

Spec: §8.3.8.3, p. 58 — “Once the serializedData is re-assembled by the RTPS Reader, the interpretation of the DataFrag Submessages is identical to that of the Data Submessage.”

Repo: —

Tests: crates/rtps/src/reliable_reader.rs::tests::a_fragmented_dispose_is_delivered_as_a_dispose, crates/rtps/src/fragment_assembler.rs::tests::the_first_fragments_inline_qos_reaches_the_completed_sample

Status: done

§8.3.8.3 DataFrag: fragment size from the smallest transport

Spec: §8.3.8.3, p. 59 — “An RTPS Writer will select fragmentSize based on the smallest message size supported across all underlying transports. … the RTPS Writer can pack multiple fragments into a single DataFrag Submessage or may even send a regular Data Submessage if fragmentation is no longer required.”

Repo: crates/rtps/src/reliable_writer.rs (fragment_size_for_message_size, fragments_per_message, ReliableWriterConfig::fragment_size); crates/transport/src/lib.rs (Transport::max_message_size); crates/dcps/src/runtime.rs (writer creation)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_under_fragment_size_produces_single_data, crates/rtps/src/reliable_writer.rs::tests::write_above_fragment_size_packs_the_fragments_a_message_carries, crates/rtps/src/reliable_writer.rs::tests::fragment_size_is_fixed_and_a_larger_path_gets_one_data, crates/dcps/src/runtime.rs::tests::a_writers_fragment_size_follows_the_message_size_of_its_transport

Status: done — the fragment size of a writer follows the smallest message size of its transports (Transport::max_message_size, item under §8.4.14.1); several fragments go into one DATA_FRAG where the message carries them; a path that needs no fragmentation gets a DATA.

§8.3.8.3 DataFrag: inline QoS needed on the first fragment only

Spec: §8.3.8.3, p. 59 — “When sending inlineQos with DataFrag Submessages, it is only required to send the inlineQos with the first DataFrag Submessage for a given Writer sequence number.”

Repo: crates/rtps/src/reliable_writer.rs (inline QoS with PID_KEY_HASH on the DATA_FRAGs of a sample)

Tests: crates/rtps/src/reliable_writer.rs::tests::keyed_alive_preserves_inline_hash_on_data_fragments_and_rebuilds

Status: done — the inline QoS of a coherent-set member on the first DATA_FRAG is listed under §8.7.6.

§8.3.8.4 Gap: Purpose and filtered changes

Spec: §8.3.8.4, p. 59 — “indicates to the RTPS Reader that a set of changes in the RTPS Writer HistoryCache are not available to one or more RTPS Reader endpoints and will not be sent to them. … Filtered changes should not be treated as samples lost by the RTPS Reader.”

Repo: crates/rtps/src/reliable_reader.rs (handle_gap: irrelevant_change_set)

Tests: crates/rtps/src/writer_proxy.rs::tests::gap_marks_irrelevant, crates/rtps/src/writer_proxy.rs::tests::lost_changes_update_counts_what_was_neither_received_nor_irrelevant

Status: done

§8.3.8.4 Table 8.43 Gap EndiannessFlag

Spec: §8.3.8.4, p. 59, Table 8.43 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/submessages.rs (GapSubmessage::write_body, GapSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::tests::gap_submessage_roundtrip_le, crates/rtps/src/submessages.rs::tests::gap_with_group_info_roundtrip_be

Status: done

§8.3.8.4 Table 8.43 Gap GroupInfoFlag

Spec: §8.3.8.4, p. 59, Table 8.43 — “GroupInfoFlag … Indicates the presence of additional information about the group of writers (Writer Group) the sender belongs to.”

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::gap_with_group_info_roundtrip_be, crates/rtps/src/submessages.rs::tests::gap_decode_rejects_invalid_group_sequence_numbers, crates/rtps/src/submessages.rs::tests::a_gap_end_gsn_one_below_its_start_is_an_empty_range_and_valid, crates/rtps/src/submessages.rs::tests::the_gap_flags_are_those_of_9_4_5_6

Status: done

§8.3.8.4 Table 8.43 Gap FilteredCountFlag

Spec: §8.3.8.4, p. 59, Table 8.43 — “FilteredCountFlag … Indicates the presence of the filteredCount submessage element.”

Repo: crates/rtps/src/submessages.rs (GAP_FLAG_FILTERED_COUNT)

Tests: crates/rtps/src/submessages.rs::tests::the_gap_flags_are_those_of_9_4_5_6, crates/rtps/src/submessages.rs::tests::gap_with_filtered_count_roundtrip_le

Status: done

§8.3.8.4 Table 8.43 Gap readerId

Spec: §8.3.8.4, p. 59, Table 8.43 — “The readerId may be set to ENTITYID_UNKNOWN to indicate the Gap message applies to all Readers within the receiving Participant that are matched with the Writer specified by the writerId.”

Repo: crates/rtps/src/submessages.rs (GapSubmessage::reader_id); crates/dcps/src/runtime.rs (handle_user_datagram_from: fan-out on EntityId::UNKNOWN)

Tests: crates/rtps/src/submessages.rs::tests::gap_submessage_roundtrip_le

Status: done

§8.3.8.4 Table 8.43 Gap writerId

Spec: §8.3.8.4, p. 60, Table 8.43 — “writerId: EntityId — Identifies the Writer Entity to which the not-available changes apply.”

Repo: crates/rtps/src/submessages.rs (GapSubmessage::writer_id); crates/rtps/src/reliable_reader.rs (handle_gap)

Tests: crates/rtps/src/reliable_reader.rs::tests::gap_after_the_held_data_releases_it

Status: done

§8.3.8.4 Table 8.43 Gap gapStart

Spec: §8.3.8.4, p. 60, Table 8.43 — “gapStart: SequenceNumber — Identifies the first sequence number in the interval of sequence numbers corresponding to the set of not-available changes.”

Repo: crates/rtps/src/submessages.rs (GapSubmessage::gap_start)

Tests: crates/rtps/src/reliable_reader.rs::tests::gap_before_any_heartbeat_lets_the_next_data_through

Status: done

§8.3.8.4 Table 8.43 Gap gapList

Spec: §8.3.8.4, p. 60, Table 8.43 — “gapList: SequenceNumberSet — … (1) Identifies the last sequence number in the interval … (2) Identifies an additional list of sequence numbers corresponding to not-available changes.”

Repo: crates/rtps/src/submessages.rs (GapSubmessage::gap_list); crates/rtps/src/reliable_reader.rs (handle_gap)

Tests: crates/rtps/src/reliable_reader.rs::tests::gap_after_the_held_data_releases_it, crates/rtps/src/reliable_writer.rs::tests::tick_resends_evicted_request_as_gap

Status: done

§8.3.8.4 Table 8.43 Gap gapStartGSN

Spec: §8.3.8.4, p. 60, Table 8.43 — “gapStartGSN: SequenceNumber — Present only if the GroupInfoFlag is set in the header.”

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::gap_with_group_info_roundtrip_be, crates/rtps/src/submessages.rs::tests::gap_decode_rejects_invalid_group_sequence_numbers, crates/rtps/src/submessages.rs::tests::a_gap_end_gsn_one_below_its_start_is_an_empty_range_and_valid, crates/rtps/src/submessages.rs::tests::the_gap_flags_are_those_of_9_4_5_6

Status: done

§8.3.8.4 Table 8.43 Gap gapEndGSN

Spec: §8.3.8.4, p. 60, Table 8.43 — “gapEndGSN: SequenceNumber — Present only if the GroupInfoFlag is set in the header. … It shall be greater than or equal to the group sequence number corresponding to the sample identified by gapList.bitmapBase.”

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::gap_with_group_info_roundtrip_be, crates/rtps/src/submessages.rs::tests::gap_decode_rejects_invalid_group_sequence_numbers, crates/rtps/src/submessages.rs::tests::a_gap_end_gsn_one_below_its_start_is_an_empty_range_and_valid, crates/rtps/src/submessages.rs::tests::the_gap_flags_are_those_of_9_4_5_6

Status: done

§8.3.8.4 Table 8.43 Gap filteredCount

Spec: §8.3.8.4, p. 60, Table 8.43 — “filteredCount: ChangeCount — Present only if the FilteredCountFlag is set in the header. Indicates the number of changes corresponding to the set of sequence numbers in the Gap that are still present in the Writer cache but are being filtered for the RTPS Reader.”

Repo: crates/rtps/src/submessages.rs (GapSubmessage::filtered_count)

Tests: crates/rtps/src/submessages.rs::tests::gap_filtered_count_is_eight_octets_high_then_low, crates/rtps/src/submessages.rs::tests::gap_with_filtered_count_roundtrip_le

Status: done

§8.3.8.4 Gap invalid: submessageLength too small

Spec: §8.3.8.4, p. 60 — “submessageLength in the Submessage header is too small.”

Repo: crates/rtps/src/submessages.rs (GapSubmessage::read_body)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — the shortening is recognised; the submessage is invalid and the rest of the message with it, the submessages before it stand (ParsedDatagram::invalid_rest, counted).

§8.3.8.4 Gap invalid: gapStart ≤ 0

Spec: §8.3.8.4, p. 60 — “gapStart is zero or negative.”

Repo: crates/rtps/src/submessages.rs (GapSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::validity_tests::gap_and_sequence_number_set_validity_rules

Status: done — a gapStart below 1 is refused.

§8.3.8.4 Gap invalid: invalid gapList

Spec: §8.3.8.4, p. 60 — “gapList is invalid (as defined in 8.3.5.5).”

Repo: crates/rtps/src/submessages.rs (SequenceNumberSet::read_from)

Tests: crates/rtps/src/submessages.rs::validity_tests::gap_and_sequence_number_set_validity_rules, crates/rtps/src/submessages.rs::tests::seqnumset_rejects_num_bits_above_256

Status: done — numBits > 256 and bitmapBase < 1 are refused.

§8.3.8.4 Gap invalid: group fields

Spec: §8.3.8.4, p. 60 — “If GroupInfoFlag is set and: gapStartGSN.value is zero or negative; gapEndGSN.value is zero or negative; gapEndGSN.value < gapStartGSN.value-1”.

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::gap_decode_rejects_invalid_group_sequence_numbers, crates/rtps/src/submessages.rs::tests::gap_decode_rejects_truncated_group_info

Status: done

§8.3.8.4 Gap::sequence_number_set

Spec: §8.3.8.4, pp. 60–61 — “1. All sequence numbers in the range gapStart <= sequence_number <= gapList.base -1; 2. All the sequence numbers that appear explicitly listed in the gapList.”

Repo: crates/rtps/src/reliable_reader.rs (handle_gap)

Tests: crates/rtps/src/reliable_reader.rs::tests::gap_after_the_held_data_releases_it, crates/rtps/src/reliable_reader.rs::tests::a_best_effort_reader_counts_the_samples_a_gap_lost

Status: done

§8.3.8.4 Gap: writerGUID = {sourceGuidPrefix, writerId}

Spec: §8.3.8.4, p. 61 — “writerGUID = { Receiver.sourceGuidPrefix, Gap.writerId }”.

Repo: crates/rtps/src/reliable_reader.rs (handle_gap: proxy_index_by_writer(Guid::new(source_prefix, gap.writer_id)))

Tests: crates/rtps/src/reliable_reader.rs::tests::gap_after_the_held_data_releases_it

Status: done

§8.3.8.4 Gap: readerGUID = {destGuidPrefix, readerId}

Spec: §8.3.8.4, p. 61 — “readerGUID = { Receiver.destGuidPrefix, Gap.readerId }”.

Repo: crates/dcps/src/runtime.rs (handle_user_datagram_from)

Tests: crates/dcps/src/runtime.rs::tests::the_submessages_after_an_info_destination_for_another_participant_are_not_ours

Status: done

§8.3.8.4 Gap: content of the GroupInfoFlag

Spec: §8.3.8.4, p. 61 — “The Writer sets the GroupInfoFlag to indicate the presence of the gapStartGSN and gapEndGSN elements. … The gapEndGSN can extend past the Group Sequence Number that corresponds to gapList.bitmapBase”.

Repo: crates/rtps/src/reliable_writer.rs (gap_group_info, note_gsn, GapGroupInfo); crates/rtps/src/submessages.rs; crates/dcps/src/runtime.rs (note_writer_group_progress)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_gap_of_a_group_writer_carries_the_group_sequence_numbers, crates/rtps/src/submessages.rs::tests::gap_with_group_info_roundtrip_be, crates/dcps/src/group_order.rs::tests::a_gap_rules_the_number_out_for_its_writer

Status: done — the writer of a GROUP publisher sends GAPs with the GroupInfoFlag set: gapStartGSN is the group sequence number of the change taken away, gapEndGSN the same (a range of one number; valid under §8.3.8.4); the number comes from the cache or from a bounded list (4096) for changes that left the cache. A writer outside a group sends no flag. The reader takes both numbers into the commit rule (DcpsRuntime::note_writer_group_progress).

§8.3.8.4 Gap: content of filteredCount

Spec: §8.3.8.4, p. 61 — “The filteredCount, if present, shall include: Changes filtered due to the writer-side application of a content-filtered-topic … a time filter … Changes that are written in ways that intend to exclude delivery to the Reader. … The filteredCount shall not include changes that are no longer in the RTPS Writer HistoryCache”.

Repo: —

Tests: —

Status: open — part of the optional filtering on the writer side (§8.7.3), which ZeroDDS does not perform. The Gap codec knows the field (GAP_FLAG_FILTERED_COUNT), append_gap sets filtered_count: None.

§8.3.8.5 HeaderExtension

Spec: §8.3.8.5, p. 61 — “This submessage is logically part of the header and it is defined in 8.3.7.”

Repo: —

Tests: —

Status: n/a (informative) — reference; items under §8.3.7.

§8.3.8.6 Heartbeat: Purpose

Spec: §8.3.8.6, p. 61 — “This message is sent from an RTPS Writer to an RTPS Reader to communicate the sequence numbers of changes that the Writer has available.”

Repo: —

Tests: —

Status: n/a (informative) — statement of purpose.

§8.3.8.6 Table 8.44 Heartbeat EndiannessFlag

Spec: §8.3.8.6, p. 62, Table 8.44 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/submessages.rs (HeartbeatSubmessage::write_body, HeartbeatSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_submessage_roundtrip_le, crates/rtps/tests/cyclone_compliance.rs::cyclone_heartbeat_decodes

Status: done

§8.3.8.6 Table 8.44 Heartbeat FinalFlag

Spec: §8.3.8.6, p. 62, Table 8.44 — “FinalFlag … Indicates whether the Reader is required to respond to the Heartbeat or if it is just an advisory heartbeat.”

Repo: crates/rtps/src/submessages.rs (HEARTBEAT_FLAG_FINAL, HeartbeatSubmessage::final_flag)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_submessage_no_final_flag_when_disabled, crates/rtps/src/reliable_writer.rs::tests::periodic_heartbeat_has_final_flag_unset

Status: done

§8.3.8.6 Table 8.44 Heartbeat LivelinessFlag

Spec: §8.3.8.6, p. 62, Table 8.44 — “LivelinessFlag … Indicates that the DDS DataWriter associated with the RTPS Writer of the message has manually asserted its LIVELINESS.”

Repo: crates/rtps/src/submessages.rs (HEARTBEAT_FLAG_LIVELINESS); crates/rtps/src/reliable_writer.rs (ReliableWriter::liveliness_heartbeat)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_submessage_liveliness_flag_roundtrip, crates/rtps/src/reliable_writer.rs::tests::liveliness_heartbeat_is_a_final_heartbeat_with_the_liveliness_flag

Status: done

§8.3.8.6 Table 8.44 Heartbeat GroupInfoFlag

Spec: §8.3.8.6, p. 62, Table 8.44 — “GroupInfoFlag … Indicates the presence of additional information about the group of writers (Writer Group) the sender belongs to.”

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::the_group_info_is_the_three_sequence_numbers_of_9_4_5_7, crates/rtps/src/submessages.rs::tests::heartbeat_with_group_info_roundtrip_le, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_heartbeat_carries_the_groups_numbers

Status: done

§8.3.8.6 Table 8.44 Heartbeat readerId

Spec: §8.3.8.6, p. 62, Table 8.44 — “readerId … Can be set to ENTITYID_UNKNOWN to indicate all readers for the writer that sent the message.”

Repo: crates/rtps/src/submessages.rs (HeartbeatSubmessage::reader_id); crates/dcps/src/runtime.rs (handle_user_datagram_from: fan-out on EntityId::UNKNOWN)

Tests: crates/rtps/src/reliable_reader.rs::tests::final_heartbeat_from_unknown_to_data_writer_requests_the_missing_sn

Status: done

§8.3.8.6 Table 8.44 Heartbeat writerId

Spec: §8.3.8.6, p. 62, Table 8.44 — “writerId: EntityId — Identifies the Writer Entity to which the range of sequence numbers applies.”

Repo: crates/rtps/src/submessages.rs (HeartbeatSubmessage::writer_id)

Tests: crates/rtps/src/reliable_reader.rs::tests::unknown_writer_id_in_heartbeat_counts_not_crashes

Status: done

§8.3.8.6 Table 8.44 Heartbeat firstSN

Spec: §8.3.8.6, p. 62, Table 8.44 — “If samples are available in the Writer, identifies the first (lowest) sequence number that is available in the Writer. If no samples are available in the Writer, identifies the lowest sequence number that is yet to be written by the Writer.”

Repo: crates/rtps/src/reliable_writer.rs (append_heartbeat)

Tests: crates/rtps/src/reliable_writer.rs::tests::heartbeat_carries_cache_range, crates/rtps/src/reliable_writer.rs::tests::a_heartbeat_after_the_cache_emptied_announces_the_last_sn_written

Status: done

§8.3.8.6 Table 8.44 Heartbeat lastSN

Spec: §8.3.8.6, p. 62, Table 8.44 — “lastSN: SequenceNumber — Identifies the last (highest) sequence number that the Writer has ever written.”

Repo: crates/rtps/src/reliable_writer.rs (append_heartbeat: last_written_sn)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_heartbeat_after_the_cache_emptied_announces_the_last_sn_written

Status: done

§8.3.8.6 Table 8.44 Heartbeat count

Spec: §8.3.8.6, p. 62, Table 8.44 — “count: Count — A counter that is incremented each time a new Heartbeat message is sent.”

Repo: crates/rtps/src/reliable_writer.rs (append_heartbeat: heartbeat_count.wrapping_add(1))

Tests: crates/rtps/src/reliable_writer.rs::tests::heartbeat_count_increments

Status: done

§8.3.8.6 Table 8.44 Heartbeat currentGSN

Spec: §8.3.8.6, p. 62, Table 8.44 — “currentGSN … Identifies the last (highest) group sequence number written by any DataWriter in the Writer’s Group at the time that the HeartBeat was sent.”

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::the_group_info_is_the_three_sequence_numbers_of_9_4_5_7, crates/rtps/src/submessages.rs::tests::heartbeat_with_group_info_roundtrip_le, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_heartbeat_carries_the_groups_numbers

Status: done

§8.3.8.6 Table 8.44 Heartbeat firstGSN

Spec: §8.3.8.6, p. 62, Table 8.44 — “firstGSN … Identifies the group sequence number corresponding to the sample identified by sequence number firstSN.”

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::the_group_info_is_the_three_sequence_numbers_of_9_4_5_7, crates/rtps/src/submessages.rs::tests::heartbeat_with_group_info_roundtrip_le, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_heartbeat_carries_the_groups_numbers

Status: done

§8.3.8.6 Table 8.44 Heartbeat lastGSN

Spec: §8.3.8.6, p. 62, Table 8.44 — “lastGSN … Identifies the group sequence number corresponding to the sample identified by sequence number lastSN.”

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::the_group_info_is_the_three_sequence_numbers_of_9_4_5_7, crates/rtps/src/submessages.rs::tests::heartbeat_with_group_info_roundtrip_le, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_heartbeat_carries_the_groups_numbers

Status: done

§8.3.8.6 Table 8.44 Heartbeat writerSet

Spec: §8.3.8.6, p. 62, Table 8.44 — “writerSet: GroupDigest … Identifies the subset of Writers that belong to the Writer’s Group at the time the sample with currentGSN was written.”

Repo: crates/rtps/src/submessages.rs (HeartbeatGroupInfo, HeartbeatSubmessage::write_body, read_body); crates/rtps/src/dialect.rs (HeartbeatGroupDigests); crates/rtps/src/reliable_writer.rs (heartbeat_group_info); crates/dcps/src/group_order.rs; wire.omit_heartbeat_group_digests

Tests: crates/rtps/src/submessages.rs::tests::the_group_digests_follow_last_gsn_and_are_optional_on_read, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_heartbeat_carries_the_writer_sets_unless_the_peer_omits_them, crates/dcps/src/group_order.rs::tests::a_heartbeat_whose_writer_sets_are_not_the_discovered_ones_keeps_the_number_open, crates/dcps/tests/runtime_config_layering.rs::the_heartbeat_digest_and_keyless_lifecycle_settings_are_read_from_yaml

Status: done — with G=1 the writer sends writerSet after lastGSN as a GroupDigest (four octets, §9.4.2.19; the first four octets of the MD5 over the EntityIdSet_t, sorted, §9.3.2.5; empty group: zero). The reader reads both when the submessageLength leaves room and accepts their absence (figure of §9.4.5.7); the commit rule of §8.7.5 compares them with the discovered writers. wire.omit_heartbeat_group_digests leaves them out on send. Contradiction PIM/PSM: see “Contradictions within the spec”.

§8.3.8.6 Table 8.44 Heartbeat secureWriterSet

Spec: §8.3.8.6, p. 62, Table 8.44 — “secureWriterSet: GroupDigest … Reserved for use by the DDS-Security Specification.”

Repo: crates/rtps/src/submessages.rs (HeartbeatGroupInfo, HeartbeatSubmessage::write_body, read_body); crates/rtps/src/dialect.rs (HeartbeatGroupDigests); crates/rtps/src/reliable_writer.rs (heartbeat_group_info); crates/dcps/src/group_order.rs; wire.omit_heartbeat_group_digests

Tests: crates/rtps/src/submessages.rs::tests::the_group_digests_follow_last_gsn_and_are_optional_on_read, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_heartbeat_carries_the_writer_sets_unless_the_peer_omits_them, crates/dcps/src/group_order.rs::tests::a_heartbeat_whose_writer_sets_are_not_the_discovered_ones_keeps_the_number_open, crates/dcps/tests/runtime_config_layering.rs::the_heartbeat_digest_and_keyless_lifecycle_settings_are_read_from_yaml

Status: done — with G=1 the writer sends secureWriterSet after lastGSN as a GroupDigest (four octets, §9.4.2.19; the first four octets of the MD5 over the EntityIdSet_t, sorted, §9.3.2.5; empty group: zero; secureWriterSet is reserved for DDS-Security and is sent as zero). The reader reads both when the submessageLength leaves room and accepts their absence (figure of §9.4.5.7); the commit rule of §8.7.5 compares them with the discovered writers. wire.omit_heartbeat_group_digests leaves them out on send. Contradiction PIM/PSM: see “Contradictions within the spec”.

§8.3.8.6 Heartbeat example 1: never written

Spec: §8.3.8.6, p. 63 — “A Writer that has never written any samples before sending a Heartbeat will send a Heartbeat with firstSN.value = 1, lastSN.value = 0.”

Repo: crates/rtps/src/reliable_writer.rs (append_heartbeat)

Tests: crates/rtps/src/reliable_writer.rs::tests::an_empty_writer_heartbeats_a_reader_until_it_answers

Status: done

§8.3.8.6 Heartbeat example 2: one sample in the cache

Spec: §8.3.8.6, p. 63 — “A Writer that has only one sample in its cache with sequence number SN will send a Heartbeat with firstSN.value = lastSN.value = SN.”

Repo: crates/rtps/src/reliable_writer.rs (append_heartbeat)

Tests: crates/rtps/src/reliable_writer.rs::tests::heartbeat_carries_cache_range

Status: done

§8.3.8.6 Heartbeat example 3: part of the history in the cache

Spec: §8.3.8.6, p. 63 — “A Writer that has written 10 samples and still has the last 5 samples in its cache will send a Heartbeat with firstSN.value = 6, lastSN.value = 10.”

Repo: crates/rtps/src/reliable_writer.rs (append_heartbeat)

Tests: crates/rtps/src/reliable_writer.rs::tests::keep_last_evicts_oldest_on_overflow

Status: done

§8.3.8.6 Heartbeat example 4: cache empty after writing

Spec: §8.3.8.6, p. 63 — “A Writer that has written 10 samples before sending a Heartbeat but does not have any samples available at the time of the Heartbeat will send a Heartbeat with firstSN.value = 11, lastSN.value = 10.”

Repo: crates/rtps/src/reliable_writer.rs (append_heartbeat: first_sn.min(last + 1))

Tests: crates/rtps/src/reliable_writer.rs::tests::a_heartbeat_after_the_cache_emptied_announces_the_last_sn_written

Status: done

§8.3.8.6 Heartbeat invalid: submessageLength too small

Spec: §8.3.8.6, p. 63 — “submessageLength in the Submessage header is too small”.

Repo: crates/rtps/src/submessages.rs (HeartbeatSubmessage::read_body)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — the shortening is recognised; the submessage is invalid and the rest of the message with it, the submessages before it stand (ParsedDatagram::invalid_rest, counted).

§8.3.8.6 Heartbeat invalid: firstSN ≤ 0

Spec: §8.3.8.6, p. 63 — “firstSN.value is zero or negative”.

Repo: crates/rtps/src/submessages.rs (HeartbeatSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::validity_tests::heartbeat_validity_rules

Status: done — a firstSN below 1 is refused.

§8.3.8.6 Heartbeat invalid: lastSN < 0

Spec: §8.3.8.6, p. 63 — “lastSN.value is negative”.

Repo: crates/rtps/src/submessages.rs (HeartbeatSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::validity_tests::heartbeat_validity_rules

Status: done — a negative lastSN is refused.

§8.3.8.6 Heartbeat invalid: lastSN < firstSN − 1

Spec: §8.3.8.6, p. 63 — “lastSN.value < firstSN.value - 1”.

Repo: crates/rtps/src/submessages.rs (HeartbeatSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::validity_tests::heartbeat_validity_rules

Status: done — lastSN < firstSN - 1 is refused; lastSN = firstSN - 1 (empty history) is valid.

§8.3.8.6 Heartbeat invalid: group fields

Spec: §8.3.8.6, p. 63 — six conditions for currentGSN, firstGSN and lastGSN when the GroupInfoFlag is set.

Repo: crates/rtps/src/submessages.rs (HeartbeatSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_decode_rejects_invalid_group_sequence_numbers, crates/rtps/src/submessages.rs::tests::a_current_gsn_past_the_writers_last_is_accepted, crates/rtps/src/submessages.rs::tests::heartbeat_decode_rejects_truncated_group_info

Status: done — five of the six conditions are checked. The sixth, currentGSN > lastGSN, contradicts the definition of currentGSN (pp. 62–63: the number of the sample written last, which lastGSN may not include yet) and is not applied; the test a_current_gsn_past_the_writers_last_is_accepted holds that. The reading chosen is under “Contradictions within the spec”. Cyclone DDS, Fast DDS and OpenDDS send no group HEARTBEATs; expected: no effect.

§8.3.8.6 Heartbeat: report availability

Spec: §8.3.8.6, p. 63 — “It informs the Reader of the sequence numbers that are available in the writer’s HistoryCache so that the Reader may request (using an AckNack) any that it has missed.”

Repo: crates/rtps/src/reliable_reader.rs (handle_heartbeat: update_from_heartbeat); crates/rtps/src/writer_proxy.rs

Tests: crates/rtps/src/writer_proxy.rs::tests::heartbeat_sets_available_range, crates/rtps/src/reliable_reader.rs::tests::heartbeat_with_missing_triggers_acknack_after_delay

Status: done

§8.3.8.6 Heartbeat without FinalFlag requires an AckNack

Spec: §8.3.8.6, p. 63 — “if the FinalFlag is not set, then the Reader must send an AckNack message indicating which CacheChange changes it has received, even if the AckNack indicates it has received all CacheChange changes in the writer’s HistoryCache.”

Repo: crates/rtps/src/reliable_reader.rs (handle_heartbeat, tick_outbound)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_heartbeat_without_the_final_flag_is_answered_when_everything_is_received

Status: done — a HEARTBEAT without the FinalFlag triggers an ACKNACK even when everything is received (bitmapBase behind the last number, nothing missing), with and without the LivelinessFlag.

§8.3.8.6 Heartbeat LivelinessFlag renews the manual lease

Spec: §8.3.8.6, p. 63 — “The RTPS Reader should therefore renew the manual liveliness lease of the corresponding remote DDS DataWriter.”

Repo: crates/dcps/src/runtime.rs (handle_user_datagram_from: liveliness.writer_asserted on h.liveliness_flag)

Tests: crates/dcps/tests/liveliness_qos.rs::linux::assert_liveliness_keeps_a_manual_writer_alive_at_a_remote_reader

Status: done

§8.3.8.6 Heartbeat: content of the GroupInfoFlag

Spec: §8.3.8.6, p. 64 — “The Writer sets the GroupInfoFlag to indicate the presence of the currentGSN, firstGSN, lastGSN, writerSet, and secureWriterSet elements.”

Repo: crates/rtps/src/submessages.rs; crates/rtps/src/reliable_writer.rs (heartbeat_group_info)

Tests: crates/rtps/src/submessages.rs::tests::the_group_digests_follow_last_gsn_and_are_optional_on_read, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_heartbeat_carries_the_writer_sets_unless_the_peer_omits_them, crates/dcps/src/group_order.rs::tests::a_heartbeat_whose_writer_sets_are_not_the_discovered_ones_keeps_the_number_open, crates/dcps/tests/runtime_config_layering.rs::the_heartbeat_digest_and_keyless_lifecycle_settings_are_read_from_yaml, crates/rtps/src/submessages.rs::tests::heartbeat_with_group_info_roundtrip_le, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_heartbeat_carries_the_groups_numbers

Status: done — currentGSN, firstGSN, lastGSN, writerSet and secureWriterSet are sent and read (see the writerSet and secureWriterSet items).

§8.3.8.6 Heartbeat: writerGUID = {sourceGuidPrefix, writerId}

Spec: §8.3.8.6, p. 64 — “writerGUID = { Receiver.sourceGuidPrefix, Heartbeat.writerId }”.

Repo: crates/rtps/src/reliable_reader.rs (handle_heartbeat)

Tests: crates/rtps/src/reliable_reader.rs::tests::same_entity_id_different_prefix_not_confused

Status: done

§8.3.8.6 Heartbeat: readerGUID = {destGuidPrefix, readerId}

Spec: §8.3.8.6, p. 64 — “readerGUID = { Receiver.destGuidPrefix, Heartbeat.readerId }. The Heartbeat.readerId can be ENTITYID_UNKNOWN, in which case the Heartbeat applies to all Readers of that writerGUID within the Participant.”

Repo: crates/dcps/src/runtime.rs (handle_user_datagram_from)

Tests: crates/dcps/src/runtime.rs::tests::the_submessages_after_an_info_destination_for_another_participant_are_not_ours

Status: done

§8.3.8.7 HeartbeatFrag: Purpose

Spec: §8.3.8.7, p. 64 — “When fragmenting data and until all fragments are available, the HeartbeatFrag Submessage is sent from an RTPS Writer to an RTPS Reader to communicate which fragments the Writer has available.”

Repo: —

Tests: —

Status: n/a (informative) — statement of purpose; ZeroDDS sends a sample only once all its fragments are available.

§8.3.8.7 Table 8.45 HeartbeatFrag EndiannessFlag

Spec: §8.3.8.7, p. 64, Table 8.45 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/submessages.rs (HeartbeatFragSubmessage::write_body, HeartbeatFragSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_frag_roundtrip_be

Status: done

§8.3.8.7 Table 8.45 HeartbeatFrag readerId

Spec: §8.3.8.7, p. 64, Table 8.45 — “readerId … Can be set to ENTITYID_UNKNOWN to indicate all readers for the writer that sent the message.”

Repo: crates/rtps/src/submessages.rs (HeartbeatFragSubmessage::reader_id)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_frag_roundtrip_le

Status: done

§8.3.8.7 Table 8.45 HeartbeatFrag writerId

Spec: §8.3.8.7, p. 64, Table 8.45 — “writerId: EntityId — Identifies the Writer Entity that sent the Submessage.”

Repo: crates/rtps/src/submessages.rs (HeartbeatFragSubmessage::writer_id)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_frag_roundtrip_le

Status: done

§8.3.8.7 Table 8.45 HeartbeatFrag writerSN

Spec: §8.3.8.7, p. 64, Table 8.45 — “writerSN: SequenceNumber — Identifies the sequence number of the data change for which fragments are available.”

Repo: crates/rtps/src/submessages.rs (HeartbeatFragSubmessage::writer_sn)

Tests: crates/rtps/src/datagram.rs::tests::decode_heartbeat_frag_roundtrip

Status: done

§8.3.8.7 Table 8.45 HeartbeatFrag lastFragmentNum

Spec: §8.3.8.7, p. 64, Table 8.45 — “lastFragmentNum: FragmentNumber — All fragments up to and including this last (highest) fragment are available on the Writer for the change identified by writerSN.”

Repo: crates/rtps/src/submessages.rs (HeartbeatFragSubmessage::last_fragment_num)

Tests: crates/rtps/src/datagram.rs::tests::decode_heartbeat_frag_roundtrip

Status: done

§8.3.8.7 Table 8.45 HeartbeatFrag count

Spec: §8.3.8.7, p. 64, Table 8.45 — “count: Count — A counter that is incremented each time a new HeartbeatFrag message is sent.”

Repo: crates/rtps/src/submessages.rs (HeartbeatFragSubmessage::count)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_frag_roundtrip_le

Status: done — ZeroDDS sends no HEARTBEAT_FRAG; the field is encoded and read.

§8.3.8.7 HeartbeatFrag invalid: submessageLength too small

Spec: §8.3.8.7, p. 64 — “submessageLength in the Submessage header is too small”.

Repo: crates/rtps/src/submessages.rs (HeartbeatFragSubmessage::read_body)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — the shortening is recognised; the submessage is invalid and the rest of the message with it, the submessages before it stand (ParsedDatagram::invalid_rest, counted).

§8.3.8.7 HeartbeatFrag invalid: writerSN ≤ 0

Spec: §8.3.8.7, p. 64 — “writerSN.value is zero or negative”.

Repo: crates/rtps/src/submessages.rs (HeartbeatFragSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::validity_tests::fragment_submessages_validity_rules, crates/rtps/src/reliable_reader.rs::tests::a_heartbeat_frag_is_answered_when_an_available_fragment_is_missing

Status: done — a writerSN below 1 is refused.

§8.3.8.7 HeartbeatFrag invalid: lastFragmentNum ≤ 0

Spec: §8.3.8.7, p. 64 — “lastFragmentNum.value is zero or negative”.

Repo: crates/rtps/src/submessages.rs (HeartbeatFragSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::validity_tests::fragment_submessages_validity_rules, crates/rtps/src/reliable_reader.rs::tests::a_heartbeat_frag_is_answered_when_an_available_fragment_is_missing

Status: done — a lastFragmentNum below 1 is refused.

§8.3.8.7 HeartbeatFrag: the reader answers with a NackFrag

Spec: §8.3.8.7, p. 65 — “The RTPS Reader will respond by sending a NackFrag message, but only if it is missing any of the available fragments.”

Repo: crates/rtps/src/reliable_reader.rs (ReliableReader::handle_heartbeat_frag), crates/dcps/src/runtime.rs (handle_user_datagram_from)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_heartbeat_frag_is_answered_when_an_available_fragment_is_missing

Status: done

§8.3.8.7 HeartbeatFrag: writerGUID/readerGUID

Spec: §8.3.8.7, p. 65 — “writerGUID = { Receiver.sourceGuidPrefix, HeartbeatFrag.writerId } … readerGUID = { Receiver.destGuidPrefix, HeartbeatFrag.readerId } … can be ENTITYID_UNKNOWN”.

Repo: crates/dcps/src/runtime.rs (handle_user_datagram_from: readerId or ENTITYID_UNKNOWN), crates/rtps/src/reliable_reader.rs (proxy_index_by_writer)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_heartbeat_frag_is_answered_when_an_available_fragment_is_missing

Status: done

§8.3.8.8 InfoDestination: Purpose

Spec: §8.3.8.8, p. 65 — “This message is sent from an RTPS Writer to an RTPS Reader to modify the GuidPrefix used to interpret the Reader entityIds appearing in the Submessages that follow it.”

Repo: —

Tests: —

Status: n/a (informative) — statement of purpose.

§8.3.8.8 Table 8.46 InfoDestination EndiannessFlag

Spec: §8.3.8.8, p. 65, Table 8.46 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/datagram.rs (decode_datagram, encode_datagram for InfoDestination)

Tests: crates/rtps/src/datagram.rs::tests::info_dst_decodes_to_typed_destination_prefix

Status: done

§8.3.8.8 Table 8.46 InfoDestination guidPrefix

Spec: §8.3.8.8, p. 65, Table 8.46 — “guidPrefix: GuidPrefix — Provides the GuidPrefix that should be used to reconstruct the GUIDs of all the RTPS Reader entities whose EntityIds appears in the Submessages that follow.”

Repo: crates/rtps/src/datagram.rs (ParsedSubmessage::InfoDestination); crates/rtps/src/reliable_reader.rs (wrap_to_writer sends INFO_DST before ACKNACK/NACK_FRAG)

Tests: crates/rtps/src/datagram.rs::tests::info_dst_body_of_exactly_twelve_decodes, crates/rtps/src/reliable_reader.rs::tests::pre_emptive_acknack_carries_info_dst, crates/rtps/src/reliable_writer.rs::tests::every_proxy_directed_datagram_carries_info_dst_not_just_the_heartbeat_path

Status: done

§8.3.8.8 InfoDestination invalid: submessageLength too small

Spec: §8.3.8.8, p. 65 — “submessageLength in the Submessage header is too small.”

Repo: crates/rtps/src/datagram.rs (decode_datagram, InfoDestination)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — the shortening is recognised; the submessage is invalid and the rest of the message with it, the submessages before it stand (ParsedDatagram::invalid_rest, counted).

§8.3.8.8 InfoDestination: destGuidPrefix = guidPrefix

Spec: §8.3.8.8, p. 65 — “if (InfoDestination.guidPrefix != GUIDPREFIX_UNKNOWN) { Receiver.destGuidPrefix = InfoDestination.guidPrefix }”.

Repo: crates/rtps/src/datagram.rs (ReceiverWalk::next)

Tests: crates/rtps/src/datagram.rs::tests::receiver_walk_info_source_does_not_reset_dest_guid_prefix

Status: done

§8.3.8.8 InfoDestination: GUIDPREFIX_UNKNOWN sets the own prefix

Spec: §8.3.8.8, p. 65 — “else { Receiver.destGuidPrefix = }”.

Repo: crates/rtps/src/datagram.rs (ReceiverWalk::next, InfoDestination)

Tests: crates/dcps/src/runtime.rs::tests::the_submessages_after_an_info_destination_for_another_participant_are_not_ours

Status: done

§8.3.8.8 destGuidPrefix on the user-data path

Spec: §8.3.8.2, p. 56 — “readerGUID = { Receiver.destGuidPrefix, Data.readerId }”; likewise §8.3.8.4, p. 61 (Gap), §8.3.8.6, p. 64 (Heartbeat), §8.3.8.7, p. 65 (HeartbeatFrag); §8.3.8.3, p. 58 — “the interpretation of the DataFrag Submessages is identical to that of the Data Submessage”; §8.3.8.1, p. 54 — “writerGUID = { Receiver.destGuidPrefix, AckNack.writerId }”; likewise §8.3.8.12, p. 69 (NackFrag).

Repo: —

Tests: crates/dcps/src/runtime.rs::tests::the_submessages_after_an_info_destination_for_another_participant_are_not_ours

Status: done

§8.3.8.9 InfoReply: Purpose

Spec: §8.3.8.9, p. 66 — “It contains explicit information on where to send a reply to the Submessages that follow it within the same message.”

Repo: —

Tests: —

Status: n/a (informative) — statement of purpose.

§8.3.8.9 Table 8.47 InfoReply EndiannessFlag

Spec: §8.3.8.9, p. 66, Table 8.47 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/submessages.rs (InfoReplySubmessage::write_body, InfoReplySubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::tests::info_reply_with_multicast_roundtrip_be

Status: done

§8.3.8.9 Table 8.47 InfoReply MulticastFlag

Spec: §8.3.8.9, p. 66, Table 8.47 — “MulticastFlag … Indicates whether the Submessage also contains a multicast address.”

Repo: crates/rtps/src/submessages.rs (INFO_REPLY_FLAG_MULTICAST)

Tests: crates/rtps/src/submessages.rs::tests::info_reply_with_multicast_roundtrip_le, crates/rtps/src/submessages.rs::tests::info_reply_unicast_only_roundtrip_le

Status: done

§8.3.8.9 Table 8.47 InfoReply unicastLocatorList

Spec: §8.3.8.9, p. 66, Table 8.47 — “unicastLocatorList: LocatorList — Indicates an alternative set of unicast addresses that the Writer should use to reach the Readers when replying to the Submessages that follow.”

Repo: crates/rtps/src/submessages.rs (InfoReplySubmessage::unicast_locators)

Tests: crates/rtps/src/submessages.rs::tests::info_reply_empty_unicast_list_is_valid, crates/rtps/src/submessages.rs::tests::info_reply_unicast_only_roundtrip_le

Status: done — whether a writer uses the list when replying is listed under §8.4.

§8.3.8.9 Table 8.47 InfoReply multicastLocatorList

Spec: §8.3.8.9, p. 66, Table 8.47 — “multicastLocatorList … Only present when the MulticastFlag is set.”

Repo: crates/rtps/src/submessages.rs (InfoReplySubmessage::multicast_locators)

Tests: crates/rtps/src/submessages.rs::tests::info_reply_with_multicast_roundtrip_le

Status: done

§8.3.8.9 InfoReply invalid: submessageLength too small

Spec: §8.3.8.9, p. 66 — “submessageLength in the Submessage header is too small.”

Repo: crates/rtps/src/submessages.rs (InfoReplySubmessage::read_body)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest, crates/rtps/src/submessages.rs::validity_tests::an_info_reply_locator_of_an_unknown_kind_is_left_out_and_counted

Status: done — the shortening is recognised; the submessage is invalid and the rest of the message with it, the submessages before it stand. A locator of an unknown kind in the list does not make the submessage invalid (§9.3.2.4: vendor kinds): it is left out and counted (skipped_unknown_locators), the others stand.

§8.3.8.9 InfoReply: Receiver.unicastReplyLocatorList

Spec: §8.3.8.9, p. 66 — “Receiver.unicastReplyLocatorList = InfoReply.unicastLocatorList”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_info_reply)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_info_reply_sets_locators, crates/rtps/src/datagram.rs::tests::receiver_walk_info_reply_sets_reply_locators

Status: done

§8.3.8.9 InfoReply: Receiver.multicastReplyLocatorList

Spec: §8.3.8.9, p. 66 — “if ( MulticastFlag ) { Receiver.multicastReplyLocatorList = InfoReply.multicastLocatorList } else { Receiver.multicastReplyLocatorList = }”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_info_reply)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_info_reply_sets_locators, crates/rtps/src/receiver_state.rs::tests::an_info_reply_without_the_multicast_flag_empties_the_multicast_list

Status: done — without the MulticastFlag the list is emptied.

§8.3.8.10 InfoSource: Purpose

Spec: §8.3.8.10, p. 66 — “This message modifies the logical source of the Submessages that follow.”

Repo: —

Tests: —

Status: n/a (informative) — statement of purpose.

§8.3.8.10 Table 8.48 InfoSource EndiannessFlag

Spec: §8.3.8.10, p. 67, Table 8.48 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/submessages.rs (InfoSourceSubmessage::write_body, InfoSourceSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::tests::info_source_roundtrip_be

Status: done

§8.3.8.10 Table 8.48 InfoSource protocolVersion

Spec: §8.3.8.10, p. 67, Table 8.48 — “protocolVersion: ProtocolVersion — Indicates the protocol used for subsequent Submessages.”

Repo: crates/rtps/src/submessages.rs (InfoSourceSubmessage::protocol_version)

Tests: crates/rtps/src/submessages.rs::tests::info_source_roundtrip_le

Status: done

§8.3.8.10 Table 8.48 InfoSource vendorId

Spec: §8.3.8.10, p. 67, Table 8.48 — “vendorId: VendorId — Indicates the VendorId of the vendor that originated the subsequent Submessages.”

Repo: crates/rtps/src/submessages.rs (InfoSourceSubmessage::vendor_id)

Tests: crates/rtps/src/submessages.rs::tests::info_source_roundtrip_le

Status: done

§8.3.8.10 Table 8.48 InfoSource guidPrefix

Spec: §8.3.8.10, p. 67, Table 8.48 — “guidPrefix: GuidPrefix — Identifies the Participant that is the container of the RTPS Writer entities that are the source of the Submessages that follow.”

Repo: crates/rtps/src/submessages.rs (InfoSourceSubmessage::guid_prefix)

Tests: crates/rtps/src/datagram.rs::tests::receiver_walk_attributes_submessages_after_info_source_to_the_new_prefix

Status: done

§8.3.8.10 InfoSource invalid: submessageLength too small

Spec: §8.3.8.10, p. 67 — “submessageLength in the Submessage header is too small.”

Repo: crates/rtps/src/submessages.rs (InfoSourceSubmessage::read_body)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — the shortening is recognised; the submessage is invalid and the rest of the message with it, the submessages before it stand (ParsedDatagram::invalid_rest, counted).

§8.3.8.10 InfoSource: sourceGuidPrefix, sourceVersion, sourceVendorId

Spec: §8.3.8.10, p. 67 — “Receiver.sourceGuidPrefix = InfoSource.guidPrefix; Receiver.sourceVersion = InfoSource.protocolVersion; Receiver.sourceVendorId = InfoSource.vendorId”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_info_source)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_info_source_resets_reply_locators_and_timestamp, crates/discovery/tests/opensplice_infosrc_regression.rs::opensplice_bundled_infosrc_datagrams_attribute_to_the_real_source

Status: done

§8.3.8.10 InfoSource: reply lists = {LOCATOR_INVALID}

Spec: §8.3.8.10, p. 67 — “Receiver.unicastReplyLocatorList = { LOCATOR_INVALID }; Receiver.multicastReplyLocatorList = { LOCATOR_INVALID }”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_info_source)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_info_source_resets_reply_locators_and_timestamp

Status: done — both lists are set to { LOCATOR_INVALID }.

§8.3.8.10 InfoSource: haveTimestamp = false

Spec: §8.3.8.10, p. 67 — “haveTimestamp = false”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_info_source)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_info_source_resets_reply_locators_and_timestamp

Status: done

§8.3.8.11 InfoTimestamp: Purpose

Spec: §8.3.8.11, p. 67 — “This Submessage is used to send a timestamp which applies to the Submessages that follow within the same message.”

Repo: —

Tests: —

Status: n/a (informative) — statement of purpose.

§8.3.8.11 Table 8.49 InfoTimestamp EndiannessFlag

Spec: §8.3.8.11, p. 67, Table 8.49 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/submessages.rs (InfoTimestampSubmessage::write_body, InfoTimestampSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::tests::info_timestamp_roundtrip_be

Status: done

§8.3.8.11 Table 8.49 InfoTimestamp InvalidateFlag

Spec: §8.3.8.11, p. 67, Table 8.49 — “InvalidateFlag … Indicates whether subsequent Submessages should be considered as having a timestamp or not.”

Repo: crates/rtps/src/submessages.rs (INFO_TIMESTAMP_FLAG_INVALIDATE, InfoTimestampSubmessage::invalidate)

Tests: crates/rtps/src/submessages.rs::tests::info_timestamp_invalidate_flag_yields_empty_body, crates/rtps/src/submessages.rs::tests::info_timestamp_decode_with_invalidate_ignores_body

Status: done

§8.3.8.11 Table 8.49 InfoTimestamp timestamp

Spec: §8.3.8.11, p. 67, Table 8.49 — “timestamp: Timestamp — Present only if the InvalidateFlag is not set in the header.”

Repo: crates/rtps/src/submessages.rs (InfoTimestampSubmessage::timestamp, InfoTimestampSubmessage::timestamp_body)

Tests: crates/rtps/src/submessages.rs::tests::info_timestamp_roundtrip_le, crates/rtps/src/reliable_writer.rs::tests::write_stamped_prepends_info_ts_before_data

Status: done

§8.3.8.11 InfoTimestamp invalid: submessageLength too small

Spec: §8.3.8.11, p. 68 — “submessageLength in the Submessage header is too small.”

Repo: crates/rtps/src/submessages.rs (InfoTimestampSubmessage::read_body)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — the shortening is recognised; the submessage is invalid and the rest of the message with it, the submessages before it stand (ParsedDatagram::invalid_rest, counted).

§8.3.8.11 InfoTimestamp: set haveTimestamp and timestamp

Spec: §8.3.8.11, p. 68 — “if ( !InfoTimestamp.InvalidateFlag ) { Receiver.haveTimestamp = true; Receiver.timestamp = InfoTimestamp.timestamp … } else { Receiver.haveTimestamp = false }”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_info_timestamp)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_info_timestamp_sets_value, crates/rtps/src/receiver_state.rs::tests::apply_info_timestamp_with_invalidate_clears, crates/rtps/src/datagram.rs::tests::receiver_walk_info_timestamp_invalidate_clears_have_timestamp

Status: done

§8.3.8.11 InfoTimestamp: correction on clockSkewDetected

Spec: §8.3.8.11, p. 68 — “if ( Receiver.clockSkewDetected ) { Receiver.timestamp += Receiver.rtpsReceptionTime - Receiver.rtpsSendTimestamp }”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::note_reception, note_clock_skew, apply_info_timestamp); crates/rtps/src/datagram.rs (ReceptionClock, ReceiveContext); crates/dcps/src/runtime.rs (receive_context, RuntimeConfig::clock_skew_threshold_s)

Tests: crates/rtps/src/receiver_state.rs::tests::the_reception_time_is_kept_and_checked_against_the_send_time, crates/rtps/src/receiver_state.rs::tests::an_info_timestamp_is_corrected_by_the_clock_skew, crates/rtps/src/datagram.rs::tests::the_walk_with_a_reception_clock_detects_a_skew_and_corrects_the_timestamp, crates/dcps/tests/runtime_config_layering.rs::the_clock_skew_threshold_is_a_setting_and_off_by_default

Status: done — with clockSkewDetected, apply_info_timestamp adds reception time minus send time; in every receive path this takes effect once wire.clock_skew_threshold_s is set (default off, see §8.3.7.4 TimestampFlag).

§8.3.8.11 InfoTimestamp: source timestamp of the following Data/DataFrag

Spec: §8.3.8.11, p. 68 — “The reception of the InfoTimestamp submessage sets the source timestamp associated with any subsequent Data and DataFrag submessages.”

Repo: crates/rtps/src/receiver_state.rs, crates/dcps/src/runtime.rs (handle_user_datagram_from)

Tests: crates/rtps/src/datagram.rs::tests::receiver_walk_info_timestamp_invalidate_clears_have_timestamp, crates/rtps/src/datagram.rs::tests::a_header_extension_timestamp_is_no_source_timestamp, crates/rtps/tests/reliable_e2e.rs::e2e_source_timestamp_round_trips

Status: done — an INFO_TS sets the source timestamp of the following Data and DataFrag, the I-flag case clears it; the timestamp of a HeaderExtension is rtpsSendTimestamp and no source timestamp.

§8.3.8.12 NackFrag: Purpose

Spec: §8.3.8.12, p. 68 — “This Submessage can only contain negative acknowledgements. … Fragments can be negatively acknowledged in any order.”

Repo: —

Tests: —

Status: n/a (informative) — statement of purpose.

§8.3.8.12 Table 8.50 NackFrag EndiannessFlag

Spec: §8.3.8.12, p. 68, Table 8.50 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/submessages.rs (NackFragSubmessage::write_body, NackFragSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::tests::nack_frag_roundtrip_be

Status: done

§8.3.8.12 Table 8.50 NackFrag readerId

Spec: §8.3.8.12, p. 68, Table 8.50 — “readerId: EntityId — Identifies the Reader entity that requests to receive certain fragments.”

Repo: crates/rtps/src/submessages.rs (NackFragSubmessage::reader_id)

Tests: crates/rtps/src/reliable_writer.rs::tests::nackfrag_dispatches_only_to_matching_proxy

Status: done

§8.3.8.12 Table 8.50 NackFrag writerId

Spec: §8.3.8.12, p. 69, Table 8.50 — “writerId: EntityId — Identifies the Writer entity that is the target of the NackFrag message.”

Repo: crates/rtps/src/submessages.rs (NackFragSubmessage::writer_id); crates/rtps/src/reliable_writer.rs (handle_nackfrag)

Tests: crates/rtps/src/reliable_writer.rs::tests::handle_nackfrag_queues_fragment_resends

Status: done

§8.3.8.12 Table 8.50 NackFrag writerSN

Spec: §8.3.8.12, p. 69, Table 8.50 — “writerSN: SequenceNumber — The sequence number for which some fragments are missing.”

Repo: crates/rtps/src/submessages.rs (NackFragSubmessage::writer_sn)

Tests: crates/rtps/src/reliable_writer.rs::tests::tick_resends_requested_fragments

Status: done

§8.3.8.12 Table 8.50 NackFrag fragmentNumberState

Spec: §8.3.8.12, p. 69, Table 8.50 — “fragmentNumberState: FragmentNumberSet — … The fragment numbers that appear in the set indicate missing fragments on the reader side.”

Repo: crates/rtps/src/submessages.rs (NackFragSubmessage::fragment_number_state); crates/rtps/src/reader_proxy.rs (requested_fragments_set)

Tests: crates/rtps/src/reader_proxy.rs::tests::requested_fragments_set_above_ack_only, crates/rtps/src/reliable_writer.rs::tests::handle_nackfrag_queues_fragment_resends

Status: done

§8.3.8.12 Table 8.50 NackFrag count

Spec: §8.3.8.12, p. 69, Table 8.50 — “count: Count — A counter that is incremented each time a new NackFrag message is sent.”

Repo: crates/rtps/src/reliable_reader.rs (build_nackfrag_datagram)

Tests: crates/rtps/src/reliable_reader.rs::tests::the_counts_of_acknack_and_nack_frag_rise_with_each_message

Status: done — successive NACK_FRAGs carry the counts 1, 2, 3.

§8.3.8.12 NackFrag invalid: submessageLength too small

Spec: §8.3.8.12, p. 69 — “submessageLength in the Submessage header is too small.”

Repo: crates/rtps/src/submessages.rs (NackFragSubmessage::read_body)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — the shortening is recognised; the submessage is invalid and the rest of the message with it, the submessages before it stand (ParsedDatagram::invalid_rest, counted).

§8.3.8.12 NackFrag invalid: writerSN ≤ 0

Spec: §8.3.8.12, p. 69 — “writerSN.value is zero or negative.”

Repo: crates/rtps/src/submessages.rs (NackFragSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::validity_tests::fragment_submessages_validity_rules

Status: done — a writerSN below 1 is refused.

§8.3.8.12 NackFrag invalid: invalid fragmentNumberState

Spec: §8.3.8.12, p. 69 — “fragmentNumberState is invalid (as defined in 8.3.5.7).”

Repo: crates/rtps/src/submessages.rs (FragmentNumberSet::read_from)

Tests: crates/rtps/src/submessages.rs::validity_tests::fragment_submessages_validity_rules, crates/rtps/src/submessages.rs::tests::fnset_rejects_num_bits_above_256

Status: done — numBits > 256 and bitmapBase < 1 are refused.

§8.3.8.12 NackFrag: writerGUID = {destGuidPrefix, writerId}

Spec: §8.3.8.12, p. 69 — “writerGUID = { Receiver.destGuidPrefix, NackFrag.writerId }”.

Repo: crates/dcps/src/runtime.rs (handle_user_datagram_from: rt.writer_slot(nf.writer_id))

Tests: crates/dcps/src/runtime.rs::tests::the_submessages_after_an_info_destination_for_another_participant_are_not_ours

Status: done

§8.3.8.12 NackFrag: readerGUID = {sourceGuidPrefix, readerId}

Spec: §8.3.8.12, p. 69 — “readerGUID = { Receiver.sourceGuidPrefix, NackFrag.readerId }”.

Repo: crates/dcps/src/runtime.rs (handle_user_datagram_from: Guid::new(src_prefix, nf.reader_id)); crates/rtps/src/reliable_writer.rs (handle_nackfrag)

Tests: crates/rtps/src/reliable_writer.rs::tests::handle_nackfrag_unknown_source_counts

Status: done

§8.3.8.13 Pad: Purpose

Spec: §8.3.8.13, p. 69 — “The purpose of this Submessage is to allow the introduction of any padding necessary to meet any desired memory- alignment requirements. It has no other meaning.”

Repo: —

Tests: —

Status: n/a (informative) — statement of purpose.

§8.3.8.13 Pad: length from submessageLength, always valid

Spec: §8.3.8.13, p. 69 — “This Submessage has no contents. … The amount of padding is determined by the value of submessageLength. … This Submessage is always valid.”

Repo: crates/rtps/src/datagram.rs (decode_datagram: PAD skipped as ParsedSubmessage::Unknown, length 0 as a length)

Tests: crates/rtps/src/datagram.rs::tests::pad_submessage_is_skipped_and_the_data_behind_it_still_decodes, crates/rtps/src/datagram.rs::tests::pad_submessage_is_skipped_and_re_encoded_byte_for_byte

Status: done


§8.4 Behavior Module

§8.4.1 Overview

Spec: §8.4.1, p. 70 — structure of the module; §8.4.2 holds the obligations, §8.4.7–§8.4.12 two reference implementations.

Repo: —

Tests: —

Status: n/a (informative) — structure.

§8.4.1 The DataWriter removes changes only per communication status and QoS

Spec: §8.4.1, p. 70 — “It is the responsibility of the DDS DataWriter to only remove those CacheChange changes that can be removed based on the communication status and the DDS DataWriter’s QoS. For example, the HISTORY QoS setting of KEEP_LAST with a depth of 1 allows a DataWriter to remove a CacheChange if a more recent change replaces the value of the same data-object.”

Repo: crates/rtps/src/reliable_writer.rs (remove_acknowledged, KEEP_LAST eviction through HistoryCache::insert_returning_evicted); crates/dcps/src/runtime.rs (await_writer_room for KEEP_ALL)

Tests: crates/rtps/src/reliable_writer.rs::tests::keep_last_evicts_oldest_on_overflow, crates/rtps/src/history_cache.rs::tests::keep_last_per_instance_keeps_the_newest_of_each_instance, crates/dcps/tests/reader_room_backpressure.rs::a_full_keep_all_reader_blocks_its_writer_and_loses_nothing

Status: done

§8.4.1.1 Example Behavior

Spec: §8.4.1.1, pp. 70–72 — “The contents of this sub clause are not part of the formal specification of the protocol.”

Repo: —

Tests: —

Status: n/a (informative) — explicitly not part of the formal spec.

§8.4.2 Behavior Required for Interoperability: scope

Spec: §8.4.2, pp. 72–73 — the obligations apply to exchanges between implementations of different vendors.

Repo: —

Tests: —

Status: n/a (informative) — scope; the obligations follow one by one.

§8.4.2.1 Only RTPS messages

Spec: §8.4.2.1, p. 73 — “No other messages can be used than the RTPS Messages defined in 8.3. … Vendors may extend Messages for vendor specific needs using the extension mechanisms provided by the protocol (see 8.6).”

Repo: crates/rtps/src/datagram.rs (decode_datagram, encode_datagram); crates/rtps/src/parameter_list.rs (vendor PIDs SHM_LOCATOR, ZERODDS_TYPE_ID)

Tests: crates/rtps/tests/vendor_frames.rs::cyclone_session_re_encodes_byte_for_byte, crates/rtps/tests/vendor_frames.rs::rti_session_re_encodes_byte_for_byte

Status: done — the deviation in the HeaderExtension id is listed under §9.4.5.1.1.

§8.4.2.1 Message receiver implemented

Spec: §8.4.2.1, p. 73 — “Implementations must implement the rules followed by the RTPS Message Receiver, as introduced in 8.3.4 … This requirement also includes proper Message formatting by preceding Entity Submessages with Interpreter Submessages when required”.

Repo: crates/rtps/src/datagram.rs (ParsedDatagram::receiver_walk); crates/rtps/src/reliable_writer.rs (INFO_TS and INFO_DST before DATA, HEARTBEAT); crates/rtps/src/reliable_reader.rs (wrap_to_writer)

Tests: crates/rtps/src/datagram.rs::tests::receiver_walk_attributes_submessages_after_info_source_to_the_new_prefix, crates/rtps/src/reliable_writer.rs::tests::write_stamped_prepends_info_ts_before_data, crates/rtps/src/reliable_reader.rs::tests::pre_emptive_acknack_carries_info_dst

Status: done — the receiver is implemented; the items under §8.3.4, §8.3.4.1 and §8.3.8 in which it differed from the spec (“Valid submessages before an invalid one”, “destGuidPrefix on the data path” and others) are done.

§8.4.2.1 Timing tunable

Spec: §8.4.2.1, p. 73 — “where the requirements on the protocol behavior allow delayed responses or specify periodic events, implementations must allow the end-user to tune those timing characteristics.”

Repo: crates/dcps/src/runtime.rs (RuntimeConfig::nack_response_delay, nack_suppression_duration, writer_heartbeat_period, reader_heartbeat_response_delay, reader_heartbeat_suppression_duration, spdp_period, wlp_period)

Tests: crates/dcps/tests/runtime_config_layering.rs::the_protocol_timing_parameters_are_settings, crates/rtps/src/reliable_writer.rs::tests::a_repair_waits_for_the_nack_response_delay, crates/rtps/src/reliable_writer.rs::tests::a_nack_inside_the_suppression_duration_is_ignored

Status: done — nackResponseDelay, nackSuppressionDuration, heartbeatPeriod, heartbeatResponseDelay, heartbeatSuppressionDuration, the SPDP and the WLP period are settings (writer.*_ms, reader.*_ms, discovery.*_ms, man page and example configuration).

§8.4.2.1 HEARTBEAT timings of the user endpoints tunable

Spec: §8.4.2.1, p. 73 — as the previous item; §8.4.7.1 Table 8.53 heartbeatPeriod, §8.4.10.1 Table 8.67 heartbeatResponseDelay, heartbeatSuppressionDuration.

Repo: crates/dcps/src/runtime.rs (writer_heartbeat_period, reader_heartbeat_response_delay, reader_heartbeat_suppression_duration)

Tests: crates/dcps/tests/runtime_config_layering.rs::the_protocol_timing_parameters_are_settings

Status: done — writer.heartbeat_period_ms, reader.heartbeat_response_delay_ms, reader.heartbeat_suppression_duration_ms.

§8.4.2.1 SPDP and SEDP implemented

Spec: §8.4.2.1, p. 73 — “For the purpose of interoperability, implementations must implement at least the Simple Participant Discovery Protocol and Simple Endpoint Discovery Protocol (see 8.5.1).”

Repo: crates/discovery/src/spdp.rs; crates/discovery/src/sedp/stack.rs

Tests: crates/discovery/src/spdp.rs::tests::beacon_serializes_to_decodable_datagram, crates/discovery/src/sedp/stack.rs::tests::end_to_end_discovery_between_two_stacks

Status: done — the individual obligations are under §8.5.

§8.4.2.2 Writers do not send out of order

Spec: §8.4.2.2, p. 73 — “A Writer must send out data samples in the order they were added to its HistoryCache.”

Repo: crates/rtps/src/reliable_writer.rs (write_sample_with_inline_qos: sends only to a proxy that is in step; repairs ascending through next_requested_change)

Tests: crates/rtps/tests/reliable_e2e.rs::e2e_zero_loss_delivers_all_in_order, crates/rtps/src/reliable_writer.rs::tests::repairs_in_order_bring_a_lagging_proxy_into_step

Status: done

§8.4.2.2 Writers send in-line QoS on the reader’s request

Spec: §8.4.2.2, p. 73 — “A Writer must honor a Reader’s request to receive data messages with in-line QoS.”

Repo: crates/rtps/src/reliable_writer.rs (set_inline_writer_qos, sample_inline_qos); crates/rtps/src/reader_proxy.rs (ReaderProxy::expects_inline_qos)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_reader_that_expects_inline_qos_gets_the_writers_qos_with_each_data

Status: done

§8.4.2.2 Periodic HEARTBEATs (reliable only)

Spec: §8.4.2.2, pp. 73–74 — “A Writer must periodically inform each matching reliable Reader of the availability of a data sample by sending a periodic HEARTBEAT Message … For strict reliable communication, the Writer must continue to send HEARTBEAT Messages to a Reader until the Reader has either acknowledged receiving all available samples or has disappeared.”

Repo: crates/rtps/src/reliable_writer.rs (tick: announcing, heartbeat_due)

Tests: crates/rtps/src/reliable_writer.rs::tests::tick_emits_heartbeat_after_period, crates/rtps/src/reliable_writer.rs::tests::an_acknowledged_reader_is_heartbeated_until_it_answers_one, crates/rtps/src/reliable_writer.rs::tests::a_reader_that_acknowledged_the_cache_gets_no_periodic_heartbeat

Status: done

§8.4.2.2 Response to a negative acknowledgement (reliable only)

Spec: §8.4.2.2, p. 74 — “When receiving an ACKNACK Message indicating a Reader is missing some data samples, the Writer must respond by either sending the missing data samples, sending a GAP message when the sample is not relevant, or sending a HEARTBEAT message when the sample is no longer available.”

Repo: crates/rtps/src/reliable_writer.rs (tick: DATA from the cache, GAP through append_gap for changes no longer present)

Tests: crates/rtps/src/reliable_writer.rs::tests::tick_resends_requested_as_data_aggregated_with_hb, crates/rtps/src/reliable_writer.rs::tests::tick_resends_evicted_request_as_gap

Status: done

§8.4.2.2 HEARTBEAT and GAP with writer group information

Spec: §8.4.2.2, p. 74 — “A Writer belonging to a Group shall send HEARTBEAT or GAP Submessages to its matched Readers even if the Reader has acknowledged all of that Writer’s samples.”

Repo: —

Tests: crates/rtps/src/reliable_writer.rs::tests::a_group_writer_heartbeats_an_acknowledged_reader_when_the_group_moved_on, crates/rtps/src/reliable_writer.rs::tests::a_group_writer_with_an_empty_cache_is_due_for_a_heartbeat

Status: done

§8.4.2.3 Best-effort readers are passive

Spec: §8.4.2.3, p. 74 — “A best-effort Reader is completely passive as it only receives data and does not send messages itself.”

Repo: crates/rtps/src/reliable_reader.rs (ReliableReader::tick_outbound)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_best_effort_reader_sends_no_acknack

Status: done — a reader with set_best_effort(true) sends neither ACKNACK nor NACK_FRAG, neither on matching nor in answer to HEARTBEATs.

§8.4.2.3 Response to a HEARTBEAT without FinalFlag

Spec: §8.4.2.3, p. 74 — “Upon receiving a HEARTBEAT Message with final flag not set, the Reader must respond with an ACKNACK Message. … The response may be delayed to avoid message storms.”

Repo: crates/rtps/src/reliable_reader.rs (handle_heartbeat, tick_outbound)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_heartbeat_with_the_liveliness_flag_is_taken_as_a_heartbeat

Status: done

§8.4.2.3 Response to a HEARTBEAT with missing samples

Spec: §8.4.2.3, p. 74 — “a Reader that is missing some data samples must respond with an ACKNACK Message indicating which data samples are missing. This requirement only applies if the Reader can accommodate these missing samples in its cache … The response is not required when a liveliness HEARTBEAT has both liveliness and final flags set”.

Repo: crates/rtps/src/reliable_reader.rs (handle_heartbeat, tick_outbound, full_for_the_consumer, build_acknack_datagram)

Tests: crates/rtps/src/reliable_reader.rs::tests::heartbeat_with_missing_triggers_acknack_after_delay, crates/rtps/src/reliable_reader.rs::tests::a_cache_full_for_the_consumer_holds_the_acknack_until_it_takes, crates/rtps/src/reliable_reader.rs::tests::a_cache_full_behind_a_missing_change_still_names_it

Status: done

§8.4.2.3 Once acknowledged, always acknowledged (reader)

Spec: §8.4.2.3, p. 74 — “Once a Reader has positively acknowledged receiving a sample using an ACKNACK Message, it can no longer negatively acknowledge that same sample at a later point.”

Repo: crates/rtps/src/writer_proxy.rs (acknack_base monotonic; unreceive_change_set only above the base)

Tests: crates/rtps/src/writer_proxy.rs::tests::acknack_base_walks_up, crates/rtps/src/reliable_reader.rs::tests::sample_rejected_by_a_full_cache_stays_missing_for_the_acknack

Status: done

§8.4.2.3 The writer resends acknowledged samples requested again

Spec: §8.4.2.3, p. 74 — “if a Writer receives a negative acknowledgement to a previously positively acknowledged sample, and the Writer can still service the request, the Writer should send the sample.”

Repo: crates/rtps/src/reader_proxy.rs (requested_changes_set); crates/rtps/src/reliable_writer.rs (handle_acknack_window, tick)

Tests: crates/rtps/src/reader_proxy.rs::tests::a_request_for_an_acknowledged_change_is_kept, crates/rtps/src/reliable_writer.rs::tests::an_acknowledged_change_asked_for_again_is_sent_again

Status: done — a new request for an acknowledged sample is kept; the writer sends it while its cache holds it, a GAP otherwise.

§8.4.2.3 ACKNACK only in response to a HEARTBEAT

Spec: §8.4.2.3, p. 74 — “In steady state, an ACKNACK Message can only be sent as a response to a HEARTBEAT Message from a Writer. ACKNACK Messages can be sent from a Reader when it first discovers a Writer as an optimization.”

Repo: crates/rtps/src/reliable_reader.rs (add_writer_proxy, handle_heartbeat, handle_data_frag_opening, tick_outbound)

Tests: crates/rtps/src/reliable_reader.rs::tests::acknack_and_nack_frag_wait_for_a_heartbeat, crates/rtps/src/reliable_reader.rs::tests::pre_emptive_acknack_emitted_after_add_writer_proxy

Status: done — an ACKNACK follows from a HEARTBEAT (Table 8.77 T2) and from the first match of a writer; neither the repeated add_writer_proxy of a known writer nor a DATA_FRAG with holes arms one.

§8.4.3 Implementing the RTPS Protocol

Spec: §8.4.3, p. 75 — “a compliant implementation of the protocol need only satisfy the requirements presented in 8.4.2. … Actual implementations need not necessarily follow the reference implementations.”

Repo: —

Tests: —

Status: n/a (informative) — makes the reference implementations optional. The transitions under §8.4.8–§8.4.12 are checked against the ZeroDDS types that model a reference implementation: ReliableWriter (stateful writer, best effort and reliable, user-data path), ReliableReader (stateful reader), BestEffortWriter, ReliableStatelessWriter, BestEffortReader (used in tests only) and the SPDP beacon.

§8.4.4 Permitted combinations of reliabilityLevel

Spec: §8.4.4, p. 75 — “An RTPS Writer cannot be matched to an RTPS Reader unless either the RTPS Writer has the reliabilityLevel set to RELIABLE, or else both the RTPS Writer and RTPS Reader have the reliabilityLevel set to BEST_EFFORT.”

Repo: crates/qos/src/policies/reliability.rs (ReliabilityKind ordering); QoS comparison on matching in crates/dcps/src/runtime.rs; the ReaderProxy is reliable only with a reliable writer and reader (ReaderProxy::new in the SEDP match path of crates/dcps/src/runtime.rs)

Tests: crates/qos/src/policies/reliability.rs::tests::best_effort_lt_reliable, crates/qos/src/policies/reliability.rs::tests::ordering_reliable_higher_than_besteffort, crates/dcps/tests/transient_local_durability.rs::linux::transient_local_writer_delivers_history_to_late_joiner

Status: done — the comparison of offered and requested QoS is listed in the DCPS audit.

§8.4.4 Stateful and stateless interoperate

Spec: §8.4.4, p. 75 — “a Stateful Writer is able to communicate with a Stateless Reader and vice versa.”

Repo: —

Tests: —

Status: n/a (informative) — follows from §8.4.2; no requirement of its own.

§8.4.5 Notational Conventions

Spec: §8.4.5, pp. 75–76, Table 8.51 — abbreviations DW, DR, W, RP, RL, R, WP, WHC, RHC.

Repo: —

Tests: —

Status: n/a (informative) — notation.

§8.4.6 Table 8.52 Duration_t

Spec: §8.4.6, p. 76, Table 8.52 — “Duration_t: Type used to hold time differences. Should have at least nano-second resolution.”

Repo: crates/qos/src/duration.rs (Duration {seconds, fraction}, 2⁻³² s)

Tests: crates/dcps/src/time.rs::tests::duration_zero_and_infinite_sentinels, crates/rtps/src/participant_data.rs::tests::duration_roundtrip_le

Status: done

§8.4.6 Table 8.52 ChangeForReaderStatusKind

Spec: §8.4.6, p. 76, Table 8.52 — “UNSENT, UNACKNOWLEDGED, REQUESTED, ACKNOWLEDGED, UNDERWAY”.

Repo: crates/rtps/src/reader_proxy.rs (highest_sent_sn, highest_acked_sn, requested_changes instead of a status per change)

Tests: crates/rtps/src/reader_proxy.rs::tests::next_unsent_change_walks_sequentially, crates/rtps/src/reader_proxy.rs::tests::acking_also_prunes_requested_changes

Status: done — modelled as counters and sets (§8.4.15.1).

§8.4.6 Table 8.52 ChangeFromWriterStatusKind

Spec: §8.4.6, p. 76, Table 8.52 — “NOT_AVAILABLE, MISSING, RECEIVED, UNKNOWN. There are three sub-kinds of NOT_AVAILABLE: NA_FILTERED, NA_REMOVED, NA_UNSPECIFIED”.

Repo: crates/rtps/src/writer_proxy.rs (ChangeFromWriterStatus, WriterProxy::change_status, NotAvailableKind, not_available_change_set, lost_changes_update); crates/rtps/src/reliable_reader.rs (ReliableReader::change_status, handle_gap)

Tests: crates/rtps/src/writer_proxy.rs::tests::change_status_is_kept_per_change_with_the_sub_kind, crates/rtps/src/writer_proxy.rs::tests::lost_changes_update_sets_na_removed_per_change, crates/rtps/src/writer_proxy.rs::tests::not_available_runs_are_joined_and_bounded, crates/rtps/src/reliable_reader.rs::tests::the_reader_keeps_the_status_of_each_change, crates/rtps/src/reliable_reader.rs::tests::a_gap_sorts_its_changes_by_the_filtered_count

Status: done — UNKNOWN, MISSING, RECEIVED and NOT_AVAILABLE with the sub-kinds NA_FILTERED, NA_REMOVED and NA_UNSPECIFIED are kept per change (WriterProxy::change_status). The NOT_AVAILABLE changes are held as runs of one sub-kind (at most 4096; older means None). lost_changes_update enters NA_REMOVED and counts it; a change with the FilteredFlag enters NA_FILTERED.

§8.4.6 Table 8.52 InstanceHandle_t

Spec: §8.4.6, p. 76, Table 8.52 — “Type used to represent the identity of a data-object whose changes in value are communicated by the RTPS protocol.”

Repo: crates/rtps/src/history_cache.rs (CacheChange::key_hash)

Tests: crates/rtps/src/history_cache.rs::tests::the_instance_index_follows_inserts_evictions_and_removals

Status: done — as Table 8.2 (§8.2.1.2).

§8.4.6 Table 8.52 ParticipantMessageData

Spec: §8.4.6, p. 76, Table 8.52 — “Type used to hold data exchanged between Participants. The most notable use of this type is for the Writer Liveliness Protocol.”

Repo: crates/rtps/src/participant_message_data.rs (ParticipantMessageData)

Tests: crates/rtps/src/participant_message_data.rs::tests::participant_message_data_roundtrip_le

Status: done — content and wire format under §8.4.13.4 and §9.6.3.1.

§8.4.7.1 Table 8.53 Writer pushMode

Spec: §8.4.7.1, p. 78, Table 8.53 — “If pushMode==true, then the Writer will push changes to the reader. If pushMode==false, changes will only be announced via heartbeats and only be sent as response to the request of a reader.”

Repo: crates/rtps/src/reliable_writer.rs (set_push_mode, push_mode)

Tests: crates/rtps/src/reliable_writer.rs::tests::push_mode_false_announces_by_heartbeat_and_sends_only_on_request, crates/rtps/src/reliable_writer.rs::tests::push_mode_false_sends_no_data_on_the_piggyback_path

Status: done

§8.4.7.1 Table 8.53 Writer heartbeatPeriod

Spec: §8.4.7.1, p. 78, Table 8.53 — “heartbeatPeriod: Protocol tuning parameter that allows the RTPS Writer to repeatedly announce the availability of data by sending a Heartbeat Message.”

Repo: crates/rtps/src/reliable_writer.rs (ReliableWriterConfig::heartbeat_period, DEFAULT_HEARTBEAT_PERIOD)

Tests: crates/rtps/src/reliable_writer.rs::tests::heartbeat_due_follows_the_last_heartbeat, crates/rtps/src/reliable_writer.rs::tests::tick_emits_heartbeat_after_period

Status: done — its tunability for the user is listed under §8.4.2.1.

§8.4.7.1 Table 8.53 Writer nackResponseDelay

Spec: §8.4.7.1, p. 78, Table 8.53 — “nackResponseDelay: Protocol tuning parameter that allows the RTPS Writer to delay the response to a request for data from a negative acknowledgment.”

Repo: crates/rtps/src/reliable_writer.rs (set_nack_response_delay); crates/rtps/src/reader_proxy.rs (repair_due)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_repair_waits_for_the_nack_response_delay, crates/rtps/src/reliable_writer.rs::tests::a_zero_nack_response_delay_repairs_on_the_next_tick

Status: done

§8.4.7.1 Table 8.53 Writer nackSuppressionDuration

Spec: §8.4.7.1, p. 78, Table 8.53 — “nackSuppressionDuration: Protocol tuning parameter that allows the RTPS Writer to ignore requests for data from negative acknowledgments that arrive ‘too soon’ after the corresponding change is sent.”

Repo: crates/rtps/src/reliable_writer.rs (set_nack_suppression_duration, too_soon)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_nack_inside_the_suppression_duration_is_ignored

Status: done

§8.4.7.1 Table 8.53 Writer lastChangeSequenceNumber

Spec: §8.4.7.1, p. 78, Table 8.53 — “Internal counter used to assign increasing sequence number to each change made by the Writer.”

Repo: crates/rtps/src/reliable_writer.rs (next_sn, last_written_sn)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_increments_sn_and_returns_data_datagram

Status: done

§8.4.7.1 Table 8.53 Writer writer_cache

Spec: §8.4.7.1, p. 78, Table 8.53 — “writer_cache: HistoryCache — Contains the history of CacheChange changes for this Writer.”

Repo: crates/rtps/src/reliable_writer.rs (ReliableWriter::cache)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_at_cache_capacity_is_error

Status: done

§8.4.7.1 Table 8.53 Writer dataMaxSizeSerialized

Spec: §8.4.7.1, p. 78, Table 8.53 — “Optional attribute that indicates the maximum size of any SerializedPayload that may be sent by the Writer.”

Repo: crates/dcps/src/dds_type.rs (MAX_SERIALIZED_SIZE); crates/dcps/src/publisher.rs (WriterRegistration); crates/dcps/src/runtime.rs (UserWriterConfig::data_max_size_serialized, build_publication_data)

Tests: crates/rtps/src/publication_data.rs::tests::the_max_payload_size_and_the_name_of_a_writer_travel

Status: done — the attribute is optional. The writer announces dataMaxSizeSerialized as PID_TYPE_MAX_SIZE_SERIALIZED when it is set: from DdsType::MAX_SERIALIZED_SIZE or from UserWriterConfig::data_max_size_serialized (the value is without the encapsulation header; it is announced with the 4 octets of the header). Without a value it announces nothing.

§8.4.7.1 Table 8.54 Writer new

Spec: §8.4.7.1, p. 79 — “this.lastChangeSequenceNumber := 0; this.writer_cache := new HistoryCache;” and the attributes taken from the constructor.

Repo: crates/rtps/src/reliable_writer.rs (ReliableWriter::new: next_sn: 0, a new HistoryCache)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_increments_sn_and_returns_data_datagram

Status: done

§8.4.7.1 Table 8.54 Writer new_change

Spec: §8.4.7.1, p. 79 — “The sequence number of the CacheChange is automatically set to be the sequenceNumber of the previous change plus one. … ++this.lastChangeSequenceNumber; a_change := new CacheChange(kind, this.guid, this.lastChangeSequenceNumber, data, inlineQos, handle);”

Repo: crates/rtps/src/reliable_writer.rs (stage_sample, write_lifecycle)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_increments_sn_and_returns_data_datagram, crates/rtps/src/writer.rs::tests::writer_sn_overflow_is_error

Status: done

§8.4.7.1 Default nackResponseDelay = 200 ms

Spec: §8.4.7.1, p. 79 — “nackResponseDelay.sec = 0; nackResponseDelay.nanosec = 200 * 1000 * 1000; //200 milliseconds”.

Repo: crates/rtps/src/reliable_writer.rs (DEFAULT_NACK_RESPONSE_DELAY, SPEC_NACK_RESPONSE_DELAY); crates/dcps/src/runtime.rs (RuntimeConfig::nack_response_delay)

Tests: crates/rtps/src/reliable_writer.rs::tests::nack_response_delay_defaults_to_the_spec_200_ms_and_suppression_to_zero, crates/dcps/tests/runtime_config_layering.rs::the_protocol_timing_parameters_are_settings

Status: done — DEFAULT_NACK_RESPONSE_DELAY and RuntimeConfig::nack_response_delay are 200 ms; a NACK is answered with the repair only after that time (test). writer.nack_response_delay_ms: 0 answers on the next tick.

§8.4.7.1 Default nackResponseDelay

Spec: §8.4.7.1, p. 79 — “The following timing-related values are used as the defaults in order to facilitate ‘out-of-the-box’ interoperability between implementations.”

Repo: crates/rtps/src/reliable_writer.rs (DEFAULT_NACK_RESPONSE_DELAY, DEFAULT_NACK_SUPPRESSION_DURATION); crates/dcps/src/runtime.rs; man/man5/zerodds.yaml.5; packaging/linux/configs/zerodds.yaml.example

Tests: crates/dcps/tests/runtime_config_layering.rs::the_protocol_timing_parameters_are_settings, crates/rtps/src/reliable_writer.rs::tests::nack_response_delay_defaults_to_the_spec_200_ms_and_suppression_to_zero

Status: done — the values of the spec are the defaults: nackResponseDelay 200 ms, nackSuppressionDuration 0 (runtime, YAML default, man page, example configuration). The former 0 ms stay reachable through writer.nack_response_delay_ms; tests that drive a millisecond clock set 0 explicitly.

§8.4.7.1 Default nackSuppressionDuration = 0

Spec: §8.4.7.1, p. 79 — “nackSuppressionDuration.sec = 0; nackSuppressionDuration.nanosec = 0;”.

Repo: crates/rtps/src/reliable_writer.rs (DEFAULT_NACK_SUPPRESSION_DURATION)

Tests: crates/rtps/src/reliable_writer.rs::tests::nack_response_delay_defaults_to_the_spec_200_ms_and_suppression_to_zero

Status: done

§8.4.7.2 Table 8.55 StatelessWriter reader_locators

Spec: §8.4.7.2, p. 80, Table 8.55 — “The StatelessWriter maintains the list of locators to which it sends the CacheChanges. This list may include both unicast and multicast locators.”

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter::reader_locators, ReaderLocator); crates/discovery/src/spdp.rs (SpdpBeacon, target locators)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::reader_locators_are_added_looked_up_and_removed

Status: done — the list consists of ReaderLocator objects with state of their own (highest_sent_seq_num, requested changes, expects_inline_qos).

§8.4.7.2 Table 8.56 StatelessWriter new

Spec: §8.4.7.2, p. 80 — “this.reader_locators := ;”

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter::new: reader_locators leer)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::reader_locators_are_added_looked_up_and_removed, crates/rtps/src/reliable_stateless_writer.rs::tests::shutdown_clears_the_cache_and_the_requests

Status: done

§8.4.7.2 Table 8.56 StatelessWriter reader_locator_add

Spec: §8.4.7.2, p. 80 — “ADD a_locator TO {this.reader_locators};”

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator) reader_locator_add

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::reader_locators_are_added_looked_up_and_removed

Status: done — a locator is added as a ReaderLocator with expectsInlineQos, once per locator. ReliableStatelessWriter is used by no production path; no vendor is measured.

§8.4.7.2 Table 8.56 StatelessWriter reader_locator_remove

Spec: §8.4.7.3, p. 81 — “REMOVE a_locator FROM {this.reader_locators};”

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter::reader_locator_remove)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::reader_locators_are_added_looked_up_and_removed

Status: done — a ReaderLocator is removed; removing it again reports false.

§8.4.7.2 Table 8.56 StatelessWriter unsent_changes_reset

Spec: §8.4.7.2, p. 81 — “This operation resets the ‘highestSentChangeSN’ for all the ReaderLocators … useful when called periodically to cause the StatelessWriter to keep re-sending all available changes”.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter::unsent_changes_reset, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::unsent_changes_reset_makes_every_change_unsent_again, crates/rtps/src/reliable_stateless_writer.rs::tests::unsent_changes_are_pushed_in_order_then_announced

Status: done — unsent_changes_reset sets highestSentChangeSN of all ReaderLocators to 0; the next tick sends all changes of the cache again to every locator. ReliableStatelessWriter is used by no production path; no vendor is measured.

§8.4.7.3 Table 8.57 ReaderLocator attributes

Spec: §8.4.7.3, p. 81, Table 8.57 — highestSentChangeSN, requestedChanges, locator, expectsInlineQos.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::reader_locators_are_added_looked_up_and_removed, crates/rtps/src/reliable_stateless_writer.rs::tests::unsent_changes_are_pushed_in_order_then_announced

Status: done — ReaderLocator holds locator, expects_inline_qos, highest_sent_seq_num and the requested changes. ReliableStatelessWriter is used by no production path; no vendor is measured.

§8.4.7.3 Table 8.58 ReaderLocator operations

Spec: §8.4.7.3, pp. 81–82, Table 8.58 — new, next_requested_change, next_unsent_change, requested_changes, requested_changes_set, unsent_changes.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::unsent_changes_are_pushed_in_order_then_announced, crates/rtps/src/reliable_stateless_writer.rs::tests::an_acknack_is_answered_at_its_reply_locator_after_the_delay

Status: done — requested_changes, requested_changes_set, next_requested_change, unsent_changes are methods of ReaderLocator; next_unsent_change is in the push machine (next_cached_above). ReliableStatelessWriter is used by no production path; no vendor is measured.

§8.4.7.4 Table 8.59 StatefulWriter matched_readers

Spec: §8.4.7.4, p. 83, Table 8.59 — “The StatefulWriter keeps track of all the RTPS Readers matched with it. Each matched reader is represented by an instance of the ReaderProxy class.”

Repo: crates/rtps/src/reliable_writer.rs (reader_proxies, reader_proxies())

Tests: crates/rtps/src/reliable_writer.rs::tests::write_fans_out_to_all_reader_proxies

Status: done

§8.4.7.4 Table 8.60 StatefulWriter new

Spec: §8.4.7.4, p. 83 — “this.matched_readers := ;”

Repo: crates/rtps/src/reliable_writer.rs (ReliableWriter::new with ReliableWriterConfig::reader_proxies)

Tests: crates/rtps/src/reliable_writer.rs::tests::is_acked_by_all_without_proxies_is_true

Status: done

§8.4.7.4 Table 8.60 StatefulWriter is_acked_by_all

Spec: §8.4.7.4, p. 83 — “return true IF and only IF FOREACH proxy IN this.matched_readers a_change_seq_num IN proxy.acknowledged_changes”.

Repo: crates/rtps/src/reliable_writer.rs (is_acked_by_all)

Tests: crates/rtps/src/reliable_writer.rs::tests::is_acked_by_all_follows_the_slowest_reader_proxy, crates/rtps/src/reliable_writer.rs::tests::is_acked_by_all_without_proxies_is_true

Status: done

§8.4.7.4 Table 8.60 StatefulWriter matched_reader_add

Spec: §8.4.7.4, pp. 83–84 — “ADD a_reader_proxy TO {this.matched_readers};”

Repo: crates/rtps/src/reliable_writer.rs (add_reader_proxy)

Tests: crates/rtps/src/reliable_writer.rs::tests::add_reader_proxy_is_idempotent_on_same_guid, crates/rtps/src/reliable_writer.rs::tests::heartbeat_after_add_reader_proxy_is_non_final

Status: done

§8.4.7.4 Table 8.60 StatefulWriter matched_reader_remove

Spec: §8.4.7.4, p. 84 — “REMOVE a_reader_proxy FROM {this.matched_readers}; delete proxy;”

Repo: crates/rtps/src/reliable_writer.rs (remove_reader_proxy)

Tests: crates/rtps/src/reliable_writer.rs::tests::remove_reader_proxy_by_guid

Status: done

§8.4.7.4 Table 8.60 StatefulWriter matched_reader_lookup

Spec: §8.4.7.4, p. 84 — “FIND proxy IN this.matched_readers SUCH-THAT (proxy.remoteReaderGuid == a_reader_guid); return proxy;”

Repo: crates/rtps/src/reliable_writer.rs (handle_acknack_window, handle_nackfrag: lookup by remote_reader_guid)

Tests: crates/rtps/src/reliable_writer.rs::tests::acknack_dispatches_to_matching_proxy_only

Status: done

§8.4.7.5 Table 8.61 ReaderProxy remoteReaderGuid

Spec: §8.4.7.5, p. 84, Table 8.61 — “remoteReaderGuid: GUID_t — Identifies the remote matched RTPS Reader that is represented by the ReaderProxy.”

Repo: crates/rtps/src/reader_proxy.rs (ReaderProxy::remote_reader_guid)

Tests: crates/rtps/src/reliable_writer.rs::tests::add_reader_proxy_is_idempotent_on_same_guid

Status: done

§8.4.7.5 Table 8.61 ReaderProxy remoteGroupEntityId

Spec: §8.4.7.5, p. 84, Table 8.61 — “remoteGroupEntityId: EntityId_t — Identifies the group to which the matched Reader belongs”.

Repo: crates/rtps/src/reader_proxy.rs (ReaderProxy::remote_group_entity_id, with_remote_group_entity_id); crates/dcps/src/runtime.rs (match path, PID_GROUP_GUID of the subscription)

Tests: crates/rtps/src/reader_proxy.rs::tests::the_remote_group_entity_id_is_kept, crates/dcps/src/runtime.rs::tests::the_proxies_of_a_match_carry_the_remote_group_entity_id

Status: done — the proxy holds remoteGroupEntityId; the match path fills it from PID_GROUP_GUID of the reader’s SEDP announcement, ENTITYID_UNKNOWN without a group.

§8.4.7.5 Table 8.61 ReaderProxy unicastLocatorList

Spec: §8.4.7.5, p. 84, Table 8.61 — “List of unicast locators … that can be used to send messages to the matched RTPS Reader. The list may be empty.”

Repo: crates/rtps/src/reader_proxy.rs (ReaderProxy::unicast_locators)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_fans_out_to_every_unicast_locator_of_a_proxy

Status: done

§8.4.7.5 Table 8.61 ReaderProxy multicastLocatorList

Spec: §8.4.7.5, p. 84, Table 8.61 — “List of multicast locators … that can be used to send messages to the matched RTPS Reader. The list may be empty.”

Repo: crates/rtps/src/reader_proxy.rs (ReaderProxy::multicast_locators); crates/rtps/src/reliable_writer.rs (proxy_targets_of)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_reader_proxy_with_multicast_locators_is_sent_to_at_the_multicast_locator

Status: done — a proxy with multicast locators is sent to there (DATA and HEARTBEAT, one datagram for the group), one without at its unicast locators. The SEDP match path passes an empty list (“The list may be empty”); the unicast locators of the reader apply then.

§8.4.7.5 Table 8.61 ReaderProxy highestSentChangeSN

Spec: §8.4.7.5, p. 84, Table 8.61 — “The highest sequence number of the changes that have been sent to the matched RTPS Reader.”

Repo: crates/rtps/src/reader_proxy.rs (highest_sent_sn)

Tests: crates/rtps/src/reader_proxy.rs::tests::next_unsent_change_walks_sequentially

Status: done

§8.4.7.5 Table 8.61 ReaderProxy requestedChanges

Spec: §8.4.7.5, p. 84, Table 8.61 — “A list of sequence numbers representing changes that were requested by the matched RTPS Reader.”

Repo: crates/rtps/src/reader_proxy.rs (requested_changes)

Tests: crates/rtps/src/reader_proxy.rs::tests::a_request_for_an_acknowledged_change_is_kept

Status: done

§8.4.7.5 Table 8.61 ReaderProxy acknowledgedChanges

Spec: §8.4.7.5, pp. 84–85, Table 8.61 — “A list of sequence numbers representing changes that have been acknowledged by the matched RTPS Reader.”

Repo: crates/rtps/src/reader_proxy.rs (highest_acked_sn)

Tests: crates/rtps/src/reader_proxy.rs::tests::acked_changes_set_monotonic

Status: done — kept as the highest acknowledged number.

§8.4.7.5 Table 8.61 ReaderProxy expectsInlineQos

Spec: §8.4.7.5, p. 85, Table 8.61 — “Specifies whether the remote matched RTPS Reader expects in-line QoS to be sent along with any data.”

Repo: crates/rtps/src/reader_proxy.rs (expects_inline_qos, set_expects_inline_qos)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_reader_that_expects_inline_qos_gets_the_writers_qos_with_each_data

Status: done

§8.4.7.5 Table 8.61 ReaderProxy isActive

Spec: §8.4.7.5, p. 85, Table 8.61 — “isActive: bool — Specifies whether the remote Reader is responsive to the Writer.”

Repo: crates/rtps/src/reader_proxy.rs (note_activity, is_inactive)

Tests: crates/rtps/src/reader_proxy.rs::tests::proxy_becomes_inactive_after_threshold_elapses, crates/rtps/src/reader_proxy.rs::tests::proxy_is_active_after_note_activity

Status: done

§8.4.7.5 Matching follows the DDS match

Spec: §8.4.7.5, p. 85 — “The matching is a consequence of the match of the corresponding DDS entities. That is, the DDS DataWriter matches a DDS DataReader by Topic, has compatible QoS, and is not being explicitly ignored by the application that uses DDS.”

Repo: crates/dcps/src/runtime.rs (SEDP match, add_reader_proxy); crates/dcps/src/participant.rs (ignore_subscription)

Tests: crates/discovery/src/sedp/stack.rs::tests::end_to_end_discovery_between_two_stacks, crates/dcps/tests/xtypes_aware_match.rs::final_vs_appendable_mismatch_rejected_at_match_time

Status: done

§8.4.7.5 Table 8.62 ReaderProxy new

Spec: §8.4.7.5, p. 85 — “this.requested_changes := ; this.acknowledged_changes := ; this.highest_sent_seq_num := 0;”

Repo: crates/rtps/src/reader_proxy.rs (ReaderProxy::new)

Tests: crates/rtps/src/reader_proxy.rs::tests::fresh_proxy_has_zero_state

Status: done

§8.4.7.5 Table 8.62 ReaderProxy acked_changes_set

Spec: §8.4.7.5, p. 86 — “FOR_EACH seq_num <= committed_seq_num DO ADD seq_num TO this.acknowledged_changes”.

Repo: crates/rtps/src/reader_proxy.rs (acked_changes_set)

Tests: crates/rtps/src/reader_proxy.rs::tests::acked_changes_set_monotonic, crates/rtps/src/reader_proxy.rs::tests::acking_also_prunes_requested_changes

Status: done — the parameter is readerSNState.base, the acknowledged upper bound base − 1.

§8.4.7.5 Table 8.62 ReaderProxy next_requested_change

Spec: §8.4.7.5, p. 86 — “return MIN( this.requested_changes() );”

Repo: crates/rtps/src/reader_proxy.rs (next_requested_change)

Tests: crates/rtps/src/reader_proxy.rs::tests::next_requested_change_pulls_smallest_first

Status: done

§8.4.7.5 Table 8.62 ReaderProxy next_unsent_change

Spec: §8.4.7.5, p. 86 — “unsent_changes := { changes SUCH-THAT change.sequenceNumber > this.higuest_sent_seq_num } … ELSE return MIN { unsent_changes.sequenceNumber }”.

Repo: crates/rtps/src/reader_proxy.rs (next_unsent_change)

Tests: crates/rtps/src/reader_proxy.rs::tests::next_unsent_change_walks_sequentially, crates/rtps/src/reader_proxy.rs::tests::next_unsent_change_picks_up_after_cache_grows

Status: done — returns highest_sent + 1 up to the cache maximum; tick answers numbers no longer present with a GAP.

§8.4.7.5 Table 8.62 ReaderProxy requested_changes

Spec: §8.4.7.5, p. 86 — “return this.requested_changes”.

Repo: crates/rtps/src/reader_proxy.rs (pending_requested_count, next_requested_change)

Tests: crates/rtps/src/reader_proxy.rs::tests::a_request_for_an_acknowledged_change_is_kept

Status: done

§8.4.7.5 Table 8.62 ReaderProxy requested_changes_set

Spec: §8.4.7.5, p. 86 — “FOR_EACH seq_num IN req_seq_num_set DO ADD seq_num TO this.requested_changes;”

Repo: crates/rtps/src/reader_proxy.rs (requested_changes_set)

Tests: crates/rtps/src/reader_proxy.rs::tests::a_request_for_an_acknowledged_change_is_kept

Status: done — takes every requested number from the ACKNACK’s base on, also one acknowledged before (§8.4.2.3).

§8.4.7.5 Table 8.62 ReaderProxy unsent_changes

Spec: §8.4.7.5, p. 86 — “return ( this.next_unsent_change() != SEQUENCE_NUMBER_INVALID )”.

Repo: crates/rtps/src/reader_proxy.rs (highest_sent_sn against the cache maximum)

Tests: crates/rtps/src/reader_proxy.rs::tests::next_unsent_change_picks_up_after_cache_grows

Status: done

§8.4.7.5 Table 8.62 ReaderProxy unacked_changes

Spec: §8.4.7.5, p. 86 — “return ( highest_available_seq_num > highest_acked_seq_num )”.

Repo: crates/rtps/src/reader_proxy.rs (unacked_changes)

Tests: crates/rtps/src/reader_proxy.rs::tests::unacked_changes_detects_gap

Status: done

§8.4.8.1 Table 8.63 best-effort StatelessWriter T1

Spec: §8.4.8.1, pp. 87–88, Table 8.63 T1 — “a_locator := new ReaderLocator( locator, expectsInlineQos ); the_rtps_writer.reader_locator_add( a_locator );”

Repo: crates/discovery/src/spdp.rs (SpdpBeacon); crates/dcps/src/runtime.rs (RuntimeConfig::initial_peers, the SPDP multicast locator)

Tests: crates/dcps/src/runtime.rs::tests::initial_peer_specs_expand_per_the_configured_participant_limit, crates/discovery/src/spdp.rs::tests::beacon_serializes_to_decodable_datagram

Status: done — the SPDP beacon is ZeroDDS’ best-effort StatelessWriter; its target locators come from the configuration (§8.5.3.1).

§8.4.8.1 Table 8.63 best-effort StatelessWriter T2

Spec: §8.4.8.1, p. 88 — “triggered by the guard condition [RL::unsent_changes() == true] … The transition performs no logical actions”.

Repo: —

Tests: —

Status: n/a (informative) — transition without a logical action; T4 is what is observable.

§8.4.8.1 Table 8.63 best-effort StatelessWriter T3

Spec: §8.4.8.1, p. 88 — “[RL::unsent_changes() == false] … The transition performs no logical actions”.

Repo: —

Tests: —

Status: n/a (informative) — transition without a logical action.

§8.4.8.1 Table 8.63 best-effort StatelessWriter T4

Spec: §8.4.8.1, p. 88 — next unsent change; GAP for skipped numbers; “DATA = new DATA(a_change); IF (the_reader_locator.expectsInlineQos) { DATA.inlineQos := … } DATA.readerId := ENTITYID_UNKNOWN; sendto the_reader_locator.locator, DATA;”

Repo: crates/discovery/src/spdp.rs (SpdpBeacon::serialize: one DATA with a consecutive number per announcement)

Tests: crates/discovery/src/spdp.rs::tests::beacon_serializes_to_decodable_datagram

Status: done — the DATA carries readerId = ENTITYID_SPDP_BUILTIN_PARTICIPANT_DETECTOR instead of UNKNOWN (§8.3.8.2 allows either); since every number is sent, no GAP arises.

§8.4.8.1 Table 8.63 best-effort StatelessWriter T5

Spec: §8.4.8.1, pp. 88–89 — “the_rtps_writer.reader_locator_remove( the_reader_locator); delete the_reader_locator;”

Repo: —

Tests: —

Status: n/a (informative) — for SPDP the locators are configured and fixed (§8.5.3.1); a removal by discovery does not occur.

§8.4.8.2 Table 8.64 reliable StatelessWriter T1

Spec: §8.4.8.2, p. 90, Table 8.64 T1 — “a_locator := new ReaderLocator( locator, expectsInlineQos ); the_rtps_writer.reader_locator_add( a_locator );”

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::reader_locators_are_added_looked_up_and_removed

Status: done — reader_locator_add(locator, expects_inline_qos). ReliableStatelessWriter is used by no production path; no vendor is measured.

§8.4.8.2 Table 8.64 reliable StatelessWriter T2

Spec: §8.4.8.2, p. 90 — “[RL::unsent_changes() == true] … The transition performs no logical actions”.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::unsent_changes_are_pushed_in_order_then_announced

Status: done — unsent changes put the push machine in Pushing. ReliableStatelessWriter is used by no production path; no vendor is measured.

§8.4.8.2 Table 8.64 reliable StatelessWriter T3

Spec: §8.4.8.2, p. 90 — “[RL::unsent_changes == false] … The transition performs no logical actions”.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::unsent_changes_are_pushed_in_order_then_announced

Status: done — with no unsent changes the push machine goes to Announcing. ReliableStatelessWriter is used by no production path; no vendor is measured.

§8.4.8.2 Table 8.64 reliable StatelessWriter T4

Spec: §8.4.8.2, p. 91 — send the next unsent change as DATA with readerId := ENTITYID_UNKNOWN, a GAP for skipped numbers; postcondition higuest_sent_seq_num == a_change_seq_num.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::unsent_changes_are_pushed_in_order_then_announced, crates/rtps/src/reliable_stateless_writer.rs::tests::a_gap_precedes_the_data_after_a_hole_in_the_cache, crates/rtps/src/reliable_stateless_writer.rs::tests::the_related_qos_goes_out_with_the_data_only_where_it_is_expected, crates/rtps/src/reliable_stateless_writer.rs::tests::the_resend_per_tick_is_bounded

Status: done — the next unsent change goes as DATA with readerId = ENTITYID_UNKNOWN to the locator, preceded by a GAP with filteredCount = 0 over the missing numbers; inline QoS of the related DDS writer only with expectsInlineQos; RL::can_send() is the bound max_per_tick. ReliableStatelessWriter is used by no production path; no vendor is measured.

§8.4.8.2 Table 8.64 reliable StatelessWriter T5

Spec: §8.4.8.2, p. 91 — periodically “HEARTBEAT := new HEARTBEAT(the_rtps_writer.writerGuid, seq_num_min, seq_num_max); HEARTBEAT.FinalFlag := SET; HEARTBEAT.readerId := ENTITYID_UNKNOWN;”

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::an_announcing_locator_gets_a_final_heartbeat_each_period, crates/rtps/src/reliable_stateless_writer.rs::tests::a_heartbeat_of_an_empty_cache_has_first_after_last, crates/rtps/src/reliable_stateless_writer.rs::tests::the_heartbeat_count_wraps_at_u32_max

Status: done — HEARTBEAT with FinalFlag set and readerId = ENTITYID_UNKNOWN each heartbeatPeriod to an announcing locator; an empty cache announces firstSN = lastSN + 1. ReliableStatelessWriter is used by no production path; no vendor is measured.

§8.4.8.2 Table 8.64 reliable StatelessWriter T6

Spec: §8.4.8.2, pp. 91–92 — “FOREACH reply_locator_t IN { Receiver.unicastReplyLocatorList, Receiver.multicastReplyLocatorList } reader_locator := the_rtps_writer.reader_locator_lookup(reply_locator_t); reader_locator.requested_changes_set(ACKNACK.readerSNState.set);”

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::an_acknack_is_answered_at_its_reply_locator_after_the_delay, crates/rtps/src/reliable_stateless_writer.rs::tests::an_acknack_without_a_usable_reply_locator_is_counted

Status: done — an ACKNACK sets requested_changes_set(readerSNState) for each reply locator of the receiver state that names a port and is a ReaderLocator; an ACKNACK without a usable reply locator (no InfoReply) is counted (unmatched_acknacks). ReliableStatelessWriter is used by no production path; no vendor is measured.

§8.4.8.2 Table 8.64 reliable StatelessWriter T7

Spec: §8.4.8.2, p. 92 — “[RL::requested_changes() != ] … The transition performs no logical actions”.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::an_acknack_is_answered_at_its_reply_locator_after_the_delay

Status: done — requested changes put the repair machine in MustRepair. ReliableStatelessWriter is used by no production path; no vendor is measured.

§8.4.8.2 Table 8.64 reliable StatelessWriter T8

Spec: §8.4.8.2, p. 92 — “The transition performs the same logical actions performed by Transition T6”.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::an_acknack_is_answered_at_its_reply_locator_after_the_delay

Status: done — another ACKNACK in MustRepair is handled as in T6. ReliableStatelessWriter is used by no production path; no vendor is measured.

§8.4.8.2 Table 8.64 reliable StatelessWriter T9

Spec: §8.4.8.2, p. 92 — “triggered by the firing of a timer indicating that the duration of W::nackResponseDelay has elapsed since the state must_repair was entered.”

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::an_acknack_is_answered_at_its_reply_locator_after_the_delay

Status: done — after nackResponseDelay (set_nack_response_delay) the machine goes to Repairing. ReliableStatelessWriter is used by no production path; no vendor is measured.

§8.4.8.2 Table 8.64 reliable StatelessWriter T10 (DATA)

Spec: §8.4.8.2, p. 92 — “a_change_seq_num := the_reader_locator.next_requested_change(); … IF ( a_change != ) { DATA = new DATA(a_change); … DATA.readerId := ENTITYID_UNKNOWN; sendto the_reader_locator.locator, DATA; }”.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::an_acknack_is_answered_at_its_reply_locator_after_the_delay, crates/rtps/src/reliable_stateless_writer.rs::tests::the_related_qos_goes_out_with_the_data_only_where_it_is_expected

Status: done — next_requested_change goes as DATA with readerId = ENTITYID_UNKNOWN to the locator; inline QoS of the DDS writer and of the change with expectsInlineQos. ReliableStatelessWriter is used by no production path; no vendor is measured.

§8.4.8.2 Table 8.64 reliable StatelessWriter T10 (GAP)

Spec: §8.4.8.2, p. 92 — “ELSE { GAP = new GAP(a_change.sequenceNumber); GAP.readerId := ENTITYID_UNKNOWN; GAP.filteredCount := 0; sendto the_reader_locator.locator, GAP; }”.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::a_requested_change_that_left_the_cache_is_answered_by_a_gap

Status: done — a requested change that is no longer in the cache is answered with a GAP (filteredCount = 0). ReliableStatelessWriter is used by no production path; no vendor is measured.

§8.4.8.2 Table 8.64 reliable StatelessWriter T11

Spec: §8.4.8.2, p. 93 — “[RL::requested_changes() == ] … The transition performs no logical actions”.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::an_acknack_is_answered_at_its_reply_locator_after_the_delay

Status: done — with no requested changes the machine goes to Waiting. ReliableStatelessWriter is used by no production path; no vendor is measured.

§8.4.8.2 Table 8.64 reliable StatelessWriter T12

Spec: §8.4.8.2, p. 93 — “the_rtps_writer.reader_locator_remove( the_reader_locator); delete the_reader_locator;”

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::reader_locators_are_added_looked_up_and_removed

Status: done — reader_locator_remove deletes the ReaderLocator. ReliableStatelessWriter is used by no production path; no vendor is measured.

§8.4.9.1 Table 8.65 best-effort StatefulWriter T1

Spec: §8.4.9.1, p. 94, Table 8.65 T1 — “a_reader_proxy := new ReaderProxy( remoteReaderGuid, remoteGroupEntityId, expectsInlineQos, unicastLocatorList, multicastLocatorList); the_rtps_writer.matched_reader_add(a_reader_proxy);”

Repo: crates/rtps/src/reliable_writer.rs (add_reader_proxy with ReaderProxy::new(.., is_reliable: false)); crates/rtps/src/reader_proxy.rs (remote_group_entity_id); crates/dcps/src/runtime.rs (match path)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_best_effort_reader_matched_late_gets_the_next_write, crates/rtps/src/reader_proxy.rs::tests::the_remote_group_entity_id_is_kept, crates/dcps/src/runtime.rs::tests::the_proxies_of_a_match_carry_the_remote_group_entity_id

Status: done — matched_reader_add takes remoteGroupEntityId, expectsInlineQos and both locator lists.

§8.4.9.1 Table 8.65 best-effort StatefulWriter T2

Spec: §8.4.9.1, p. 94 — “[RP::unsent_changes() == true] … Note that for a Best-Effort Writer, W::pushMode == true … The transition performs no logical actions”.

Repo: —

Tests: —

Status: n/a (informative) — transition without a logical action.

§8.4.9.1 Table 8.65 best-effort StatefulWriter T3

Spec: §8.4.9.1, p. 94 — “[RP::unsent_changes() == false] … The transition performs no logical actions”.

Repo: —

Tests: —

Status: n/a (informative) — transition without a logical action.

§8.4.9.1 Table 8.65 best-effort StatefulWriter T4

Spec: §8.4.9.1, pp. 94–95 — next unsent change; a GAP with filteredCount 0 for skipped numbers; DATA if DDS_FILTER passes, otherwise a GAP with filteredCount 1; in-line QoS on expectsInlineQos; postcondition higuest_sent_seq_num == a_change_seq_num.

Repo: crates/rtps/src/reliable_writer.rs (write_sample_with_inline_qos, tick, append_change, is_relevant, passes_dds_filter, gap_filtered_count); crates/rtps/src/reader_proxy.rs (ChangeFilter, with_filter)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_best_effort_reader_matched_late_gets_the_next_write, crates/rtps/src/reliable_writer.rs::tests::a_best_effort_reader_matched_late_is_pushed_what_the_cache_holds, crates/rtps/src/reliable_writer.rs::tests::a_best_effort_reader_behind_is_pushed_gaps_with_the_filtered_count, crates/rtps/src/reliable_writer.rs::tests::a_change_that_fails_the_readers_filter_is_a_gap_with_filtered_count_one, crates/rtps/src/reliable_writer.rs::tests::a_gap_for_a_number_the_cache_no_longer_holds_has_filtered_count_zero, crates/rtps/src/reliable_writer.rs::tests::write_fans_out_to_all_reader_proxies

Status: done — a proxy in step gets every new change as DATA; one that is behind gets every change not yet sent as DATA in tick, a number the cache no longer holds as a GAP with filteredCount 0. If a change fails DDS_FILTER(the_reader_proxy, a_change) (ReaderProxy::with_filter), a GAP with filteredCount 1 goes out instead of the DATA. The runtime sets no filter (DDS_FILTER may be a no-op, §8.2.10.1); the behaviour against Cyclone DDS, Fast DDS and OpenDDS is not measured.

§8.4.9.1 Best-effort StatefulWriter: lagging proxy

Spec: §8.4.9.1, p. 95 — T4 sends next_unsent_change() to every proxy, “if ( a_change_seq_num > the_reader_proxy.higuest_sent_seq_num +1 ) { GAP = … }”.

Repo: crates/rtps/src/reliable_writer.rs (tick: next_unsent_change per best-effort proxy, append_change)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_best_effort_reader_matched_late_is_pushed_what_the_cache_holds

Status: done — a lagging best-effort proxy gets the changes not yet sent to it in order, unasked; a number the cache no longer holds as a GAP.

§8.4.9.1 Table 8.65 best-effort StatefulWriter T5

Spec: §8.4.9.1, pp. 95–96 — “ADD a_change TO the_rtps_writer.writer_cache;” postcondition “FOREACH proxy IN the_rtps_writer.matched_readers proxy.unsent_changes() == true”.

Repo: crates/rtps/src/reliable_writer.rs (stage_sample)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_fans_out_to_all_reader_proxies

Status: done

§8.4.9.1 Table 8.65 best-effort StatefulWriter T6

Spec: §8.4.9.1, p. 96 — “the_rtps_writer.matched_reader_remove( the_reader_proxy); delete the_reader_proxy;”

Repo: crates/rtps/src/reliable_writer.rs (remove_reader_proxy)

Tests: crates/rtps/src/reliable_writer.rs::tests::remove_reader_proxy_by_guid

Status: done

§8.4.9.2 Table 8.66 reliable StatefulWriter T1

Spec: §8.4.9.2, p. 98, Table 8.66 T1 — “a_reader_proxy := new ReaderProxy( remoteReaderGuid, remoteGroupEntityId, expectsInlineQos, unicastLocatorList, multicastLocatorList); the_rtps_writer.matched_reader_add(a_reader_proxy);”

Repo: crates/rtps/src/reliable_writer.rs (add_reader_proxy); crates/rtps/src/reader_proxy.rs (remote_group_entity_id); crates/dcps/src/runtime.rs (match path, skip_samples_up_to for VOLATILE)

Tests: crates/rtps/src/reliable_writer.rs::tests::heartbeat_after_add_reader_proxy_is_non_final, crates/rtps/src/reliable_writer.rs::tests::a_reader_matched_inside_an_open_coherent_set_gets_the_whole_set, crates/rtps/src/reader_proxy.rs::tests::the_remote_group_entity_id_is_kept, crates/dcps/src/runtime.rs::tests::the_proxies_of_a_match_carry_the_remote_group_entity_id

Status: done — matched_reader_add takes remoteGroupEntityId, expectsInlineQos and both locator lists.

§8.4.9.2 Table 8.66 reliable StatefulWriter T2

Spec: §8.4.9.2, pp. 98–99 — “[RP::unsent_changes() != ] … The transition performs no logical actions”.

Repo: —

Tests: —

Status: n/a (informative) — transition without a logical action.

§8.4.9.2 Table 8.66 reliable StatefulWriter T3

Spec: §8.4.9.2, p. 99 — “[RP::unsent_changes() == false] … The transition performs no logical actions”.

Repo: —

Tests: —

Status: n/a (informative) — transition without a logical action.

§8.4.9.2 Table 8.66 reliable StatefulWriter T4

Spec: §8.4.9.2, pp. 99–100 — the next unsent change as DATA (or a GAP if DDS_FILTER = false, filteredCount 1), a GAP for numbers removed from the cache (filteredCount 0); “DATA.readerId := ENTITYID_UNKNOWN; // or ReaderProxy.entityId”.

Repo: crates/rtps/src/reliable_writer.rs (write_sample_with_inline_qos, write_with_heartbeat_stamped; tick for lagging proxies)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_increments_sn_and_returns_data_datagram, crates/rtps/src/reliable_writer.rs::tests::repairs_in_order_bring_a_lagging_proxy_into_step, crates/rtps/src/reliable_writer.rs::tests::a_reliable_proxy_behind_the_cache_is_pushed_into_step, crates/rtps/src/reliable_writer.rs::tests::a_repair_out_of_order_is_followed_by_the_changes_before_it, crates/rtps/src/reliable_writer.rs::tests::a_reader_asking_for_a_replaced_change_gets_the_current_one

Status: done — write sends a change at once to the proxies in step; to a lagging proxy (a late joiner, or one whose request a GAP answered) tick under pushMode sends the unsent changes in order, DATA for those in the cache, GAP for those removed. A change repaired out of order in the same round does not go out twice.

§8.4.9.2 Table 8.66 reliable StatefulWriter T5

Spec: §8.4.9.2, p. 100 — “[RP::unacked_changes() == false] … The transition performs no logical actions”.

Repo: crates/rtps/src/reliable_writer.rs (tick: no periodic HEARTBEAT without unacknowledged changes)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_reader_that_acknowledged_the_cache_gets_no_periodic_heartbeat

Status: done

§8.4.9.2 Table 8.66 reliable StatefulWriter T6

Spec: §8.4.9.2, p. 100 — “[RP::unacked_changes() == true] … The transition performs no logical actions”.

Repo: crates/rtps/src/reliable_writer.rs (tick: announcing)

Tests: crates/rtps/src/reliable_writer.rs::tests::the_heartbeat_sent_with_a_change_is_answered_by_the_next_acknack

Status: done

§8.4.9.2 Table 8.66 reliable StatefulWriter T7

Spec: §8.4.9.2, p. 100 — “HEARTBEAT := new HEARTBEAT(the_rtps_writer.writerGuid, seq_num_min, seq_num_max); HEARTBEAT.FinalFlag := NOT_SET; HEARTBEAT.readerId := ENTITYID_UNKNOWN; send HEARTBEAT;”

Repo: crates/rtps/src/reliable_writer.rs (tick, append_heartbeat)

Tests: crates/rtps/src/reliable_writer.rs::tests::periodic_heartbeat_has_final_flag_unset, crates/rtps/src/reliable_writer.rs::tests::heartbeat_carries_cache_range

Status: done — the HEARTBEAT goes per proxy with its readerId; firstSN is max(seq_num_min, highest_acked + 1) of the proxy.

§8.4.9.2 Table 8.66 reliable StatefulWriter T8

Spec: §8.4.9.2, p. 100 — “the_rtps_writer.acked_changes_set( ACKNACK.readerSNState.base - 1); the_reader_proxy.requested_changes_set( ACKNACK.readerSNState.set);”

Repo: crates/rtps/src/reliable_writer.rs (handle_acknack_window)

Tests: crates/rtps/src/reliable_writer.rs::tests::handle_acknack_updates_proxy_state, crates/rtps/src/reliable_writer.rs::tests::handle_acknack_with_lower_base_leaves_requested

Status: done

§8.4.9.2 Table 8.66 reliable StatefulWriter T9

Spec: §8.4.9.2, p. 100 — “[RP::requested_changes() != ] … The transition performs no logical actions”.

Repo: —

Tests: —

Status: n/a (informative) — transition without a logical action.

§8.4.9.2 Table 8.66 reliable StatefulWriter T10

Spec: §8.4.9.2, p. 101 — “The transition performs the same logical actions as Transition T8”.

Repo: crates/rtps/src/reliable_writer.rs (handle_acknack_window)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_full_nack_window_gets_a_heartbeat_with_its_repair

Status: done

§8.4.9.2 Table 8.66 reliable StatefulWriter T11

Spec: §8.4.9.2, p. 101 — “triggered by the firing of a timer indicating that the duration of W::nackResponseDelay has elapsed since the state must_repair was entered.”

Repo: crates/rtps/src/reader_proxy.rs (repair_due, note_nack)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_repair_waits_for_the_nack_response_delay

Status: done

§8.4.9.2 Table 8.66 reliable StatefulWriter T12

Spec: §8.4.9.2, pp. 101–102 — the requested change from the cache as DATA (or a GAP with filteredCount 1 if DDS_FILTER = false), otherwise “GAP = new GAP(a_change.sequenceNumber, the_reader_proxy.remoteReaderGuid); GAP.filteredCount := 0;”; postcondition: the change is no longer requested.

Repo: crates/rtps/src/reliable_writer.rs (tick: append_data, append_lifecycle, append_gap)

Tests: crates/rtps/src/reliable_writer.rs::tests::tick_resends_requested_as_data_aggregated_with_hb, crates/rtps/src/reliable_writer.rs::tests::tick_resends_evicted_request_as_gap, crates/rtps/src/reliable_writer.rs::tests::lifecycle_repair_reproduces_the_key

Status: done — the GAP carries no filteredCount field; that equals a change not counted.

§8.4.9.2 Table 8.66 reliable StatefulWriter T13

Spec: §8.4.9.2, p. 102 — “[RP::requested_changes() == ] … The transition performs no logical actions”.

Repo: —

Tests: —

Status: n/a (informative) — transition without a logical action.

§8.4.9.2 Table 8.66 reliable StatefulWriter T14

Spec: §8.4.9.2, p. 102 — “ADD a_change TO the_rtps_writer.writer_cache;” postcondition: every proxy has unsent changes.

Repo: crates/rtps/src/reliable_writer.rs (stage_sample)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_fans_out_to_all_reader_proxies

Status: done

§8.4.9.2 Table 8.66 reliable StatefulWriter T15

Spec: §8.4.9.2, p. 102 — “triggered by the removal of a CacheChange ‘a_change’ from the HistoryCache of the RTPS Writer”.

Repo: crates/rtps/src/reliable_writer.rs (KEEP_LAST eviction in stage_sample, remove_acknowledged, remove_samples_up_to)

Tests: crates/rtps/src/reliable_writer.rs::tests::keep_last_stalled_reader_does_not_block_fresh_writes, crates/rtps/src/reliable_writer.rs::tests::tick_resends_evicted_request_as_gap

Status: done

§8.4.9.2 Table 8.66 reliable StatefulWriter T16

Spec: §8.4.9.2, p. 102 — “the_rtps_writer.matched_reader_remove( the_reader_proxy); delete the_reader_proxy;”

Repo: crates/rtps/src/reliable_writer.rs (remove_reader_proxy)

Tests: crates/rtps/src/reliable_writer.rs::tests::remove_reader_proxy_by_guid, crates/rtps/src/reliable_writer.rs::tests::the_unacked_window_fills_and_acknowledgements_free_it

Status: done

§8.4.10.1 Table 8.67 Reader heartbeatResponseDelay

Spec: §8.4.10.1, p. 103, Table 8.67 — “heartbeatResponseDelay: Protocol tuning parameter that allows the RTPS Reader to delay the sending of a positive or negative acknowledgment”.

Repo: crates/rtps/src/reliable_reader.rs (ReliableReaderConfig::heartbeat_response_delay, tick_outbound)

Tests: crates/rtps/src/reliable_reader.rs::tests::heartbeat_with_missing_triggers_acknack_after_delay

Status: done — its tunability for the user is listed under §8.4.2.1.

§8.4.10.1 Table 8.67 Reader heartbeatSuppressionDuration

Spec: §8.4.10.1, p. 103, Table 8.67 — “heartbeatSuppressionDuration: Protocol tuning parameter that allows the RTPS Reader to ignore HEARTBEATs that arrive ‘too soon’ after a previous HEARTBEAT was received.”

Repo: crates/rtps/src/reliable_reader.rs (set_heartbeat_suppression_duration, handle_heartbeat)

Tests: crates/rtps/src/reliable_reader.rs::tests::heartbeat_suppression_duration_ignores_a_heartbeat_that_arrives_too_soon

Status: done

§8.4.10.1 Table 8.67 Reader reader_cache

Spec: §8.4.10.1, p. 103, Table 8.67 — “reader_cache: History Cache — Contains the history of CacheChange changes for this RTPS Reader.”

Repo: crates/rtps/src/reliable_reader.rs (WriterProxyState::received_cache); crates/dcps/src/subscriber.rs (the DataReader’s sample store)

Tests: crates/rtps/src/reliable_reader.rs::tests::out_of_order_data_buffered_until_gap_filled, crates/rtps/src/reliable_reader.rs::tests::a_full_cache_takes_the_change_in_front_of_what_it_holds

Status: done

§8.4.10.1 Table 8.67 Reader expectsInlineQos

Spec: §8.4.10.1, p. 104, Table 8.67 — “expectsInlineQos: bool — Specifies whether the RTPS Reader expects in-line QoS to be sent along with any data.”

Repo: crates/rtps/src/subscription_data.rs (SubscriptionBuiltinTopicData::expects_inline_qos)

Tests: crates/rtps/src/subscription_data.rs::tests::expects_inline_qos_goes_out_when_set_and_reads_back

Status: done

§8.4.10.1 Default heartbeatResponseDelay = 500 ms

Spec: §8.4.10.1, p. 104 — “heartbeatResponseDelay.sec = 0; heartbeatResponseDelay.nanosec = 500 * 1000 * 1000; // 500 milliseconds”.

Repo: crates/rtps/src/reliable_reader.rs (DEFAULT_HEARTBEAT_RESPONSE_DELAY, SPEC_HEARTBEAT_RESPONSE_DELAY); crates/dcps/src/runtime.rs (RuntimeConfig::reader_heartbeat_response_delay)

Tests: crates/rtps/src/reliable_reader.rs::tests::default_heartbeat_suppression_duration_is_the_spec_zero, crates/dcps/tests/runtime_config_layering.rs::the_protocol_timing_parameters_are_settings

Status: done — DEFAULT_HEARTBEAT_RESPONSE_DELAY and RuntimeConfig::reader_heartbeat_response_delay are 500 ms; reader.heartbeat_response_delay_ms: 0 answers on the next tick.

§8.4.10.1 Default heartbeatResponseDelay

Spec: §8.4.10.1, p. 104 — “The following timing-related values are used as the defaults in order to facilitate ‘out-of-the-box’ interoperability between implementations.”

Repo: crates/rtps/src/reliable_reader.rs (DEFAULT_HEARTBEAT_RESPONSE_DELAY, DEFAULT_HEARTBEAT_SUPPRESSION_DURATION); crates/dcps/src/runtime.rs; crates/dcps/src/type_lookup_transport.rs; man/man5/zerodds.yaml.5; packaging/linux/configs/zerodds.yaml.example

Tests: crates/dcps/tests/runtime_config_layering.rs::the_protocol_timing_parameters_are_settings, crates/rtps/src/reliable_reader.rs::tests::default_heartbeat_suppression_duration_is_the_spec_zero

Status: done — the values of the spec are the defaults: heartbeatResponseDelay 500 ms, heartbeatSuppressionDuration 0 (runtime, man page, example configuration). The former 0 ms stay reachable through reader.heartbeat_response_delay_ms. §8.4.7.1 names no heartbeatPeriod; it stays 100 ms (writer.heartbeat_period_ms). The built-in readers of SEDP, secure volatile and TypeLookup use the same default.

§8.4.10.1 Default heartbeatSuppressionDuration = 0

Spec: §8.4.10.1, p. 104 — “heartbeatSuppressionDuration.sec = 0; heartbeatSuppressionDuration.nanosec = 0;”.

Repo: crates/rtps/src/reliable_reader.rs (DEFAULT_HEARTBEAT_SUPPRESSION_DURATION)

Tests: crates/rtps/src/reliable_reader.rs::tests::default_heartbeat_suppression_duration_is_the_spec_zero, crates/rtps/src/reliable_reader.rs::tests::heartbeat_storm_from_a_writer_that_never_fulfils_a_nack_cannot_arise, crates/discovery/src/sedp/reader.rs::tests::sedp_reader_does_not_storm_against_a_writer_that_never_delivers

Status: done — every reader runs with 0, the built-in ones of SEDP and VolatileSecure too. A writer that re-announces the same range at short intervals (HDDS 1.4.8: a HEARTBEAT [1,1] about every 1.5 ms) gets one response per heartbeatResponseDelay: the delay runs from the first HEARTBEAT that asks for a response.

§8.4.10.1 Table 8.68 Reader new

Spec: §8.4.10.1, p. 104 — takes over guid, locator lists, reliabilityLevel, topicKind, expectsInlineQos, heartbeatResponseDelay; “this.reader_cache := new HistoryCache;”

Repo: crates/rtps/src/reliable_reader.rs (ReliableReader::new)

Tests: crates/rtps/src/reliable_reader.rs::tests::add_writer_proxy_increases_count

Status: done

§8.4.10.2 Table 8.69 StatelessReader new

Spec: §8.4.10.2, pp. 104–105 — “The RTPS StatelessReader has no knowledge of the number of matched writers, nor does it maintain any state for each matched RTPS Writer.”

Repo: crates/rtps/src/reader.rs (BestEffortReader::new); crates/discovery/src/spdp.rs (SpdpReader::new)

Tests: crates/rtps/src/reader.rs::tests::reader_delivers_data_addressed_to_us, crates/discovery/src/spdp.rs::tests::reader_rejects_non_spdp_datagram

Status: done

§8.4.10.3 Table 8.70 StatefulReader matched_writers

Spec: §8.4.10.3, p. 105, Table 8.70 — “matched_writers: WriteProxy[*] — Used to maintain state on the remote Writers matched up with the Reader.”

Repo: crates/rtps/src/reliable_reader.rs (writer_proxies)

Tests: crates/rtps/src/reliable_reader.rs::tests::two_writers_with_overlapping_sn_spaces_both_delivered

Status: done

§8.4.10.3 Table 8.71 StatefulReader new

Spec: §8.4.10.3, pp. 105–106 — “this.matched_writers := ;”

Repo: crates/rtps/src/reliable_reader.rs (ReliableReader::new)

Tests: crates/rtps/src/reliable_reader.rs::tests::no_pre_emptive_acknack_without_proxy

Status: done

§8.4.10.3 Table 8.71 StatefulReader matched_writer_add

Spec: §8.4.10.3, p. 106 — “ADD a_writer_proxy TO {this.matched_writers};”

Repo: crates/rtps/src/reliable_reader.rs (add_writer_proxy)

Tests: crates/rtps/src/reliable_reader.rs::tests::add_writer_proxy_increases_count, crates/rtps/src/reliable_reader.rs::tests::re_adding_known_writer_preserves_reliability_state

Status: done

§8.4.10.3 Table 8.71 StatefulReader matched_writer_remove

Spec: §8.4.10.3, p. 106 — “REMOVE a_writer_proxy FROM {this.matched_writers}; delete a_writer_proxy;”

Repo: crates/rtps/src/reliable_reader.rs (remove_writer_proxy, depart_writer_proxy)

Tests: crates/rtps/src/reliable_reader.rs::tests::remove_writer_proxy_drops_its_state, crates/rtps/src/reliable_reader.rs::tests::a_departed_writer_leaves_its_held_samples_with_the_reader

Status: done

§8.4.10.3 Table 8.71 StatefulReader matched_writer_lookup

Spec: §8.4.10.3, p. 106 — “FIND proxy IN this.matched_writers SUCH-THAT (proxy.remoteWriterGuid == a_writer_guid); return proxy;”

Repo: crates/rtps/src/reliable_reader.rs (proxy_index_by_writer)

Tests: crates/rtps/src/reliable_reader.rs::tests::same_entity_id_different_prefix_not_confused

Status: done

§8.4.10.4 The WriterProxy follows the DDS match

Spec: §8.4.10.4, p. 106 — “The association is a consequence of the matching of the corresponding DDS Entities … the DDS DataReader matching a DDS DataWriter by Topic, having compatible QoS, belonging to a common partition, and not being explicitly ignored by the application that uses DDS.”

Repo: crates/dcps/src/runtime.rs (match path, add_writer_proxy); crates/dcps/src/participant.rs (ignore_publication)

Tests: crates/dcps/src/runtime.rs::tests::partition_mismatch_blocks_match_without_any_incompatible_qos_event, crates/dcps/src/participant.rs::tests::ignore_publication_records_handle

Status: done

§8.4.10.4 Table 8.72 WriterProxy remoteWriterGuid

Spec: §8.4.10.4, p. 106, Table 8.72 — “remoteWriterGuid: GUID_t — Identifies the matched Writer.”

Repo: crates/rtps/src/writer_proxy.rs (WriterProxy::remote_writer_guid)

Tests: crates/rtps/src/reliable_reader.rs::tests::same_entity_id_different_prefix_not_confused

Status: done

§8.4.10.4 Table 8.72 WriterProxy unicastLocatorList

Spec: §8.4.10.4, p. 106, Table 8.72 — “List of unicast (address, port) combinations that can be used to send messages to the matched Writer or Writers. The list may be empty.”

Repo: crates/rtps/src/writer_proxy.rs (WriterProxy::unicast_locators); crates/rtps/src/reliable_reader.rs (tick_outbound: ACKNACK to these locators)

Tests: crates/rtps/src/reliable_reader.rs::tests::tick_emits_one_acknack_per_writer_with_missing

Status: done

§8.4.10.4 Table 8.72 WriterProxy multicastLocatorList

Spec: §8.4.10.4, p. 106, Table 8.72 — “List of multicast (address, port) combinations that can be used to send messages to the matched Writer or Writers. The list may be empty.”

Repo: crates/rtps/src/writer_proxy.rs (WriterProxy::multicast_locators, refresh_locators)

Tests: crates/rtps/src/reliable_reader.rs::tests::re_adding_known_writer_preserves_reliability_state

Status: done — the list is kept; ACKNACKs go to the unicast locators.

§8.4.10.4 Table 8.72 WriterProxy dataMaxSizeSerialized

Spec: §8.4.10.4, p. 106, Table 8.72 — “Optional attribute that indicates the maximum size of any SerializedPayload that may be sent by the matched Writer.”

Repo: crates/rtps/src/reliable_reader.rs (set_writer_data_max_size, oversize_payload_count); crates/dcps/src/runtime.rs (wiring when the writer proxy is created, reader.honor_data_max_size_serialized)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_payload_beyond_the_announced_maximum_is_refused_and_counted, crates/dcps/tests/runtime_config_layering.rs::the_data_max_size_setting_is_on_by_default_and_read_from_yaml

Status: done — the reader takes the attribute from the announcement and refuses a SerializedPayload beyond it (after a protected payload is opened; the number counts as not available and the counter oversize_payload_count rises). A DATA_FRAG sample is checked once reassembled; AssemblerCaps still bounds the size of reassembled samples. The named setting reader.honor_data_max_size_serialized=false takes the payload anyway, for a writer that exceeds its own announcement (Fast DDS 3.6.1: 160 octets announced, 100 036 sent).

§8.4.10.4 Table 8.72 WriterProxy changes_from_writer

Spec: §8.4.10.4, p. 106, Table 8.72 — “List of CacheChange changes received or expected from the matched RTPS Writer.”

Repo: crates/rtps/src/writer_proxy.rs (known_up_to, received, irrelevant, first_available_sn, last_available_sn)

Tests: crates/rtps/src/writer_proxy.rs::tests::the_known_run_answers_as_the_sets_of_every_sn_did

Status: done — modelled as counters and sets (§8.4.15.1).

§8.4.10.4 Table 8.72 WriterProxy remoteGroupEntityId

Spec: §8.4.10.4, p. 107, Table 8.72 — “remoteGroupEntityId: EntityId_t — Identifies the group to which the matched Reader belongs”.

Repo: crates/rtps/src/writer_proxy.rs (WriterProxy::remote_group_entity_id, with_remote_group_entity_id); crates/dcps/src/runtime.rs (match path, PID_GROUP_GUID of the publication)

Tests: crates/rtps/src/writer_proxy.rs::tests::the_remote_group_entity_id_is_kept, crates/dcps/src/runtime.rs::tests::the_proxies_of_a_match_carry_the_remote_group_entity_id

Status: done — the proxy holds remoteGroupEntityId; the match path fills it from PID_GROUP_GUID of the writer’s SEDP announcement, ENTITYID_UNKNOWN without a group.

§8.4.10.4 Table 8.73 WriterProxy new

Spec: §8.4.10.4, p. 107 — “this.changes_from_writer := ; … initialized to UNKNOWN”.

Repo: crates/rtps/src/writer_proxy.rs (WriterProxy::new: first_available_sn = 1, last_available_sn = 0)

Tests: crates/rtps/src/writer_proxy.rs::tests::fresh_proxy_has_no_missing

Status: done

§8.4.10.4 Table 8.73 WriterProxy available_changes_max

Spec: §8.4.10.4, p. 108 — “seq_num := MAX { change.sequenceNumber SUCH-THAT ( change IN this.changes_from_writer AND ( change.status == RECEIVED OR change.status == NOT_AVAILABLE) ) }” provided that no smaller number is MISSING or UNKNOWN.

Repo: crates/rtps/src/writer_proxy.rs (available_changes_max)

Tests: crates/rtps/src/writer_proxy.rs::tests::available_changes_max_stops_at_the_first_hole, crates/rtps/src/writer_proxy.rs::tests::available_changes_max_passes_over_an_irrelevant_change

Status: done

§8.4.10.4 Table 8.73 WriterProxy not_available_change_set

Spec: §8.4.10.4, p. 108 — “IF ( filteredCount == COUNT(this. a_seq_num_set) ) THEN change.status := NA_FILTERED; ELSE IF ( filteredCount == 0) change.status := NA_REMOVED; ELSE change.status := NA_UNSPECIFIED;”

Repo: crates/rtps/src/writer_proxy.rs (NotAvailableKind, WriterProxy::not_available_change_set, not_available_count, change_status); crates/rtps/src/reliable_reader.rs (handle_gap, not_available_count)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_gap_sorts_its_changes_by_the_filtered_count, crates/rtps/src/reliable_reader.rs::tests::the_reader_keeps_the_status_of_each_change, crates/rtps/src/writer_proxy.rs::tests::change_status_is_kept_per_change_with_the_sub_kind

Status: done — filteredCount equal to the size of the set gives NA_FILTERED, 0 gives NA_REMOVED, anything between gives NA_UNSPECIFIED; the status is kept per change. A GAP without the FilteredCountFlag counts as 0 (assumption: the field is missing from peers before 2.5, whose GAP reports removed changes only; not measured against a vendor). A number already known is not counted or changed again.

§8.4.10.4 Table 8.73 WriterProxy lost_changes_update

Spec: §8.4.10.4, p. 108 — “FOREACH change IN this.changes_from_writer SUCH-THAT ( change.status == UNKNOWN OR change.status == MISSING AND seq_num < first_available_seq_num ) DO { change.status := NA_REMOVED; }”.

Repo: crates/rtps/src/writer_proxy.rs (lost_changes_update)

Tests: crates/rtps/src/writer_proxy.rs::tests::lost_changes_update_counts_what_was_neither_received_nor_irrelevant, crates/rtps/src/writer_proxy.rs::tests::lost_changes_update_retires_everything_below_the_new_base

Status: done

§8.4.10.4 Table 8.73 WriterProxy missing_changes

Spec: §8.4.10.4, p. 109 — “return { change IN this.changes_from_writer SUCH-THAT change.status == MISSING};”

Repo: crates/rtps/src/writer_proxy.rs (missing_changes)

Tests: crates/rtps/src/writer_proxy.rs::tests::missing_changes_respects_max_count, crates/rtps/src/writer_proxy.rs::tests::received_removes_from_missing

Status: done

§8.4.10.4 Table 8.73 WriterProxy missing_changes_update

Spec: §8.4.10.4, p. 109 — “FOREACH change IN this.changes_from_writer SUCH-THAT ( change.status == UNKNOWN AND seq_num <= last_available_seq_num ) DO { change.status := MISSING; }”.

Repo: crates/rtps/src/writer_proxy.rs (update_from_heartbeat: last_available_sn)

Tests: crates/rtps/src/writer_proxy.rs::tests::heartbeat_sets_available_range

Status: done

§8.4.10.4 Table 8.73 WriterProxy received_change_set

Spec: §8.4.10.4, p. 109 — “FIND change FROM this.changes_from_writer SUCH-THAT change.sequenceNumber == a_seq_num; change.status := RECEIVED”.

Repo: crates/rtps/src/writer_proxy.rs (received_change_set)

Tests: crates/rtps/src/writer_proxy.rs::tests::received_removes_from_missing, crates/rtps/src/writer_proxy.rs::tests::received_before_first_is_ignored

Status: done

§8.4.10.5 Table 8.74 ChangeFromWriter status

Spec: §8.4.10.5, pp. 109–110, Table 8.74 — “status: ChangeFromWriter StatusKind — Indicates the status of a CacheChange relative to the RTPS Writer represented by the WriterProxy.” Values UNKNOWN, MISSING, RECEIVED, NOT_AVAILABLE with the sub-kinds NA_FILTERED, NA_REMOVED, NA_UNSPECIFIED.

Repo: crates/rtps/src/writer_proxy.rs (ChangeFromWriterStatus, change_status, is_known, missing_changes, not_available_count)

Tests: crates/rtps/src/writer_proxy.rs::tests::change_status_is_kept_per_change_with_the_sub_kind, crates/rtps/src/writer_proxy.rs::tests::lost_changes_update_sets_na_removed_per_change, crates/rtps/src/reliable_reader.rs::tests::the_reader_keeps_the_status_of_each_change, crates/rtps/src/reliable_reader.rs::tests::a_gap_sorts_its_changes_by_the_filtered_count

Status: done — the four main values and the three sub-kinds of NOT_AVAILABLE are kept per change (item under §8.4.6 Table 8.52 ChangeFromWriterStatusKind).

§8.4.10.5 Table 8.74 ChangeFromWriter is_relevant

Spec: §8.4.10.5, p. 109, Table 8.74 — “is_relevant: bool — Indicates whether the change is relevant to the RTPS Reader. The determination of relevant changes is affected by DDS DataReader TIME_BASED_FILTER QoS and also by the use of DDS ContentFilteredTopics.”

Repo: crates/rtps/src/history_cache.rs (ChangeKind::is_relevant, ChangeKind::AliveFiltered); crates/dcps/src/runtime.rs (tbf_should_deliver)

Tests: crates/rtps/src/history_cache.rs::tests::change_kind_alive_filtered_is_alive_but_not_relevant

Status: done

§8.4.11.1 Table 8.75 best-effort StatelessReader T1

Spec: §8.4.11.1, pp. 110–111, Table 8.75 T1 — “triggered by the creation of an RTPS StatelessReader … The transition performs no logical actions”.

Repo: —

Tests: —

Status: n/a (informative) — transition without a logical action.

§8.4.11.1 Table 8.75 best-effort StatelessReader T2

Spec: §8.4.11.1, p. 111 — “a_change := new CacheChange(DATA); the_rtps_reader.reader_cache.add_change(a_change);”

Repo: crates/discovery/src/spdp.rs (SpdpReader::samples); crates/rtps/src/reader.rs (BestEffortReader::recv_datagram)

Tests: crates/discovery/src/spdp.rs::tests::samples_reads_every_participant_a_datagram_bundles, crates/rtps/src/reader.rs::tests::reader_handles_multiple_data_in_one_datagram

Status: done

§8.4.11.1 Table 8.75 best-effort StatelessReader T3

Spec: §8.4.11.1, p. 111 — “triggered by the destruction of an RTPS Reader … The transition performs no logical actions”.

Repo: —

Tests: —

Status: n/a (informative) — transition without a logical action.

§8.4.11.2 Reliable StatelessReader not supported

Spec: §8.4.11.2, p. 111 — “This combination is not supported by the RTPS protocol.”

Repo: —

Tests: —

Status: n/a (informative) — no requirement; ZeroDDS has no reliable StatelessReader.

§8.4.12.1 Table 8.76 best-effort StatefulReader T1

Spec: §8.4.12.1, p. 112, Table 8.76 T1 — “a_writer_proxy := new WriterProxy(remoteWriterGuid, remoteGroupEntityId, unicastLocatorList, multicastLocatorList); the_rtps_reader.matched_writer_add(a_writer_proxy);”

Repo: crates/rtps/src/reliable_reader.rs (add_writer_proxy, set_best_effort); crates/rtps/src/writer_proxy.rs (remote_group_entity_id)

Tests: crates/rtps/src/reliable_reader.rs::tests::best_effort_reader_skips_leading_gap, crates/rtps/src/writer_proxy.rs::tests::the_remote_group_entity_id_is_kept, crates/dcps/src/runtime.rs::tests::the_proxies_of_a_match_carry_the_remote_group_entity_id

Status: done — matched_writer_add takes remoteGroupEntityId and both locator lists.

§8.4.12.1 Table 8.76 best-effort StatefulReader T2

Spec: §8.4.12.1, p. 113 — “expected_seq_num := writer_proxy.available_changes_max() + 1; if ( a_change.sequenceNumber >= expected_seq_num ) { … add_change(a_change); received_change_set(…); if ( a_change.sequenceNumber > expected_seq_num ) { lost_changes_update(…) } }”.

Repo: crates/rtps/src/reliable_reader.rs (handle_data_into: gap_skipped, lost_changes_update with best_effort)

Tests: crates/rtps/src/reliable_reader.rs::tests::best_effort_reader_skips_leading_gap, crates/rtps/src/reliable_reader.rs::tests::duplicate_data_is_rejected, crates/rtps/src/reliable_reader.rs::tests::a_best_effort_reader_counts_the_samples_a_gap_lost

Status: done

§8.4.12.1 Table 8.76 best-effort StatefulReader T3

Spec: §8.4.12.1, p. 113 — “the_rtps_reader.matched_writer_remove( the_writer_proxy); delete the_writer_proxy;”

Repo: crates/rtps/src/reliable_reader.rs (remove_writer_proxy)

Tests: crates/rtps/src/reliable_reader.rs::tests::remove_writer_proxy_drops_its_state

Status: done

§8.4.12.1 Table 8.76 best-effort StatefulReader T4

Spec: §8.4.12.1, p. 113 — “the_writer_proxy.not_available_change_set(GAP. sequence_number_set, GAP.filteredCount);”

Repo: crates/rtps/src/reliable_reader.rs (handle_gap)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_best_effort_reader_counts_the_samples_a_gap_lost, crates/rtps/src/reliable_reader.rs::tests::a_gap_sorts_its_changes_by_the_filtered_count, crates/rtps/src/reliable_reader.rs::tests::the_reader_keeps_the_status_of_each_change

Status: done — the numbers of the GAP are marked not available with the sub-kind given by filteredCount and are kept per change.

§8.4.12.2 Table 8.77 reliable StatefulReader T1

Spec: §8.4.12.2, pp. 114–115, Table 8.77 T1 — “a_writer_proxy := new WriterProxy(remoteWriterGuid, remoteGroupEntityId, unicastLocatorList, multicastLocatorList); the_rtps_reader.matched_writer_add(a_writer_proxy);”

Repo: crates/rtps/src/reliable_reader.rs (add_writer_proxy); crates/rtps/src/writer_proxy.rs (remote_group_entity_id)

Tests: crates/rtps/src/reliable_reader.rs::tests::add_writer_proxy_increases_count, crates/rtps/src/reliable_reader.rs::tests::changes_a_writer_sent_before_the_match_are_requested_at_once, crates/rtps/src/writer_proxy.rs::tests::the_remote_group_entity_id_is_kept, crates/dcps/src/runtime.rs::tests::the_proxies_of_a_match_carry_the_remote_group_entity_id

Status: done — matched_writer_add takes remoteGroupEntityId and both locator lists.

§8.4.12.2 Table 8.77 reliable StatefulReader T2

Spec: §8.4.12.2, p. 114 — HEARTBEAT received: “if (HB.FinalFlag == NOT_SET) then must_send_ack else if (HB.LivelinessFlag == NOT_SET) then may_send_ack else waiting”.

Repo: —

Tests: crates/rtps/src/reliable_reader.rs::tests::a_heartbeat_with_the_liveliness_flag_is_taken_as_a_heartbeat

Status: done

§8.4.12.2 Table 8.77 reliable StatefulReader T3

Spec: §8.4.12.2, p. 115 — “[W::missing_changes() == ] … The transition performs no logical actions.”

Repo: crates/rtps/src/reliable_reader.rs (handle_heartbeat: no ACKNACK on F = 1 with nothing missing)

Tests: crates/rtps/src/reliable_reader.rs::tests::heartbeat_without_missing_and_final_schedules_no_acknack

Status: done

§8.4.12.2 Table 8.77 reliable StatefulReader T4

Spec: §8.4.12.2, p. 115 — “[W::missing_changes() != ] … The transition performs no logical actions.”

Repo: crates/rtps/src/reliable_reader.rs (handle_heartbeat: has_missing sets pending_acknack_since)

Tests: crates/rtps/src/reliable_reader.rs::tests::final_heartbeat_from_unknown_to_data_writer_requests_the_missing_sn

Status: done

§8.4.12.2 Table 8.77 reliable StatefulReader T5

Spec: §8.4.12.2, pp. 115–116 — after heartbeatResponseDelay “missing_seq_num_set.base := the_writer_proxy.available_changes_max() + 1; … send ACKNACK(missing_seq_num_set);” — with too many missing numbers “the subset with smallest value of the sequence number”.

Repo: crates/rtps/src/reliable_reader.rs (tick_outbound, build_acknack_datagram); crates/rtps/src/submessages.rs (SequenceNumberSet::from_missing)

Tests: crates/rtps/src/reliable_reader.rs::tests::heartbeat_with_missing_triggers_acknack_after_delay, crates/rtps/src/submessages.rs::tests::snset_from_missing_spread_wide_stays_within_256_bits, crates/rtps/src/reliable_reader.rs::tests::a_partly_received_sample_is_asked_for_by_nack_frag_not_acknack

Status: done — base and smallest subset are right; the set holds only numbers of which no fragment has arrived (NACK_FRAG asks for the others, §8.4.14.1).

§8.4.12.2 Table 8.77 reliable StatefulReader T6

Spec: §8.4.12.2, p. 116 — “Similar to T1 … The transition performs no logical actions in the virtual machine.”

Repo: —

Tests: —

Status: n/a (informative) — transition without a logical action.

§8.4.12.2 Table 8.77 reliable StatefulReader T7

Spec: §8.4.12.2, p. 116 — “the_writer_proxy.missing_changes_update( HEARTBEAT.lastSN); the_writer_proxy.lost_changes_update(HEARTBEAT.firstSN, true);”

Repo: crates/rtps/src/writer_proxy.rs (update_from_heartbeat)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_heartbeat_with_the_liveliness_flag_is_taken_as_a_heartbeat

Status: done

§8.4.12.2 Table 8.77 reliable StatefulReader T8

Spec: §8.4.12.2, p. 116 — “a_change := new CacheChange(DATA); the_reader.reader_cache.add_change(a_change); the_writer_proxy.received_change_set(a_change.sequenceNumber);”

Repo: crates/rtps/src/reliable_reader.rs (handle_data_into, store_received)

Tests: crates/rtps/src/reliable_reader.rs::tests::in_order_data_delivered_immediately, crates/rtps/src/reliable_reader.rs::tests::out_of_order_data_buffered_until_gap_filled

Status: done

§8.4.12.2 Table 8.77 reliable StatefulReader T9

Spec: §8.4.12.2, p. 116 — “the_writer_proxy.not_available_change_set(GAP. sequence_number_set, GAP.filteredCount);”

Repo: crates/rtps/src/reliable_reader.rs (handle_gap)

Tests: crates/rtps/src/reliable_reader.rs::tests::gap_after_the_held_data_releases_it, crates/rtps/src/reliable_reader.rs::tests::a_gap_sorts_its_changes_by_the_filtered_count, crates/rtps/src/reliable_reader.rs::tests::the_reader_keeps_the_status_of_each_change

Status: done — filteredCount is evaluated (item under §8.4.10.4 Table 8.73 WriterProxy not_available_change_set); the numbers are held per change as NOT_AVAILABLE.

§8.4.12.2 Table 8.77 reliable StatefulReader T10

Spec: §8.4.12.2, p. 116 — “the_rtps_reader.matched_writer_remove( the_writer_proxy); delete the_writer_proxy;”

Repo: crates/rtps/src/reliable_reader.rs (remove_writer_proxy, depart_writer_proxy)

Tests: crates/rtps/src/reliable_reader.rs::tests::remove_writer_proxy_drops_its_state, crates/rtps/src/reliable_reader.rs::tests::a_departed_writer_counts_what_is_missing_in_front_of_its_held_samples

Status: done

§8.4.12.3 ChangeFromWriter illustrated

Spec: §8.4.12.3, pp. 117–118, Figure 8.25 — states Unknown, Missing, NotRequested, Requested, Received, NotAvailable (Filtered, Removed, Unspecified) and the events that trigger them.

Repo: —

Tests: —

Status: n/a (informative) — illustrates the transitions of §8.4.10.4 and §8.4.12.2 (“It is illustrative”); no requirement of its own.

§8.4.13 Writer Liveliness Protocol: support is mandatory

Spec: §8.4.13, p. 118 — “All implementations must support the Writer Liveliness Protocol in order to be interoperable.”

Repo: crates/dcps/src/wlp.rs (WlpEndpoint); crates/dcps/src/runtime.rs (DcpsRuntime::wlp)

Tests: crates/dcps/tests/wlp_integration.rs::linux_only::two_participants_exchange_automatic_wlp_heartbeats, crates/dcps/src/runtime.rs::tests::two_runtimes_exchange_wlp_heartbeat, crates/dcps/src/wlp.rs::tests::a_late_reader_is_told_by_heartbeat_and_gets_the_held_samples_on_request, crates/dcps/src/wlp.rs::tests::the_reader_is_treated_as_builtin_endpoint_qos_says

Status: done — writer and reader of the protocol run in every participant; the writer has the QoS of §8.4.13.3 and treats the reader as builtinEndpointQos says. The writer’s wire change is not measured against Cyclone, Fast DDS, OpenDDS and RTI.

§8.4.13.1 Association with the built-in endpoints of a discovered participant

Spec: §8.4.13.1, p. 118 — “once a Participant knows of the presence of another Participant, it can assume the presence of the built-in Endpoints made available by the remote Participant and establish the association with the locally matching built-in Endpoints.”

Repo: crates/dcps/src/wlp.rs (WlpEndpoint::add_peer_reader); crates/dcps/src/runtime.rs (spdp_announced, wlp_unicast_targets, answer_wlp_heartbeats)

Tests: crates/dcps/src/runtime.rs::tests::wlp_unicast_targets_prefers_metatraffic_then_default, crates/dcps/src/runtime.rs::tests::two_runtimes_assert_liveliness_reaches_peer, crates/dcps/src/wlp.rs::tests::only_a_participant_with_a_message_reader_gets_a_proxy

Status: done — every SPDP announcement makes (unchanged: keeps) a reader proxy for the participant’s BuiltinParticipantMessageReader when its availableBuiltinEndpoints name it; the target is its metatraffic locators.

§8.4.13.1 The same protocol as for application-defined endpoints

Spec: §8.4.13.1, p. 118 — “The protocol used to communicate between built-in Endpoints is the same as used for application-defined Endpoints.”

Repo: crates/dcps/src/wlp.rs (WlpEndpoint: make_writer, write_pulse, add_peer_reader, handle_reader_messages, tick); crates/dcps/src/runtime.rs (WLP-Tick, spdp_announced)

Tests: crates/dcps/src/wlp.rs::tests::a_late_reader_is_told_by_heartbeat_and_gets_the_held_samples_on_request, crates/dcps/src/wlp.rs::tests::the_writer_heartbeats_until_the_reader_has_acknowledged

Status: done — the WLP writer is a ReliableWriter with a reader proxy per participant: DATA with a piggyback HEARTBEAT, periodic HEARTBEATs until acknowledged, repair of what was asked for only, GAP for superseded numbers. The reader answers HEARTBEATs (heartbeat_responses) and keeps the highest sequence number received per writer.

§8.4.13.2 Built-in endpoints BuiltinParticipantMessageWriter and -Reader

Spec: §8.4.13.2, p. 118 — “The RTPS Protocol reserves the following values of the EntityId_t for these built-in Endpoints: ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER”

Repo: crates/rtps/src/wire_types.rs (EntityId::BUILTIN_PARTICIPANT_MESSAGE_WRITER, EntityId::BUILTIN_PARTICIPANT_MESSAGE_READER); crates/dcps/src/wlp.rs (WlpEndpoint::handle_datagram)

Tests: crates/dcps/src/wlp.rs::tests::wlp_handle_datagram_updates_peer_state, crates/dcps/src/wlp.rs::tests::wlp_handle_datagram_ignores_non_wlp_traffic

Status: done — the values are listed under §9.3.1.3.

§8.4.13.3 Writer durability.kind = TRANSIENT_LOCAL

Spec: §8.4.13.3, p. 118 — “both the BuiltinParticipantMessageWriter and BuiltinParticipantMessageReader shall use the following QoS values: durability.kind = TRANSIENT_LOCAL_DURABILITY”.

Repo: crates/dcps/src/wlp.rs (WlpEndpoint: make_writer, write_pulse, add_peer_reader, handle_reader_messages, tick); crates/dcps/src/runtime.rs (WLP-Tick, spdp_announced)

Tests: crates/dcps/src/wlp.rs::tests::a_late_reader_is_told_by_heartbeat_and_gets_the_held_samples_on_request

Status: done — a reader that comes later gets the held samples with the first tick, without asking (the history keeps one sample per kind, so a request would meet a newer sample), and a HEARTBEAT says what the history holds; asking again it gets them once more.

§8.4.13.3 Writer history KEEP_LAST, depth 1

Spec: §8.4.13.3, pp. 118–119 — “history.kind = KEEP_LAST_HISTORY_QOS”, “history.depth = 1”.

Repo: crates/dcps/src/wlp.rs (WlpEndpoint: make_writer, write_pulse, add_peer_reader, handle_reader_messages, tick); crates/dcps/src/runtime.rs (WLP-Tick, spdp_announced)

Tests: crates/dcps/src/wlp.rs::tests::the_history_holds_the_last_sample_of_each_kind

Status: done — the history holds the last sample of each instance (participantGuidPrefix, kind; PID_KEY_HASH in the in-line QoS); superseded samples are not repeated.

§8.4.13.3 Reader durability.kind = TRANSIENT_LOCAL

Spec: §8.4.13.3, p. 118 — “both the BuiltinParticipantMessageWriter and BuiltinParticipantMessageReader shall use the following QoS values: durability.kind = TRANSIENT_LOCAL_DURABILITY”.

Repo: crates/dcps/src/wlp.rs (WlpEndpoint::heartbeat_responses: the request starts at the HEARTBEAT’s firstSN, not at the match)

Tests: crates/dcps/src/wlp.rs::tests::a_heartbeat_announcing_a_pulse_not_received_is_answered_with_a_request_for_it, crates/dcps/tests/cyclone_live_wlp.rs::cyclone_live_wlp_handshake

Status: done

§8.4.13.3 Reader history KEEP_LAST, depth 1

Spec: §8.4.13.3, pp. 118–119 — “history.kind = KEEP_LAST_HISTORY_QOS”, “history.depth = 1”.

Repo: crates/dcps/src/wlp.rs (WlpEndpoint::peers: per participant the state last received)

Tests: crates/dcps/src/wlp.rs::tests::wlp_handle_datagram_updates_peer_state

Status: done — the reader keeps no samples; it hands every sample received at once to the DataReaders’ liveliness bookkeeping and keeps last_seen and last_kind per participant.

§8.4.13.3 Writer reliability.kind = RELIABLE

Spec: §8.4.13.3, p. 119 — “The BuiltinParticipantMessageWriter shall use reliability.kind = RELIABLE_RELIABILITY_QOS.”

Repo: crates/dcps/src/wlp.rs (WlpEndpoint: make_writer, write_pulse, add_peer_reader, handle_reader_messages, tick); crates/dcps/src/runtime.rs (WLP-Tick, spdp_announced)

Tests: crates/dcps/src/wlp.rs::tests::the_writer_heartbeats_until_the_reader_has_acknowledged, crates/dcps/src/wlp.rs::tests::a_late_reader_is_told_by_heartbeat_and_gets_the_held_samples_on_request

Status: done — the writer keeps state per reader (reader proxy), sends HEARTBEATs until acknowledged and repairs on ACKNACK (handle_reader_messages).

§8.4.13.3 Reader RELIABLE or BEST_EFFORT

Spec: §8.4.13.3, p. 119 — “The BuiltinParticipantMessageReader may be configured to use either RELIABLE_RELIABILITY_QOS or BEST_EFFORT_RELIABILITY_QOS. If the BuiltinParticipantMessageReader is configured to use BEST_EFFORT_RELIABILITY_QOS then the BEST_EFFORT_PARTICIPANT_MESSAGE_DATA_READER flag in ParticipantProxy::builtinEndpointQos shall be set.”

Repo: crates/dcps/src/wlp.rs (WlpEndpoint::heartbeat_responses)

Tests: crates/dcps/src/wlp.rs::tests::a_heartbeat_announcing_a_pulse_not_received_is_answered_with_a_request_for_it, crates/dcps/src/wlp.rs::tests::once_the_pulse_arrived_a_final_heartbeat_gets_no_answer_and_a_plain_one_the_ack

Status: done — the reader answers HEARTBEATs as a RELIABLE reader does; the flag does not apply, ZeroDDS sends no PID_BUILTIN_ENDPOINT_QOS.

§8.4.13.3 The writer treats the reader by builtinEndpointQos

Spec: §8.4.13.3, p. 119 — “If the ParticipantProxy::builtinEndpointQos is included in the SPDPdiscoveredParticipantData, then the BuiltinParticipantMessageWriter shall treat the BuiltinParticipantMessageReader as indicated by the flags. If the ParticipantProxy::builtinEndpointQos is not included then the BuiltinParticipantMessageWriter shall treat the BuiltinParticipantMessageReader as if it is configured with RELIABLE_RELIABILITY_QOS.”

Repo: crates/dcps/src/wlp.rs (WlpEndpoint::add_peer_reader, sync_proxy); crates/dcps/src/runtime.rs (spdp_announced)

Tests: crates/dcps/src/wlp.rs::tests::the_reader_is_treated_as_builtin_endpoint_qos_says

Status: done — with builtinEndpointQos and the flag the reader is a best-effort proxy (no HEARTBEATs), otherwise RELIABLE.

§8.4.13.4 Figure 8.26 ParticipantMessageData

Spec: §8.4.13.4, p. 119, Figure 8.26 — “Figure 8.26 defines the ParticipantMessageData datatype associated with the RTPS built-in Endpoint for the DCPSParticipantMessage Topic.” Attributes participantGuidPrefix, kind, data.

Repo: crates/rtps/src/participant_message_data.rs (ParticipantMessageData, to_cdr, from_cdr)

Tests: crates/rtps/src/participant_message_data.rs::tests::participant_message_data_octets_are_those_of_9_6_3_1, crates/rtps/src/participant_message_data.rs::tests::participant_message_data_reads_the_fast_dds_beat, crates/rtps/src/participant_message_data.rs::tests::participant_message_data_roundtrip_with_topic_token

Status: done

§8.4.13.5 AUTOMATIC: a sample faster than the shortest lease

Spec: §8.4.13.5, p. 119 — “If the Participant contains one or more Writers with a liveliness of AUTOMATIC_LIVELINESS_QOS, then one sample is written at a rate faster than the smallest lease duration among the Writers sharing this QoS.”

Repo: crates/dcps/src/runtime.rs (refresh_wlp_period: a third of the shortest finite lease of an AUTOMATIC writer, at most a third of the participant lease); crates/dcps/src/wlp.rs (WlpEndpoint::tick)

Tests: crates/dcps/tests/liveliness_qos.rs::linux::an_automatic_writer_that_never_writes_stays_alive_at_a_remote_reader, crates/dcps/src/wlp.rs::tests::wlp_tick_emits_again_after_period, crates/dcps/src/runtime.rs::tests::wlp_period_default_is_lease_over_three

Status: done — the AUTOMATIC sample also goes out without an AUTOMATIC writer.

§8.4.13.5 MANUAL_BY_PARTICIPANT: a separate sample

Spec: §8.4.13.5, p. 119 — “Similarly, a separate sample is written if the Participant contains one or more Writers with a liveliness of MANUAL_BY_PARTICIPANT_LIVELINESS_QOS at a rate faster than the smallest lease duration among these Writers.”

Repo: crates/dcps/src/runtime.rs (DcpsRuntime::assert_liveliness, refresh_manual_by_participant); crates/dcps/src/wlp.rs (WlpEndpoint::assert_participant, refresh_participant)

Tests: crates/dcps/src/wlp.rs::tests::wlp_assert_participant_emits_manual_pulse, crates/dcps/src/wlp.rs::tests::refreshes_before_the_tick_share_one_manual_by_participant_sample, crates/dcps/tests/wlp_integration.rs::linux_only::manual_by_participant_pulse_arrives_at_peer, crates/dcps/src/runtime.rs::tests::a_manual_by_participant_writer_refreshes_the_participant_liveliness

Status: done — the sample is written by DomainParticipant::assert_liveliness and by write, assert_liveliness, dispose and unregister_instance of a MANUAL_BY_PARTICIPANT writer; calls before the tick share one sample.

§8.4.13.5 Two instances, key participantGuidPrefix and kind

Spec: §8.4.13.5, p. 119 — “The instances are distinguished using their DDS key, which is comprised of the participantGuidPrefix and kind fields. Each of the two types of liveliness QoS handled through this protocol will result in a unique kind field and therefore form two distinct instances in the HistoryCache.”

Repo: crates/dcps/src/wlp.rs (WlpEndpoint::write_pulse)

Tests: crates/dcps/src/wlp.rs::tests::the_history_holds_the_last_sample_of_each_kind, crates/dcps/src/wlp.rs::tests::wlp_assert_participant_emits_manual_pulse, crates/dcps/src/wlp.rs::tests::wlp_handle_datagram_updates_peer_state

Status: done — the instance is (participantGuidPrefix, kind); the KeyHash (12 octets of prefix, 4 octets of kind, big endian) is PID_KEY_HASH in the in-line QoS of every DATA, and the history holds one sample per instance.

§8.4.13.5 participantGuidPrefix of the writing participant

Spec: §8.4.13.5, p. 119 — “In both liveliness cases the participantGuidPrefix field contains the GuidPrefix_t of the Participant that is writing the data (and therefore asserting the liveliness of its Writers).”

Repo: crates/dcps/src/wlp.rs (WlpEndpoint::encode_pulse: ParticipantMessageData::automatic(self.own_prefix))

Tests: crates/dcps/src/wlp.rs::tests::wlp_handle_datagram_updates_peer_state, crates/rtps/src/participant_message_data.rs::tests::participant_message_data_automatic_default_data_empty

Status: done

§8.4.13.5 MANUAL_BY_TOPIC not through the BuiltinParticipantMessageWriter

Spec: §8.4.13.5, p. 119 — “The DDS liveliness kind MANUAL_BY_TOPIC_LIVELINESS_QOS is not implemented using the BuiltinParticipantMessageWriter and BuiltinParticipantMessageReader. It is discussed in 8.7.2.2.3.”

Repo: crates/dcps/src/publisher.rs (DataWriter::assert_liveliness → DcpsRuntime::assert_writer_liveliness_eid: HEARTBEAT with the LivelinessFlag)

Tests: crates/dcps/src/runtime.rs::tests::assert_liveliness_keeps_a_manual_writer_alive_without_writing, crates/rtps/src/reliable_writer.rs::tests::liveliness_heartbeat_is_a_final_heartbeat_with_the_liveliness_flag

Status: done — DcpsRuntime::assert_writer_liveliness also writes a sample with the vendor kind 0x80000001; the DCPS API does not call it.

§8.4.14 Optional behavior

Spec: §8.4.14, p. 119 — “Optional features may not be supported by all RTPS implementations. An optional feature does not affect basic interoperability, but is only available if all implementations involved support it.”

Repo: —

Tests: —

Status: n/a (informative) — classification of the following subclauses, no requirement.

§8.4.14.1 Large Data: transport limits and fragment submessages

Spec: §8.4.14.1, p. 120 — “a transport may impose its own limitations. For example, it may limit the maximum packet size (e.g., 64K for UDP) … 8.3.8 introduces the following Submessages to enable fragmenting large data: DataFrag, HeartbeatFrag, NackFrag”.

Repo: —

Tests: —

Status: n/a (informative) — rationale, no requirement; the submessages are listed under §8.3.8.

§8.4.14.1 Fragment size from the writer’s transports

Spec: §8.4.14.1, p. 120 — “All transports available to the Writer must be able to accommodate DataFrag Submessages containing at least one fragment. This means the transport with the smallest maximum message size determines the fragment size.” “Note the fragment size is determined by all transports available to the Writer, not simply the subset of transports required to reach all currently known Readers.”

Repo: crates/transport/src/lib.rs (Transport::max_message_size, DEFAULT_MAX_MESSAGE_SIZE); crates/transport-udp/src/udp_transport.rs (UdpTransportConfig::max_message_size); crates/transport-shm, transport-uds, transport-tcp, transport-tsn (each max_message_size); crates/dcps/src/layered_transport.rs (minimum of the legs); crates/rtps/src/reliable_writer.rs (fragment_size_for_message_size); crates/dcps/src/runtime.rs (writer creation)

Tests: crates/dcps/src/runtime.rs::tests::a_writers_fragment_size_follows_the_message_size_of_its_transport, crates/rtps/src/reliable_writer.rs::tests::the_fragment_size_is_bounded_by_what_the_field_holds, crates/transport-udp/src/udp_transport.rs::tests::max_message_size_is_the_configured_one_up_to_the_datagram_limit, crates/dcps/tests/runtime_config_layering.rs::the_udp_message_size_is_a_setting, crates/rtps/src/reliable_writer.rs::tests::fragment_size_is_fixed_and_a_larger_path_gets_one_data

Status: done — every transport states its largest message (Transport::max_message_size; for UDP it is a setting, transport.udp.max_message_size, default 1472; SHM and UDS their datagram limit, TCP the frame limit, TSN 1500; the layered transport the minimum of its legs). The fragment size of a writer is the message of the smallest transport less 128 octets, fixed for the life of the writer: 1344 at the default.

§8.4.14.1 Fragment size fixed per writer

Spec: §8.4.14.1, p. 120 — “The fragment size must be fixed for a given Writer and is identical for all remote Readers. By fixing the fragment size, the data a fragment number refers to does not depend on a particular remote Reader.”

Repo: crates/rtps/src/reliable_writer.rs (ReliableWriter::fragment_size_for, needs_fragmentation); crates/rtps/src/reader_proxy.rs (ReaderProxy::message_limit)

Tests: crates/rtps/src/reliable_writer.rs::tests::fragment_size_is_fixed_and_a_larger_path_gets_one_data, crates/rtps/src/reliable_writer.rs::tests::the_fragment_size_does_not_depend_on_the_reader_expecting_inline_qos

Status: done — the fragment size is not changed after the writer is created (set_fragmentation is gone) and is the same for all readers; the in-line QoS that shortens a fragment is counted at its largest length for any reader, so a reader’s expectsInlineQos does not change it either.

§8.4.14.1 Fragment size ≤ 65536

Spec: §8.4.14.1, p. 120 — “The fragment size must satisfy: fragment size <= 65536 bytes.”

Repo: crates/rtps/src/reliable_writer.rs (MAX_FRAGMENT_SIZE, ReliableWriter::try_new, ReliableWriter::new, fragment_size_for)

Tests: crates/rtps/src/reliable_writer.rs::tests::the_fragment_size_is_bounded_by_what_the_field_holds

Status: done — fragmentSize of the DATA_FRAG is an unsigned short; 65536 has no encoding, the bound is 65535. try_new refuses larger values with an error (new panics). A DATA_FRAG holds its 32 fixed octets, the in-line QoS and the fragment in the 65535 octets of octetsToNextHeader; the fragment size is accordingly at most 65503.

§8.4.14.1 DataFrag in increasing fragment number

Spec: §8.4.14.1, p. 120 — “DataFrag Submessages are sent in order, where ordering is defined by increasing fragment numbers.”

Repo: crates/rtps/src/reliable_writer.rs (push_sample_datagrams)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_above_fragment_size_packs_the_fragments_a_message_carries

Status: done

§8.4.14.1 Fragment only if required (per sequence number)

Spec: §8.4.14.1, p. 120 — “Data must only be fragmented if required. … Likewise, for variable size data types, a regular Data Submessage must be used if fragmentation is not required for a particular sequence number.”

Repo: crates/rtps/src/reliable_writer.rs (needs_fragmentation, push_sample_datagrams)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_under_fragment_size_produces_single_data, crates/rtps/src/reliable_writer.rs::tests::write_above_fragment_size_packs_the_fragments_a_message_carries, crates/rtps/tests/reliable_e2e.rs::e2e_frag_mixed_data_and_data_frag

Status: done

§8.4.14.1 Regular Data on transports without the need to fragment

Spec: §8.4.14.1, p. 120 — “If multiple transports are available to the Writer and some transports do not require fragmentation, a regular Data Submessage must be sent on those transports instead.”

Repo: crates/rtps/src/reader_proxy.rs (ReaderProxy::set_message_limit); crates/rtps/src/reliable_writer.rs (needs_fragmentation, unfragmented_room); crates/dcps/src/runtime.rs (match of a reader on the same host)

Tests: crates/rtps/src/reliable_writer.rs::tests::fragment_size_is_fixed_and_a_larger_path_gets_one_data

Status: done — a reader on the same host (loopback, message size LOOPBACK_MTU) gets a sample that fits in one message as one DATA; a remote reader of the same writer gets the same sample as DATA_FRAGs of the writer’s size.

§8.4.14.1 Inline QoS with the first DataFrag

Spec: §8.4.14.1, p. 120 — “For a given sequence number, if in-line QoS parameters are used, they must be included with the first DataFrag Submessage (containing the fragment with fragment number equal to 1).”

Repo: crates/rtps/src/reliable_writer.rs (build_data_frag_submessage_datagram: sample_inline_qos on every DATA_FRAG)

Tests: crates/rtps/src/reliable_writer.rs::tests::an_oversized_coherent_set_member_goes_out_as_marked_fragments, crates/rtps/src/reliable_writer.rs::tests::keyed_alive_preserves_inline_hash_on_data_fragments_and_rebuilds, crates/rtps/src/fragment_assembler.rs::tests::the_first_fragments_inline_qos_reaches_the_completed_sample

Status: done

§8.4.14.1 Recommendation: several fragments per DataFrag

Spec: §8.4.14.1, p. 120 — “If a transport can accommodate multiple fragments of the given fragment size, it is recommended that implementations concatenate as many fragments as possible into a single DataFrag message.”

Repo: crates/rtps/src/reliable_writer.rs (fragments_per_message, push_sample_datagrams, reply to NACK_FRAG in tick); crates/rtps/src/reader_proxy.rs (next_requested_fragment_run_after)

Tests: crates/rtps/src/reliable_writer.rs::tests::the_fragments_of_a_sample_fill_the_messages_and_no_more, crates/rtps/src/reliable_writer.rs::tests::write_above_fragment_size_packs_the_fragments_a_message_carries, crates/rtps/src/reader_proxy.rs::tests::next_requested_fragment_run_after_pulls_neighbours_of_one_sn

Status: done — a DATA_FRAG holds as many fragments as the message to the reader carries (fragmentsInSubmessage); this holds for the first send and for the answer to a NACK_FRAG (neighbouring requested fragments). At the default of 1472 octets one fragment fits a message.

§8.4.14.1 Flow control

Spec: §8.4.14.1, p. 121 — “When sending multiple DataFrag messages, flow control may be required to avoid flooding the network. … This is not part of the RTPS specification.”

Repo: —

Tests: —

Status: n/a (informative) — by its text not part of the specification.

§8.4.14.1 Reassembly: afterwards the behaviour of Data

Spec: §8.4.14.1, p. 121 — “Once all fragments have been received, the same protocol behavior applies as for a regular Data Submessage.”

Repo: crates/rtps/src/reliable_reader.rs (handle_data_frag: received_change_set, store_received, collect_in_order_for)

Tests: crates/rtps/tests/reliable_e2e.rs::e2e_frag_many_samples_3_fragments_each_10_percent_loss, crates/rtps/tests/reliable_e2e.rs::e2e_frag_large_sample_30_percent_loss, crates/rtps/src/reliable_reader.rs::tests::a_reassembled_sample_with_the_filtered_flag_is_known_but_not_delivered, crates/rtps/src/reliable_reader.rs::tests::a_reassembled_key_is_a_dispose_or_a_registration_as_a_data_is

Status: done — acknowledgement, in-order delivery and evaluation of the in-line QoS of the first fragment (status info with D, U and F, key registration, directed write, coherent set, group) as for Data.

§8.4.14.1 Fragments in any order

Spec: §8.4.14.1, p. 121 — “Note that implementations must be able to handle out-of-order arrival of DataFrag submessages.”

Repo: crates/rtps/src/fragment_assembler.rs (FragmentAssembler::insert)

Tests: crates/rtps/src/fragment_assembler.rs::tests::fragments_complete_out_of_order, crates/rtps/src/fragment_assembler.rs::tests::out_of_order_fragments_preserve_known_zero_key

Status: done

§8.4.14.1 Heartbeat only for numbers fully available

Spec: §8.4.14.1, p. 121 — “A Heartbeat message must only include those sequence numbers for which all fragments are available.”

Repo: crates/rtps/src/reliable_writer.rs (write_sample_with_inline_qos: stage_sample puts the whole sample into the HistoryCache before any fragment is sent; the HEARTBEAT’s lastSN is last_written_sn)

Tests: crates/rtps/tests/reliable_e2e.rs::e2e_frag_large_sample_30_percent_loss

Status: done

§8.4.14.1 Positive acknowledgement only after all fragments

Spec: §8.4.14.1, p. 121 — “an AckNack message must only positively acknowledge a sequence number when all fragments were received for that sequence number.”

Repo: crates/rtps/src/reliable_reader.rs (handle_data_frag: received_change_set only when FragmentAssembler::insert returns the sample)

Tests: crates/rtps/tests/reliable_e2e.rs::e2e_frag_large_sample_30_percent_loss, crates/rtps/tests/reliable_e2e.rs::e2e_frag_many_samples_3_fragments_each_10_percent_loss

Status: done

§8.4.14.1 AckNack only for numbers missing entirely

Spec: §8.4.14.1, p. 121 — “Likewise, a sequence number must be negatively acknowledged only when all fragments are missing.”

Repo: —

Tests: crates/rtps/src/reliable_reader.rs::tests::a_partly_received_sample_is_asked_for_by_nack_frag_not_acknack

Status: done

§8.4.14.1 NackFrag for a subset of the fragments

Spec: §8.4.14.1, p. 121 — “In order to negatively acknowledge a subset of fragments for a given sequence number, a NackFrag Submessage must be used. When data is fragmented, a Heartbeat may trigger both AckNack and NackFrag Submessages.”

Repo: crates/rtps/src/reliable_reader.rs (tick_outbound: one NACK_FRAG per incomplete sequence number, then the ACKNACK; build_nackfrag_datagram)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_partly_received_sample_is_asked_for_by_nack_frag_not_acknack

Status: done

§8.4.14.1 HeartbeatFrag for partially available numbers

Spec: §8.4.14.1, p. 121 — “If a Writer wants to inform a Reader on the partial availability of fragments for a given sequence number, a HeartbeatFrag Submessage can be used instead.”

Repo: —

Tests: —

Status: n/a (informative) — no requirement; the reader’s answer to HeartbeatFrag is listed under §8.3.8.7.

§8.4.14.1 NackFrag only in response to Heartbeat or HeartbeatFrag

Spec: §8.4.14.1, p. 121 — “A NackFrag Submessage can only be sent in response to a Heartbeat or HeartbeatFrag submessage.”

Repo: crates/rtps/src/reliable_reader.rs (handle_heartbeat, handle_heartbeat_frag, handle_data_frag_opening, tick_outbound)

Tests: crates/rtps/src/reliable_reader.rs::tests::acknack_and_nack_frag_wait_for_a_heartbeat, crates/rtps/src/reliable_reader.rs::tests::a_heartbeat_frag_is_answered_when_an_available_fragment_is_missing

Status: done — a NACK_FRAG goes out only in the tick after a HEARTBEAT or HEARTBEAT_FRAG; a DATA_FRAG that leaves fragments open arms none. A lost fragment is asked for at the writer’s next HEARTBEAT.

§8.4.15 Implementation Guidelines

Spec: §8.4.15, p. 121 — “The contents of this sub clause are not part of the formal specification of the protocol.”

Repo: —

Tests: —

Status: n/a (informative) — by its text not part of the specification.

§8.4.15.1 Implementation of ReaderProxy and WriterProxy

Spec: §8.4.15.1, pp. 121–122 — “In practice, what is required is that the ReaderProxy is able to implement the operations used by the protocol and this does not require the use of explicit associations.”

Repo: —

Tests: —

Status: n/a (informative) — guideline under §8.4.15.

§8.4.15.2 Efficient use of Gap and AckNack

Spec: §8.4.15.2, p. 122 — “implementations that combine multiple Gap and AckNack Submessages and take advantage of the ability of these Submessages to contain a set of sequence number will be more efficient”.

Repo: —

Tests: —

Status: n/a (informative) — guideline under §8.4.15.

§8.4.15.3 Coalescing multiple Data submessages

Spec: §8.4.15.3, p. 122 — “implementations that combine Submessages into a single RTPS message will in general make better utilization of CPU and bandwidth.”

Repo: —

Tests: —

Status: n/a (informative) — guideline under §8.4.15.

§8.4.15.4 Piggybacking HeartBeat on Data

Spec: §8.4.15.4, p. 122 — “A particularly useful case is the piggybacking of HeartBeat Submessages following Data Submessages.”

Repo: —

Tests: —

Status: n/a (informative) — guideline under §8.4.15.

§8.4.15.5 Sending to unknown readerId

Spec: §8.4.15.5, p. 122 — “Implementations are encouraged to use this feature to minimize bandwidth usage.”

Repo: —

Tests: —

Status: n/a (informative) — guideline under §8.4.15.

§8.4.15.6 Reclaiming resources from unresponsive readers

Spec: §8.4.15.6, p. 123 — “the Writer should be allowed to deem the Reader as ‘Inactive’ and proceed in updating its queue.”

Repo: —

Tests: —

Status: n/a (informative) — guideline under §8.4.15.

§8.4.15.7 Count in Heartbeat, HeartbeatFrag, AckNack and NackFrag

Spec: §8.4.15.7, p. 123 — “an implementation should ensure that same logical HEARTBEATs are tagged with the same Count.” “The Count element should be incremented and compared according to modular arithmetic rules in order to accommodate the integer overflow.”

Repo: —

Tests: —

Status: n/a (informative) — guideline under §8.4.15; the duties on Count are under §8.3.8.

§8.5 Discovery Module

§8.5 Discovery of remote entities and built-in topics

Spec: §8.5, p. 123 — “DDS implementations must automatically discover the presence of remote entities, both when they join and leave the network. This discovery information is made accessible to the user through DDS built-in topics.”

Repo: crates/dcps/src/builtin_subscriber.rs (BuiltinSubscriber); crates/dcps/src/runtime.rs (handle_spdp_datagram, SEDP events)

Tests: crates/dcps/tests/builtin_topic_readers.rs::linux_e2e::spdp_receive_populates_dcps_participant_reader, crates/dcps/tests/builtin_topic_readers.rs::linux_e2e::sedp_pub_sub_populates_dcps_publication_and_subscription_readers, crates/dcps/tests/endpoint_delete_unmatch_e2e.rs::linux_e2e::dropping_a_writer_unmatches_the_remote_reader

Status: done

§8.5.1 SPDP and SEDP as the minimum

Spec: §8.5.1, p. 124 — “For the purpose of interoperability, all RTPS implementations must provide at least the following discovery protocols: 1. Simple Participant Discovery Protocol (SPDP) 2. Simple Endpoint Discovery Protocol (SEDP)”. Likewise §8.5.3, p. 125, and §8.5.4, p. 130.

Repo: crates/discovery/src/spdp.rs; crates/discovery/src/sedp/stack.rs (SedpStack)

Tests: crates/discovery/tests/spdp_loopback_e2e.rs::two_zerodds_participants_discover_each_other, crates/discovery/src/sedp/stack.rs::tests::end_to_end_discovery_between_two_stacks

Status: done

§8.5.1 Further PDPs and EDPs

Spec: §8.5.1, p. 124 — “Implementations may choose to support multiple PDPs and EDPs, possibly vendor-specific.” “How this information is used by a Participant to configure its local Endpoints depends on the actual implementation of the RTPS protocol and is not part of the discovery protocol specification.”

Repo: —

Tests: —

Status: n/a (informative) — no requirement.

§8.5.2 Built-in topics and their RTPS endpoints

Spec: §8.5.2, p. 124 — “There are four pre-defined built-in Topics: “DCPSParticipant,” “DCPSSubscription,” “DCPSPublication,” and “DCPSTopic.”” “The built-in DataReaders act as regular DDS DataReaders and can also be accessed by the user through the DDS API.” “RTPS maps each built-in DDS DataWriter or DataReader to an associated built-in RTPS Endpoint.”

Repo: crates/dcps/src/builtin_subscriber.rs (four built-in DataReaders); crates/discovery/src/spdp.rs; crates/discovery/src/sedp/stack.rs

Tests: crates/dcps/tests/builtin_topic_readers.rs::builtin_subscriber_has_all_four_readers_pre_created, crates/dcps/src/builtin_subscriber.rs::tests::sinks_push_topic_lands_in_reader

Status: done

§8.5.3.1 SPDP built-in endpoints

Spec: §8.5.3.1, p. 125 — “For each Participant, the SPDP creates two RTPS built-in Endpoints: the SPDPbuiltinParticipantWriter and the SPDPbuiltinParticipantReader.”

Repo: crates/discovery/src/spdp.rs (SpdpBeacon, SpdpReader); crates/dcps/src/runtime.rs (DcpsRuntime::spdp_beacon)

Tests: crates/discovery/src/spdp.rs::tests::beacon_serializes_to_decodable_datagram, crates/dcps/src/runtime.rs::tests::two_runtimes_discover_each_other_via_spdp

Status: done

§8.5.3.1 SPDPbuiltinParticipantWriter: best-effort StatelessWriter

Spec: §8.5.3.1, p. 125 — “The SPDPbuiltinParticipantWriter is an RTPS Best-Effort StatelessWriter.”

Repo: crates/discovery/src/spdp.rs (SpdpBeacon::serialize: DATA without HEARTBEAT, no state per recipient)

Tests: crates/discovery/src/spdp.rs::tests::beacon_uses_spdp_builtin_writer_id, crates/discovery/src/spdp.rs::tests::beacon_serializes_to_decodable_datagram

Status: done

§8.5.3.1 One data-object in the HistoryCache, replaced on change

Spec: §8.5.3.1, p. 125 — “The HistoryCache of the SPDPbuiltinParticipantWriter contains a single data-object of type SPDPdiscoveredParticipantData. The value of this data-object is set from the attributes in the Participant. If the attributes change, the data-object is replaced.”

Repo: crates/discovery/src/spdp.rs (SpdpBeacon::data); crates/dcps/src/runtime.rs (beacon update on a changed USER_DATA)

Tests: crates/dcps/tests/set_qos_after_enable.rs::a_user_data_change_reaches_the_peers_builtin_reader

Status: done

§8.5.3.1 Periodic resend of the same change

Spec: §8.5.3.1, p. 125 — “This is achieved by periodically calling StatelessWriter::unsent_changes_reset, which causes the StatelessWriter to resend all changes present in its HistoryCache to all locators.”

Repo: crates/discovery/src/spdp.rs (SpdpBeacon::serialize, set_new_sn_each_period); crates/dcps/src/runtime.rs (RuntimeConfig::spdp_new_sequence_per_period)

Tests: crates/discovery/src/spdp.rs::tests::the_resent_beacon_keeps_its_sequence_number_until_the_data_changes, crates/discovery/src/spdp.rs::tests::beacon_increments_sequence_number

Status: done — the periodic announcement resends the one change with its sequence number; a change of the participant data is a new change. The form of Cyclone DDS and OpenDDS (a new number each period, measured in tools/wire-capture/rtps-sessions) is the setting discovery.spdp_new_sequence_per_period. Not measured: whether a Cyclone or OpenDDS reader keeps the participant alive on a repeated number.

§8.5.3.1 Period: default by the PSM, smaller than leaseDuration

Spec: §8.5.3.1, p. 125 — “The periodic rate at which the SPDPbuiltinParticipantWriter sends out the SPDPdiscoveredParticipantData defaults to a PSM specified value. This period should be smaller than the leaseDuration specified in the SPDPdiscoveredParticipantData”.

Repo: crates/dcps/src/runtime.rs (default_spdp_period_for, DEFAULT_SPDP_PERIOD, key discovery.spdp_period_ms)

Tests: crates/dcps/src/runtime.rs::tests::a_short_lease_without_a_period_beacons_three_times_a_lease, crates/dcps/tests/runtime_config_layering.rs::the_protocol_timing_parameters_are_settings

Status: done — the default is the PSM’s, 30 s; with a lease under 90 s at most a third of the lease, so that the period stays smaller than leaseDuration.

§8.5.3.1 Pre-configured unicast and multicast locators

Spec: §8.5.3.1, p. 125 — “The pre-configured list of locators may include both unicast and multicast locators. Port numbers are defined by each PSM.”

Repo: crates/dcps/src/runtime.rs (send_spdp_multicast, send_spdp_unicast, expand_initial_peer)

Tests: crates/dcps/src/runtime.rs::tests::multicast_free_discovery_via_initial_peers, crates/dcps/src/runtime.rs::tests::expand_initial_peer_ip_only_yields_well_known_port_range

Status: done

§8.5.3.1 SPDPbuiltinParticipantReader and the choice of EDP

Spec: §8.5.3.1, p. 125 — “The contained information includes what Endpoint Discovery Protocols the remote Participant supports. The proper Endpoint Discovery Protocol is then used for exchanging Endpoint information with the remote Participant.”

Repo: crates/discovery/src/sedp/stack.rs (on_participant_discovered: by builtin_endpoint_set)

Tests: crates/discovery/src/sedp/stack.rs::tests::discovered_participant_wires_all_four_endpoints_when_present, crates/discovery/src/sedp/stack.rs::tests::partial_endpoint_set_wires_only_matching_sides

Status: done

§8.5.3.1 Optional: an announcement to a participant not known before

Spec: §8.5.3.1, p. 125 — “Implementations can minimize any start-up delays by sending an additional SPDPdiscoveredParticipantData in response to receiving this data-object from a previously unknown Participant, but this behavior is optional.”

Repo: crates/dcps/src/runtime.rs (directed_spdp_targets, SpdpResponseTargets)

Tests: crates/dcps/src/runtime.rs::tests::the_spdp_response_axis_decides_the_targets, crates/rtps/src/dialect.rs::tests::the_spdp_response_default_answers_the_beacon_source

Status: done

§8.5.3.1 Optional: extend the locator list by discovered participants

Spec: §8.5.3.1, p. 125 — “Implementations may also enable the user to choose whether to automatically extend the pre-configured list of locators with new locators from newly discovered Participants. … These last two features are optional and not required for the purpose of interoperability.”

Repo: crates/dcps/src/runtime.rs (send_spdp_unicast: the periodic announcement also goes to the metatraffic locators of discovered participants)

Tests: crates/dcps/src/runtime.rs::tests::an_initial_peer_a_discovered_participant_covers_is_left_to_the_fan_out

Status: done — the extension cannot be switched off.

§8.5.3.2 Figure 8.27 SPDPdiscoveredParticipantData

Spec: §8.5.3.2, p. 125 — “the SPDPdiscoveredParticipantData specializes the ParticipantProxy and therefore includes all the information necessary to configure a discovered Participant. The SPDPdiscoveredParticipantData also specializes the DDS-defined DDS::ParticipantBuiltinTopicData”.

Repo: crates/rtps/src/participant_data.rs (ParticipantBuiltinTopicData: attributes of the ParticipantProxy, user_data, lease_duration, manual_liveliness_count, builtin_endpoint_qos)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full, crates/rtps/src/participant_data.rs::tests::manual_liveliness_count_and_builtin_endpoint_qos_go_out_and_read_back

Status: done

§8.5.3.2 Table 8.78 domainId

Spec: §8.5.3.2, p. 126, Table 8.78 — “domainId: DomainId_t — Identifies the DDS domainId of the associated DDS DomainParticipant.”

Repo: crates/rtps/src/participant_data.rs (domain_id, PID_DOMAIN_ID); crates/dcps/src/runtime.rs (beacon with domain_id: Some(domain_id))

Tests: crates/dcps/src/runtime.rs::tests::a_participant_of_another_domain_id_is_not_discovered, crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§8.5.3.2 Table 8.78 domainTag

Spec: §8.5.3.2, p. 126, Table 8.78 — “domainTag: string — Identifies the DDS domainTag of the associated DDS DomainParticipant.”

Repo: crates/rtps/src/participant_data.rs (domain_tag, PID_DOMAIN_TAG)

Tests: crates/rtps/src/participant_data.rs::tests::domain_tag_goes_out_when_set_and_reads_back, crates/dcps/src/runtime.rs::tests::a_participant_of_another_domain_tag_is_not_discovered

Status: done

§8.5.3.2 Table 8.78 protocolVersion

Spec: §8.5.3.2, p. 126, Table 8.78 — “protocolVersion: ProtocolVersion_t — Identifies the RTPS protocol version used by the Participant.”

Repo: crates/rtps/src/participant_data.rs (protocol_version, PID_PROTOCOL_VERSION)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§8.5.3.2 Table 8.78 guidPrefix

Spec: §8.5.3.2, p. 126, Table 8.78 — “guidPrefix: GuidPrefix_t — The common GuidPrefix_t of the Participant and all the Endpoints contained within the Participant.”

Repo: crates/rtps/src/participant_data.rs (guid, PID_PARTICIPANT_GUID)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_decode_requires_guid_pid, crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§8.5.3.2 Table 8.78 vendorId

Spec: §8.5.3.2, p. 126, Table 8.78 — “vendorId: VendorId_t — Identifies the vendor of the DDS middleware that contains the Participant.”

Repo: crates/rtps/src/participant_data.rs (vendor_id, PID_VENDOR_ID)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: partial — ZeroDDS sends 0x01F0, not a value assigned by the OMG (blocked item under §8.3.5.2).

§8.5.3.2 Table 8.78 expectsInlineQos

Spec: §8.5.3.2, p. 126, Table 8.78 — “expectsInlineQos: bool — Describes whether the Readers within the Participant expect that the QoS values that apply to each data modification are encapsulated included with each Data.”

Repo: crates/rtps/src/participant_data.rs (expects_inline_qos, PID_EXPECTS_INLINE_QOS)

Tests: crates/rtps/src/participant_data.rs::tests::expects_inline_qos_goes_out_when_set_and_reads_back

Status: done

§8.5.3.2 Table 8.78 metatrafficUnicastLocatorList

Spec: §8.5.3.2, p. 126, Table 8.78 — “List of unicast locators (transport, address, port combinations) that can be used to send messages to the built-in Endpoints contained in the Participant.”

Repo: crates/rtps/src/participant_data.rs (metatraffic_unicast_locators, PID_METATRAFFIC_UNICAST_LOCATOR)

Tests: crates/rtps/src/participant_data.rs::tests::decode_retains_all_repeated_unicast_locators_in_order_le_and_be, crates/dcps/src/runtime.rs::tests::wlp_unicast_targets_prefers_metatraffic_then_default

Status: done

§8.5.3.2 Table 8.78 metatrafficMulticastLocatorList

Spec: §8.5.3.2, p. 126, Table 8.78 — “List of multicast locators (transport, address, port combinations) that can be used to send messages to the built-in Endpoints contained in the Participant.”

Repo: crates/rtps/src/participant_data.rs (metatraffic_multicast_locators, PID_METATRAFFIC_MULTICAST_LOCATOR)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full, crates/rtps/src/participant_data.rs::tests::decode_zero_locators_yields_empty_lists

Status: done

§8.5.3.2 Table 8.78 defaultUnicastLocatorList

Spec: §8.5.3.2, p. 127, Table 8.78 — “defaultUnicastLocatorList: Locator_t[1..*] … These are the unicast locators that will be used in case the Endpoint does not specify its own set of Locators, so at least one Locator must be present.”

Repo: crates/rtps/src/participant_data.rs (default_unicast_locators); crates/dcps/src/runtime.rs (announce_locators: never empty)

Tests: crates/dcps/src/runtime.rs::tests::announce_locators_automatic_is_non_empty_and_includes_probe, crates/rtps/src/participant_data.rs::tests::encode_dedups_exact_duplicate_locators

Status: done

§8.5.3.2 Table 8.78 defaultMulticastLocatorList

Spec: §8.5.3.2, p. 127, Table 8.78 — “Default list of multicast locators … These are the multicast locators that will be used in case the Endpoint does not specify its own set of Locators.”

Repo: crates/rtps/src/participant_data.rs (default_multicast_locators, PID_DEFAULT_MULTICAST_LOCATOR)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done — ZeroDDS announces no default multicast locator.

§8.5.3.2 Table 8.78 availableBuiltinEndpoints

Spec: §8.5.3.2, p. 127, Table 8.78 — “All Participants must support the SEDP. This attribute identifies the kinds of built-in SEDP Endpoints that are available in the Participant.”

Repo: crates/rtps/src/participant_data.rs (builtin_endpoint_set, endpoint_flag); crates/dcps/src/runtime.rs (ALL_STANDARD plus TOPICS_ANNOUNCER/TOPICS_DETECTOR)

Tests: crates/rtps/src/participant_data.rs::tests::endpoint_flag_bit_positions_match_spec, crates/dcps/src/runtime.rs::tests::spdp_announces_standard_bits_by_default

Status: done

§8.5.3.2 Table 8.78 leaseDuration

Spec: §8.5.3.2, p. 127, Table 8.78 — “How long a Participant should be considered alive every time an announcement is received from the Participant. If a Participant fails to send another announcement within this time period, the Participant can be considered gone.”

Repo: crates/rtps/src/participant_data.rs (lease_duration, PID_PARTICIPANT_LEASE_DURATION); crates/discovery/src/spdp.rs (DiscoveredParticipantsCache::drain_expired)

Tests: crates/rtps/src/participant_data.rs::tests::to_pl_cdr_be_is_big_endian_roundtrips_and_omits_credential_tokens

Status: done

§8.5.3.2 Table 8.78 manualLivelinessCount

Spec: §8.5.3.2, p. 127, Table 8.78 — “manualLivelinessCount: Count_t — Used to implement MANUAL_BY_PARTICIPANT liveliness QoS. When liveliness is asserted, the manualLivelinessCount is incremented and a new SPDPdiscoveredParticipantData is sent.”

Repo: crates/rtps/src/participant_data.rs (manual_liveliness_count); crates/dcps/src/runtime.rs (bump_manual_liveliness_count, spdp_announced); crates/dcps/src/wlp.rs (take_manual_participant_written)

Tests: crates/rtps/src/participant_data.rs::tests::manual_liveliness_count_and_builtin_endpoint_qos_go_out_and_read_back, crates/dcps/src/runtime.rs::tests::the_manual_liveliness_count_of_the_announcement_counts_up, crates/dcps/src/runtime.rs::tests::a_changed_manual_liveliness_count_renews_the_manual_writers_of_that_participant, crates/dcps/src/wlp.rs::tests::a_written_manual_sample_is_reported_once

Status: done — when a MANUAL_BY_PARTICIPANT sample is written the count goes up (at most once per tick) and a new announcement goes out; a receiver that sees the count of a known participant change takes it as that participant’s manual liveliness assertion (test: n, n + 1 renews the participant’s MANUAL_BY_PARTICIPANT writers at the reader).

§8.5.3.2 Table 8.78 builtinEndpointQos

Spec: §8.5.3.2, p. 127, Table 8.78 — “builtinEndpointQos: BuiltinEndpointQos_t — Provides additional information on the QoS of the built-in Endpoints supported by the Participant.”

Repo: crates/rtps/src/participant_data.rs (builtin_endpoint_qos); crates/dcps/src/wlp.rs (WlpEndpoint::add_peer_reader)

Tests: crates/rtps/src/participant_data.rs::tests::manual_liveliness_count_and_builtin_endpoint_qos_go_out_and_read_back, crates/dcps/src/wlp.rs::tests::the_reader_is_treated_as_builtin_endpoint_qos_says

Status: done — the field is read and written; the WLP writer treats the reader accordingly (§8.4.13.3). ZeroDDS announces none itself: its reader is RELIABLE.

§8.5.3.2 Further EDPs through the extension mechanisms

Spec: §8.5.3.2, p. 127 — “There are currently no other Endpoint Discovery Protocols defined by the RTPS specification. In order to extend SPDPdiscoveredParticipantData to include additional EDPs, the standard RTPS extension mechanisms can be used.”

Repo: —

Tests: —

Status: n/a (informative) — no requirement.

§8.5.3.2.1 availableBuiltinEndpoints: endpoints that may be announced

Spec: §8.5.3.2, p. 127 — “The builtin endpoints that may be announced in the availableBuiltinEndpoints include: PUBLICATIONS_DETECTOR, PUBLICATIONS_ANNOUNCER, SUBSCRIPTIONS_DETECTOR, SUBSCRIPTIONS_ANNOUNCER, TOPICS_DETECTOR, TOPICS_ANNOUNCER, PARTICIPANT_MESSAGE_READER, and PARTICIPANT_MESSAGE_WRITER. The availableBuiltinEndpoints may also announce builtin endpoints defined in other DDS specifications.”

Repo: crates/rtps/src/participant_data.rs (endpoint_flag, ALL_STANDARD, ALL_SECURE)

Tests: crates/rtps/src/participant_data.rs::tests::endpoint_flag_roundtrip_through_pl_cdr, crates/dcps/src/runtime.rs::tests::spdp_announces_secure_bits_when_configured, crates/dcps/tests/type_lookup_e2e.rs::announces_type_lookup_endpoints_in_spdp

Status: done

§8.5.3.3 EntityIds of the SPDP endpoints

Spec: §8.5.3.3, p. 128 — “The Protocol reserves the following values of the EntityId_t for the SPDP built-in Endpoints: ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER”

Repo: crates/rtps/src/wire_types.rs (EntityId::SPDP_BUILTIN_PARTICIPANT_WRITER, EntityId::SPDP_BUILTIN_PARTICIPANT_READER)

Tests: crates/rtps/src/wire_types.rs::tests::spdp_builtin_participant_writer_layout, crates/rtps/src/wire_types.rs::tests::spdp_builtin_participant_reader_layout

Status: done

§8.5.3.3 Table 8.79 SPDP writer unicastLocatorList

Spec: §8.5.3.3, p. 128, Table 8.79 — “unicastLocatorList: Transport-kinds and addresses are either auto-detected or configured by the application. Ports are a parameter to the SPDP initialization or else are set to a PSM-specified value that depends on the domainId.”

Repo: crates/dcps/src/runtime.rs (announce_locators, spdp_unicast_port)

Tests: crates/dcps/src/runtime.rs::tests::spdp_unicast_port_follows_rtps_formula, crates/dcps/src/runtime.rs::tests::announce_locators_pins_to_single_interface

Status: done

§8.5.3.3 Table 8.79 SPDP writer multicastLocatorList

Spec: §8.5.3.3, p. 128, Table 8.79 — “multicastLocatorList: Defaults to a PSM-specified value.”

Repo: crates/rtps/src/wire_types.rs (spdp_multicast_port, group 239.255.0.1); crates/dcps/src/runtime.rs (spdp_multicast_group)

Tests: crates/rtps/src/wire_types.rs::tests::spdp_default_multicast_is_239_255_0_1, crates/rtps/src/wire_types.rs::tests::spdp_multicast_port_domain_0_is_7400

Status: done

§8.5.3.3 Table 8.79 SPDP writer reliabilityLevel

Spec: §8.5.3.3, p. 128, Table 8.79 — “reliabilityLevel: BEST_EFFORT”.

Repo: crates/discovery/src/spdp.rs (SpdpBeacon)

Tests: crates/discovery/src/spdp.rs::tests::beacon_serializes_to_decodable_datagram

Status: done

§8.5.3.3 Table 8.79 SPDP writer topicKind

Spec: §8.5.3.3, p. 128, Table 8.79 — “topicKind: WITH_KEY”.

Repo: crates/rtps/src/wire_types.rs (EntityId::SPDP_BUILTIN_PARTICIPANT_WRITER: BuiltinWriterWithKey)

Tests: crates/rtps/src/wire_types.rs::tests::spdp_builtin_participant_writer_layout

Status: done

§8.5.3.3 Table 8.79 SPDP writer resendPeriod

Spec: §8.5.3.3, p. 128, Table 8.79 — “resendPeriod: Defaults to a PSM-specified value.”

Repo: crates/dcps/src/runtime.rs (RuntimeConfig::spdp_period, ZERODDS_SPDP_PERIOD_MS)

Tests: crates/dcps/src/runtime.rs::tests::a_short_lease_without_a_period_beacons_three_times_a_lease, crates/dcps/tests/runtime_config_layering.rs::the_protocol_timing_parameters_are_settings

Status: done — settable (discovery.spdp_period_ms); the default is 30 s, the PSM’s.

§8.5.3.3 Table 8.79 SPDP writer readerLocators

Spec: §8.5.3.3, p. 128, Table 8.79 — “readerLocators: ”.

Repo: crates/dcps/src/runtime.rs (RuntimeConfig::initial_peers, expand_initial_peer, multicast target)

Tests: crates/dcps/src/runtime.rs::tests::initial_peer_specs_reach_the_runtime_without_touching_the_environment, crates/dcps/src/runtime.rs::tests::initial_peer_specs_expand_per_the_configured_participant_limit

Status: done

§8.5.3.3 Table 8.80 SPDP reader unicastLocatorList

Spec: §8.5.3.3, p. 129, Table 8.80 — “unicastLocatorList: … Ports are a parameter to the SPDP initialization or else are set to a PSM-specified value that depends on the domainId.”

Repo: crates/dcps/src/runtime.rs (spdp_unicast socket on spdp_unicast_port)

Tests: crates/dcps/src/runtime.rs::tests::spdp_unicast_port_follows_rtps_formula

Status: done

§8.5.3.3 Table 8.80 SPDP reader multicastLocatorList

Spec: §8.5.3.3, p. 129, Table 8.80 — “multicastLocatorList: . Defaults to a PSM-specified value.”

Repo: crates/dcps/src/runtime.rs (spdp_multicast_rx, spdp_multicast_group)

Tests: crates/dcps/src/runtime.rs::tests::start_refuses_spdp_group_outside_allowlist, crates/discovery/tests/spdp_loopback_e2e.rs::loopback_multicast_self_discovery

Status: done

§8.5.3.3 Table 8.80 SPDP reader reliabilityLevel

Spec: §8.5.3.3, p. 129, Table 8.80 — “reliabilityLevel: BEST_EFFORT”.

Repo: crates/discovery/src/spdp.rs (SpdpReader: stateless, no ACKNACK)

Tests: crates/discovery/src/spdp.rs::tests::samples_reads_every_participant_a_datagram_bundles

Status: done

§8.5.3.3 Table 8.80 SPDP reader topicKind

Spec: §8.5.3.3, p. 129, Table 8.80 — “topicKind: WITH_KEY”.

Repo: crates/rtps/src/wire_types.rs (EntityId::SPDP_BUILTIN_PARTICIPANT_READER: BuiltinReaderWithKey)

Tests: crates/rtps/src/wire_types.rs::tests::spdp_builtin_participant_reader_layout

Status: done

§8.5.3.3 SPDP reader: HistoryCache by participant GUID

Spec: §8.5.3.3, p. 129 — “The HistoryCache of the SPDPbuiltinParticipantReader contains information on all active discovered participants; the key used to identify each data-object corresponds to the Participant GUID.” “If an entry with a matching key is not there, a new entry is added keyed by the GUID of the Participant.”

Repo: crates/discovery/src/spdp.rs (DiscoveredParticipantsCache: key data.guid.prefix)

Tests: crates/discovery/src/spdp.rs::tests::cache_insert_returns_true_for_new_participant, crates/discovery/src/spdp.rs::tests::cache_get_returns_inserted_participant

Status: done

§8.5.3.3 SPDP reader: remove stale entries

Spec: §8.5.3.3, p. 129 — “Periodically, the SPDP examines the SPDPbuiltinParticipantReader HistoryCache looking for stale entries defined as those that have not been refreshed for a period longer than their specified leaseDuration. Stale entries are removed.”

Repo: crates/discovery/src/spdp.rs (DiscoveredParticipantsCache::drain_expired); crates/dcps/src/runtime.rs (called per tick)

Tests: crates/discovery/src/spdp.rs::tests::participant_lease_lifecycle_observation_and_infinite, crates/dcps/src/runtime.rs::tests::participant_lease_lifecycle_hard_death_and_same_prefix

Status: done — drain_expired already removes when the elapsed time equals leaseDuration.

§8.5.3.4 Table 8.81 SPDP_WELL_KNOWN_UNICAST_PORT

Spec: §8.5.3.4, p. 129, Table 8.81 — “SPDP_WELL_KNOWN_UNICAST_PORT — entries in SPDPbuiltinParticipantReader.unicastLocatorList, unicast entries in SPDPbuiltinParticipantWriter.readerLocators”.

Repo: crates/rtps/src/wire_types.rs (spdp_unicast_port); crates/dcps/src/runtime.rs (expand_initial_peer)

Tests: crates/dcps/src/runtime.rs::tests::spdp_unicast_port_follows_rtps_formula, crates/dcps/src/runtime.rs::tests::expand_initial_peer_ip_only_yields_well_known_port_range

Status: done

§8.5.3.4 Table 8.81 SPDP_WELL_KNOWN_MULTICAST_PORT

Spec: §8.5.3.4, p. 129, Table 8.81 — “SPDP_WELL_KNOWN_MULTICAST_PORT — entries in SPDPbuiltinParticipantReader.multicastLocatorList, multicast entries in SPDPbuiltinParticipantWriter.readerLocators”.

Repo: crates/rtps/src/wire_types.rs (spdp_multicast_port)

Tests: crates/rtps/src/wire_types.rs::tests::spdp_multicast_port_domain_1_is_7650, crates/rtps/src/wire_types.rs::tests::spdp_multicast_port_domain_5_is_8650

Status: done

§8.5.4.1 Association with the SEDP endpoints of a discovered participant

Spec: §8.5.4.1, p. 130 — “once a Participant knows of the presence of another Participant, it can assume the presence of the built-in Endpoints made available by the remote participant and establish the association with the locally-matching built-in Endpoints.”

Repo: crates/discovery/src/sedp/stack.rs (on_participant_discovered)

Tests: crates/discovery/src/sedp/stack.rs::tests::discovered_participant_wires_all_four_endpoints_when_present, crates/discovery/src/sedp/stack.rs::tests::self_discovery_is_ignored

Status: done

§8.5.4.1 SEDP: the same protocol as for application-defined endpoints

Spec: §8.5.4.1, p. 130 — “The protocol used to communicate between built-in Endpoints is the same as used for application-defined Endpoints.”

Repo: crates/discovery/src/sedp/writer.rs (make_sedp_writer: ReliableWriter); crates/discovery/src/sedp/reader.rs (ReliableReader)

Tests: crates/discovery/src/sedp/stack.rs::tests::end_to_end_discovery_between_two_stacks, crates/discovery/src/sedp/stack.rs::tests::a_heartbeat_past_a_hole_releases_the_buffered_subscription

Status: done

§8.5.4.2 SEDP endpoints reliable

Spec: §8.5.4.2, p. 130 — “The SEDP therefore maps each corresponding built-in DDS DataWriter or DataReader into corresponding reliable RTPS Writer and Reader Endpoints.” “it is sufficient that an implementation provides the required built-in Endpoints and reliable communication that satisfies the general requirements listed in 8.4.2.”

Repo: crates/discovery/src/sedp/writer.rs (make_sedp_writer); crates/discovery/src/sedp/reader.rs

Tests: crates/discovery/src/sedp/stack.rs::tests::a_heartbeat_past_a_hole_releases_the_buffered_subscription, crates/discovery/tests/cyclone_sedp_replay.rs::cyclone_sedp_publication_fixture_flows_through_stack

Status: done — the deviations of the reliable writers and readers from §8.4.2 are listed there.

§8.5.4.2 EntityIds of the SEDP endpoints

Spec: §8.5.4.2, pp. 130–131 — “The RTPS Protocol reserves the following values of the EntityId_t for the built-in Endpoints: ENTITYID_SEDP_BUILTIN_PUBLICATIONS_ANNOUNCER … ENTITYID_SEDP_BUILTIN_TOPICS_DETECTOR”

Repo: crates/rtps/src/wire_types.rs (EntityId::SEDP_BUILTIN_PUBLICATIONS_WRITER, EntityId::SEDP_BUILTIN_SUBSCRIPTIONS_READER and the others)

Tests: crates/rtps/src/wire_types.rs::tests::sedp_publications_writer_layout, crates/rtps/src/wire_types.rs::tests::sedp_subscriptions_reader_layout

Status: done — the values are listed under §9.3.1.3.

§8.5.4.3 Topics endpoints optional

Spec: §8.5.4.3, p. 131 — “it is not required to implement the SEDPbuiltinTopicsReader and SEDPbuiltinTopicsWriter built-in Endpoints and for the purpose of interoperability, implementations should not rely on their presence in remote Participants.”

Repo: crates/discovery/src/sedp/stack.rs (on_participant_discovered: topics proxies only when the bits are set)

Tests: crates/discovery/src/sedp/stack.rs::tests::the_topics_bits_wire_the_topics_writer_and_reader, crates/discovery/src/sedp/stack.rs::tests::partial_endpoint_set_wires_only_matching_sides

Status: done

§8.5.4.3 Only the built-in endpoints needed

Spec: §8.5.4.3, p. 131 — “a Participant is only required to provide the built-in Endpoints required for matching up local and remote Endpoints.”

Repo: —

Tests: —

Status: n/a (informative) — no requirement; ZeroDDS provides all SEDP endpoints.

§8.5.4.4 Figure 8.30 DiscoveredWriterData

Spec: §8.5.4.4, p. 131 — “DiscoveredWriterData extends DDS::PublicationBuiltinTopicData” “the “Discovered” DataTypes also include all the information that may be needed by an implementation of the protocol to configure the RTPS Endpoints. This information is contained in the RTPS ReaderProxy and WriterProxy.”

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData: QoS, key, unicast_locators, multicast_locators, group_guid, data_max_size_serialized)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies, crates/discovery/tests/vendor_discovery_frames.rs::cyclone_announcements_read_and_write_back, crates/rtps/src/publication_data.rs::tests::the_max_payload_size_and_the_name_of_a_writer_travel, crates/rtps/src/publication_data.rs::tests::the_writers_group_travels_as_pid_group_guid

Status: done — the attributes of the WriterProxy are in the announcement: writer GUID, both locator lists, dataMaxSizeSerialized (PID_TYPE_MAX_SIZE_SERIALIZED) and the group (PID_GROUP_GUID, giving remoteGroupEntityId).

§8.5.4.4 Figure 8.30 DiscoveredReaderData

Spec: §8.5.4.4, p. 131 — “DiscoveredReaderData extends the DDS-defined DDS::SubscriptionBuiltinTopicData”.

Repo: crates/rtps/src/subscription_data.rs (SubscriptionBuiltinTopicData: QoS, key, unicast_locators, multicast_locators, expects_inline_qos, content_filter)

Tests: crates/rtps/src/publication_data.rs::tests::the_writers_group_travels_as_pid_group_guid

Status: done

§8.5.4.4 Figure 8.30 DiscoveredTopicData

Spec: §8.5.4.4, p. 131 — “DiscoveredTopicData extends DDS::TopicBuiltinTopicData.”

Repo: crates/rtps/src/topic_data.rs (TopicBuiltinTopicData)

Tests: crates/discovery/src/sedp/stack.rs::tests::two_stacks_exchange_a_topic_its_new_qos_and_its_dispose, crates/discovery/src/sedp/stack.rs::tests::a_cyclone_topic_and_its_dispose_are_read_by_cyclones_own_key

Status: done

§8.5.4.4 Missing information: defaults of the PSM

Spec: §8.5.4.4, p. 132 — “An implementation of the protocol need not necessarily send all information contained in the DataTypes. If any information is not present, the implementation can assume the default values, as defined by the PSM.”

Repo: crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs (default per missing PID)

Tests: crates/rtps/src/publication_data.rs::tests::an_absent_reliability_parameter_reads_as_reliable_on_a_publication, crates/rtps/src/publication_data.rs::tests::participant_key_fallback_when_pid_missing

Status: done — the default per PID is listed under §9.6.3.2.

§8.5.4.4 Table 8.82 Publications: DataType

Spec: §8.5.4.4, p. 133, Table 8.82 — “DataType: DiscoveredWriterData”.

Repo: crates/discovery/src/sedp/writer.rs (SedpPublicationsWriter::announce: PublicationBuiltinTopicData::to_pl_cdr_le)

Tests: crates/discovery/tests/sedp_loopback.rs::publication_announce_then_reader_fills_cache

Status: done

§8.5.4.4 Table 8.82 Publications: Cardinality

Spec: §8.5.4.4, p. 133, Table 8.82 — “Cardinality: The number of DataWriters contained by the DomainParticipant. There is a one-to-one correspondence between each DataWriter in the participant and a data-object that describes the DataWriter stored in the WriterHistoryCache for the SEDPbuiltinPublicationsWriter.”

Repo: crates/discovery/src/sedp/writer.rs (make_sedp_writer: one change per instance, SEDP_MAX_CHANGES; SedpPublicationsWriter::announce keyed on the endpoint GUID)

Tests: crates/discovery/src/sedp/writer.rs::tests::every_endpoint_keeps_one_change_for_a_reader_that_matches_later

Status: done

§8.5.4.4 Table 8.82 Publications: insertion

Spec: §8.5.4.4, p. 133, Table 8.82 — “Data-Object insertion: Each time a DataWriter is created in the DomainParticipant.”

Repo: crates/dcps/src/runtime.rs (announce_publication when the writer is created)

Tests: crates/dcps/tests/builtin_topic_readers.rs::linux_e2e::sedp_pub_sub_populates_dcps_publication_and_subscription_readers

Status: done

§8.5.4.4 Table 8.82 Publications: modification

Spec: §8.5.4.4, p. 133, Table 8.82 — “Data-Object modification: Each time the QoS of an existing DataWriter is modified.”

Repo: crates/dcps/src/runtime.rs (reannounce_publication)

Tests: crates/dcps/tests/set_qos_after_enable.rs::a_topic_data_change_reaches_the_writers_announcement, crates/dcps/src/runtime.rs::tests::a_partition_change_unmatches_without_a_status_and_is_announced

Status: done

§8.5.4.4 Table 8.82 Publications: deletion

Spec: §8.5.4.4, p. 133, Table 8.82 — “Data-Object deletion: Each time an existing DataWriter belonging to the DomainParticipant is deleted.”

Repo: crates/discovery/src/sedp/writer.rs (SedpPublicationsWriter::dispose); crates/dcps/src/runtime.rs (dispose_publication on deletion)

Tests: crates/dcps/tests/endpoint_delete_unmatch_e2e.rs::linux_e2e::dropping_a_writer_unmatches_the_remote_reader

Status: done

§8.5.4.4 Table 8.83 Subscriptions: DataType

Spec: §8.5.4.4, p. 134, Table 8.83 — “DataType: DiscoveredReaderData”.

Repo: crates/discovery/src/sedp/writer.rs (SedpSubscriptionsWriter::announce)

Tests: crates/discovery/tests/sedp_loopback.rs::subscription_announce_then_reader_fills_cache

Status: done

§8.5.4.4 Table 8.83 Subscriptions: Cardinality

Spec: §8.5.4.4, p. 134, Table 8.83 — “Cardinality: The number of DataReaders contained by the DomainParticipant. There is a one-to-one correspondence between each DataReaders in the Participant and a data-object that describes the DataReaders stored in the WriterHistoryCache for the SEDPbuiltinSubscriptionsWriter.”

Repo: —

Tests: crates/discovery/src/sedp/writer.rs::tests::every_endpoint_keeps_one_change_for_a_reader_that_matches_later

Status: done — the same writer setup (make_sedp_writer) as under Table 8.82 Cardinality, announced keyed on the GUID.

§8.5.4.4 Table 8.83 Subscriptions: insertion

Spec: §8.5.4.4, p. 134, Table 8.83 — “Data-Object insertion: Each time a DataReader is created in the DomainParticipant.”

Repo: crates/dcps/src/runtime.rs (announce_subscription when the reader is created)

Tests: crates/dcps/tests/builtin_topic_readers.rs::linux_e2e::sedp_pub_sub_populates_dcps_publication_and_subscription_readers

Status: done

§8.5.4.4 Table 8.83 Subscriptions: modification

Spec: §8.5.4.4, p. 134, Table 8.83 — “Data-Object modification: Each time the QoS of an existing DataReader is modified.”

Repo: crates/dcps/src/runtime.rs (announce_subscription after set_qos)

Tests: crates/dcps/tests/set_qos_after_enable.rs::a_reader_deadline_change_makes_the_pair_incompatible, crates/dcps/src/runtime.rs::tests::the_content_filter_travels_in_the_subscription_and_is_reannounced

Status: done

§8.5.4.4 Table 8.83 Subscriptions: deletion

Spec: §8.5.4.4, p. 134, Table 8.83 — “Data-Object deletion: Each time an existing DataReader belonging to the DomainParticipant is deleted.”

Repo: crates/discovery/src/sedp/writer.rs (SedpSubscriptionsWriter::dispose)

Tests: crates/dcps/tests/endpoint_delete_unmatch_e2e.rs::linux_e2e::dropping_a_reader_unmatches_the_remote_writer

Status: done

§8.5.4.4 Table 8.84 Topics: DataType

Spec: §8.5.4.4, p. 134, Table 8.84 — “DataType: DiscoveredTopicData”.

Repo: crates/discovery/src/sedp/writer.rs (SedpTopicsWriter::announce)

Tests: crates/discovery/src/sedp/stack.rs::tests::two_stacks_exchange_a_topic_its_new_qos_and_its_dispose

Status: done

§8.5.4.4 Table 8.84 Topics: Cardinality

Spec: §8.5.4.4, p. 134, Table 8.84 — “Cardinality: The number of Topics created by the DomainParticipant. There is a one-to-one correspondence between each Topic created by the DomainParticipant and a data-object that describes the Topic stored in the WriterHistoryCache for the builtinTopicsWriter.”

Repo: —

Tests: crates/discovery/src/sedp/writer.rs::tests::every_endpoint_keeps_one_change_for_a_reader_that_matches_later

Status: done — the same writer setup (make_sedp_writer) as under Table 8.82 Cardinality, announced keyed on the GUID.

§8.5.4.4 Table 8.84 Topics: insertion

Spec: §8.5.4.4, p. 134, Table 8.84 — “Data-Object insertion: Each time a Topic is created in the DomainParticipant.”

Repo: crates/dcps/src/participant.rs (announce_topic on creation or enable)

Tests: crates/dcps/tests/builtin_topic_readers.rs::linux_e2e::a_created_topic_reaches_dcps_topic_with_every_member_and_its_deletion_disposes_it

Status: done

§8.5.4.4 Table 8.84 Topics: modification

Spec: §8.5.4.4, p. 134, Table 8.84 — “Data-Object modification: Each time the QoS of an existing Topic is modified.”

Repo: crates/dcps/src/topic.rs (set_qos → announce_topic)

Tests: crates/discovery/src/sedp/stack.rs::tests::two_stacks_exchange_a_topic_its_new_qos_and_its_dispose

Status: done — the test checks the SEDP stack, not the call from Topic::set_qos.

§8.5.4.4 Table 8.84 Topics: deletion

Spec: §8.5.4.4, p. 134, Table 8.84 — “Data-Object deletion: Each time an existing Topic belonging to the DomainParticipant is deleted.”

Repo: crates/dcps/src/runtime.rs (dispose_local_topic)

Tests: crates/dcps/tests/builtin_topic_readers.rs::linux_e2e::delete_topic_disposes_the_announced_topic_and_a_writer_holds_it

Status: done

§8.5.5 Interaction with the virtual machine

Spec: §8.5.5, p. 134 — “To further illustrate the SPDP and SEDP, this specification describes how the information provided by the SPDP can be used to configure the SEDP built-in Endpoints in the RTPS virtual machine.”

Repo: —

Tests: —

Status: n/a (informative) — introduction to §8.5.5.1 and §8.5.5.2.

§8.5.5.1 New participant: compare domainId

Spec: §8.5.5.1, pp. 134–135 — “IF ( participant_data.domainId != local_participant.domainId ) THEN RETURN;”

Repo: crates/dcps/src/runtime.rs (spdp_announced: PID_DOMAIN_ID)

Tests: crates/dcps/src/runtime.rs::tests::a_participant_of_another_domain_id_is_not_discovered, crates/dcps/src/runtime.rs::tests::a_beacon_of_another_domain_is_named_once_per_sender

Status: done — a missing PID_DOMAIN_ID counts as the own domain.

§8.5.5.1 New participant: compare domainTag

Spec: §8.5.5.1, p. 135 — “IF ( !STRING_EQUAL(participant_data.domainTag, local_participant.domainTag) ) THEN RETURN;”

Repo: crates/dcps/src/runtime.rs (spdp_announced)

Tests: crates/dcps/src/runtime.rs::tests::a_participant_of_another_domain_tag_is_not_discovered

Status: done

§8.5.5.1 New participant: proxies per announced endpoint

Spec: §8.5.5.1, pp. 135–136 — “IF ( PUBLICATIONS_DETECTOR IS_IN participant_data.availableEndpoints ) THEN … writer.matched_reader_add(proxy);” and likewise for PUBLICATIONS_ANNOUNCER, SUBSCRIPTIONS_DETECTOR, SUBSCRIPTIONS_ANNOUNCER, TOPICS_DETECTOR, TOPICS_ANNOUNCER.

Repo: crates/discovery/src/sedp/stack.rs (on_participant_discovered)

Tests: crates/discovery/src/sedp/stack.rs::tests::discovered_participant_wires_all_four_endpoints_when_present, crates/discovery/src/sedp/stack.rs::tests::the_topics_bits_wire_the_topics_writer_and_reader, crates/discovery/tests/opensplice_spdp_bundle.rs::the_participant_with_the_detectors_gets_the_local_sedp_writers_proxies

Status: done — the proxies get the metatraffic unicast locators (or else the default unicast locators), no multicast locators.

§8.5.5.2 Participant removed: remove the proxies of the SEDP endpoints

Spec: §8.5.5.2, p. 136 — “Based on the remote Participant’s leaseDuration, a local Participant ‘local_participant’ concludes that a previously discovered Participant with GUID_t participant_guid is no longer present. The Participant ‘local_participant’ must reconfigure any local Endpoints that were communicating with Endpoints in the Participant”.

Repo: crates/discovery/src/sedp/stack.rs (on_participant_lost); crates/dcps/src/runtime.rs (lease expiry and departure)

Tests: crates/discovery/src/sedp/stack.rs::tests::on_participant_lost_clears_proxies_and_cache, crates/discovery/tests/cyclone_sedp_replay.rs::replay_after_participant_lost_stops_accepting_publications, crates/dcps/src/runtime.rs::tests::participant_lease_lifecycle_hard_death_and_same_prefix

Status: done

§8.5.6 Other discovery protocols

Spec: §8.5.6, p. 136 — “Remote Participants using a different vendor’s RTPS implementation must be contacted using at least the SPDP to ensure interoperability. There is no such requirement when the remote Participant uses the same RTPS implementation.”

Repo: crates/dcps/src/runtime.rs (SPDP runs in every participant; a shortcut within one process through inproc_announce_publication)

Tests: crates/dcps/src/runtime.rs::tests::handle_spdp_registers_real_fastdds_participant, crates/discovery/tests/fastdds_spdp_repro.rs::zerodds_parses_real_fastdds_spdp

Status: done

§8.5.6 A common EDP

Spec: §8.5.6, p. 137 — “All Participants must support at least the SEDP, so they always have at least one EDP in common. However, if two Participants both support another EDP, this alternative protocol can be used instead.”

Repo: —

Tests: —

Status: n/a (informative) — the duty to SEDP is listed under §8.5.1; the rest is a permission.

§8.6 Versioning and Extensibility

§8.6 Processing higher minor versions

Spec: §8.6, p. 137 — “Implementations of this version of the RTPS protocol should be able to process RTPS Messages not only with the same major version but possibly higher minor versions.”

Repo: crates/rtps/src/datagram.rs (decode_datagram: only a higher major version is refused)

Tests: crates/rtps/src/datagram.rs::tests::decode_accepts_minor_version_above_supported, crates/rtps/src/datagram.rs::tests::decode_rejects_major_version_above_supported

Status: done

§8.6.1 Skip unknown submessages

Spec: §8.6.1, p. 137 — “Additional Submessages with other submessageIds can be introduced and used anywhere in an RTPS Message. An implementation should skip over unknown Submessages using the submessageLength field in the SubmessageHeader.”

Repo: crates/rtps/src/datagram.rs (decode_datagram, ParsedSubmessage::Unknown)

Tests: crates/rtps/src/datagram.rs::tests::decode_skips_unknown_submessage_without_must_understand, crates/rtps/src/datagram.rs::tests::decode_skips_an_unknown_submessage_whatever_its_flags

Status: done — a submessage with an unknown SubmessageId is skipped by submessageLength, also with flag bit 7 set (§8.3.4.1 rule 3 has no must-understand at submessage level).

§8.6.1 Skip additional fields at the end of a submessage

Spec: §8.6.1, p. 137 — “Additional fields can be added to the end of a Submessage that was already defined in the current minor version. An implementation should skip over additional fields using the submessageLength field in the SubmessageHeader.”

Repo: crates/rtps/src/datagram.rs (decode_submessage); the read_body of the submessages in crates/rtps/src/submessages.rs

Tests: crates/rtps/src/datagram.rs::tests::additional_fields_at_the_end_of_a_known_submessage_are_skipped

Status: done — HEARTBEAT, ACKNACK, GAP, HEARTBEAT_FRAG, NACK_FRAG, INFO_TS, INFO_SRC, INFO_REPLY, INFO_REPLY_IP4 and INFO_DST give the same value with eight more octets at the end of the body as without. For DATA and DATA_FRAG the body ends with the payload; new fields before it are skipped through octetsToInlineQos.

§8.6.1 Ignore unknown built-in endpoints

Spec: §8.6.1, p. 137 — “Additional built-in Endpoints with new IDs can be added. An implementation should ignore any unknown built-in Endpoints.”

Repo: crates/discovery/src/sedp/stack.rs (routing of known EntityIds only); crates/discovery/src/sedp/stack.rs (on_participant_discovered: known bits only)

Tests: crates/discovery/src/sedp/stack.rs::tests::routing_unknown_with_wrong_writer_does_not_match, crates/discovery/src/sedp/stack.rs::tests::partial_endpoint_set_wires_only_matching_sides

Status: done

§8.6.1 Ignore unknown parameters

Spec: §8.6.1, p. 137 — “Additional parameters with new parameterIds can be added. An implementation should ignore any unknown parameters.”

Repo: crates/rtps/src/parameter_list.rs (ParameterList::from_bytes); crates/rtps/src/publication_data.rs (decoders pass over unknown PIDs)

Tests: crates/rtps/src/publication_data.rs::tests::unknown_pids_are_skipped, crates/rtps/src/parameter_list.rs::tests::validate_must_understand_in_data_pipeline_optional_unknown_pid_passes

Status: done — unknown PIDs with the must-understand bit are listed under §9.4.2.11.

§8.6.1 Extensions raise the minor version

Spec: §8.6.1, p. 137 — “All such changes require an increase of the minor version number.”

Repo: —

Tests: —

Status: n/a (informative) — a requirement on future editions of the specification.

§8.6.2 What cannot change within the major version

Spec: §8.6.2, p. 137 — “A Submessage cannot be deleted. A Submessage cannot be modified except as described in 8.6.1. The meaning of submessageIds cannot be modified.”

Repo: —

Tests: —

Status: n/a (informative) — a requirement on future editions of the specification.

§8.7 Implementing DDS QoS and advanced DDS features using RTPS

§8.7 DDS QoS and advanced features over RTPS

Spec: §8.7, p. 137 — “This sub clause defines how to use RTPS to implement the DDS QoS parameters.” “This sub clause forms a normative part of the specification for the purpose of interoperability.”

Repo: —

Tests: —

Status: n/a (informative) — introduction; the requirements are in §8.7.1 to §8.7.10.

§8.7.1 The writer’s inline QoS at the reader’s request

Spec: §8.7.1, p. 138 — “A stateless Reader’s need for receiving in-line QoS to get information on remote Writers is the justification for requiring a Writer to send in-line QoS if the Reader requests them (8.4.2.2.2).” “For immutable QoS, all RxO QoS are sent in-line … Mutable QoS relevant to the Reader are sent in-line so they may take effect immediately”.

Repo: crates/rtps/src/reliable_writer.rs (sample_inline_qos: inline_writer_qos for readers with expectsInlineQos); crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_reader_that_expects_inline_qos_gets_the_writers_qos_with_each_data, crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.1 TOPIC_NAME in the inline QoS

Spec: §8.7.1, p. 138 — “If in-line QoS parameters are expected, implementations must also include the topic name as an in-line parameter.”

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::TOPIC_NAME first)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.1 Coherent-set and filter parameters

Spec: §8.7.1, p. 138 — “Independent of whether Readers expect in-line QoS parameters, a Data Submessage may also contain in-line parameters related to coherent sets and content-filtered topics.”

Repo: —

Tests: —

Status: n/a (informative) — refers to §8.7.3 and §8.7.6.

§8.7.1 Stateful readers may pass over the inline QoS

Spec: §8.7.1, p. 138 — “For improved performance, stateful implementations may ignore in-line QoS and instead rely solely on cached values obtained through Discovery.”

Repo: —

Tests: —

Status: n/a (informative) — no requirement; ZeroDDS readers take the writer’s QoS from SEDP.

§8.7.2 Table 8.85 USER_DATA

Spec: §8.7.2, p. 138, Table 8.85 — “USER_DATA — None — No”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: not in IN_LINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 TOPIC_DATA

Spec: §8.7.2, p. 138, Table 8.85 — “TOPIC_DATA — None — No”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: not in IN_LINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 GROUP_DATA

Spec: §8.7.2, p. 138, Table 8.85 — “GROUP_DATA — None — No”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: not in IN_LINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 DURABILITY

Spec: §8.7.2, p. 138, Table 8.85 — “DURABILITY — See 8.7.2.2.1 — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::DURABILITY)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 DURABILITY_SERVICE

Spec: §8.7.2, p. 138, Table 8.85 — “DURABILITY_SERVICE — None — No”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: not in IN_LINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 PRESENTATION

Spec: §8.7.2, p. 138, Table 8.85 — “PRESENTATION — See 8.7.2.2.2 — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::PRESENTATION)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 DEADLINE

Spec: §8.7.2, p. 138, Table 8.85 — “DEADLINE — None — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::DEADLINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 LATENCY_BUDGET

Spec: §8.7.2, p. 138, Table 8.85 — “LATENCY_BUDGET — None — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::LATENCY_BUDGET)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 OWNERSHIP

Spec: §8.7.2, p. 138, Table 8.85 — “OWNERSHIP — None — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::OWNERSHIP)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 OWNERSHIP_STRENGTH

Spec: §8.7.2, p. 138, Table 8.85 — “OWNERSHIP_STRENGTH — None — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::OWNERSHIP_STRENGTH)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 LIVELINESS

Spec: §8.7.2, p. 138, Table 8.85 — “LIVELINESS — See 8.7.2.2.3 — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::LIVELINESS)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 TIME_BASED_FILTER

Spec: §8.7.2, p. 139, Table 8.85 — “TIME_BASED_FILTER — See 8.7.2.2.4 — No”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: not in IN_LINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 PARTITION

Spec: §8.7.2, p. 139, Table 8.85 — “PARTITION — None — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::PARTITION)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 RELIABILITY

Spec: §8.7.2, p. 139, Table 8.85 — “RELIABILITY — See 8.7.2.2.5 — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::RELIABILITY)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 TRANSPORT_PRIORITY

Spec: §8.7.2, p. 139, Table 8.85 — “TRANSPORT_PRIORITY — None — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::TRANSPORT_PRIORITY when not 0)

Tests: crates/rtps/src/publication_data.rs::tests::a_transport_priority_goes_in_line_and_not_into_the_announcement

Status: done

§8.7.2 Table 8.85 LIFESPAN

Spec: §8.7.2, p. 139, Table 8.85 — “LIFESPAN — None — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::LIFESPAN)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 DESTINATION_ORDER

Spec: §8.7.2, p. 139, Table 8.85 — “DESTINATION_ORDER — See 8.7.2.2.6 — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::DESTINATION_ORDER)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 HISTORY

Spec: §8.7.2, p. 139, Table 8.85 — “HISTORY — None — No”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: not in IN_LINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 RESOURCE_LIMITS

Spec: §8.7.2, p. 139, Table 8.85 — “RESOURCE_LIMITS — None — No”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: not in IN_LINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 ENTITY_FACTORY

Spec: §8.7.2, p. 139, Table 8.85 — “ENTITY_FACTORY — None — No”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: not in IN_LINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 WRITER_DATA_LIFECYCLE

Spec: §8.7.2, p. 139, Table 8.85 — “WRITER_DATA_LIFECYCLE — See 8.7.2.2.7 — No”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: not in IN_LINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 READER_DATA_LIFECYCLE

Spec: §8.7.2, p. 139, Table 8.85 — “READER_DATA_LIFECYCLE — None — No”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: not in IN_LINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2.1 Missing inline QoS: default by DDS

Spec: §8.7.2.1, p. 139 — “If a Reader expects to receive in-line QoS parameters and any of these QoS parameters are missing, it will assume the default value for that QoS parameter, where the default is defined by DDS.”

Repo: —

Tests: —

Status: n/a (informative) — the condition does not occur: ZeroDDS readers announce expectsInlineQos = FALSE and take the writer’s QoS from SEDP.

§8.7.2.1 TOPIC_NAME for self-describing messages

Spec: §8.7.2.1, p. 139 — “In order to achieve self-describing messages, not only the parameters defined in Table 8.85 have to be sent with the submessage, but also a parameter TOPIC_NAME.”

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2.2.1 DURABILITY

Spec: §8.7.2.2.1, p. 139 — “While volatile and transient-local durability do not affect the RTPS protocol, support for transient and persistent durability may. This is not covered in the current version of the specification.”

Repo: —

Tests: —

Status: n/a (informative) — no requirement.

§8.7.2.2.2 PRESENTATION

Spec: §8.7.2.2.2, p. 139 — “Sub clause 8.7.5 defines how to implement the GROUP ordered access policy of the PRESENTATION QoS. Sub clause 8.7.6 defines how to implement the coherent access policy of the PRESENTATION QoS.”

Repo: —

Tests: —

Status: n/a (informative) — refers to §8.7.5 and §8.7.6.

§8.7.2.2.3 LIVELINESS AUTOMATIC

Spec: §8.7.2.2.3, p. 139 — “DDS_AUTOMATIC_LIVELINESS_QOS : liveliness is maintained through the BuiltinParticipantMessageWriter. … implementations must refresh the Participant’s liveliness (i.e., send the ParticipantMessageData, see (8.4.13.5) at a rate faster than the smallest lease duration among the Writers.”

Repo: crates/dcps/src/runtime.rs (refresh_wlp_period); crates/dcps/src/wlp.rs (WlpEndpoint::tick)

Tests: crates/dcps/tests/liveliness_qos.rs::linux::an_automatic_writer_that_never_writes_stays_alive_at_a_remote_reader

Status: done

§8.7.2.2.3 LIVELINESS MANUAL_BY_PARTICIPANT

Spec: §8.7.2.2.3, p. 139 — “If the Participant has any MANUAL_BY_PARTICIPANT Writers, implementations must check periodically to see if write(), assert_liveliness(), dispose(), or unregister_instance() was called for any of them. The period for this check equals the smallest lease duration among the Writers. If any of the operations were called, implementations must refresh the Participant’s liveliness (i.e., send the ParticipantMessageData, see 8.4.13.5).”

Repo: crates/dcps/src/runtime.rs (refresh_manual_by_participant, calls in write_user_sample_*, write_user_lifecycle_with, assert_writer_liveliness_eid, bump_manual_liveliness_count); crates/dcps/src/wlp.rs

Tests: crates/dcps/src/runtime.rs::tests::a_manual_by_participant_writer_refreshes_the_participant_liveliness, crates/dcps/src/wlp.rs::tests::refreshes_before_the_tick_share_one_manual_by_participant_sample, crates/dcps/src/runtime.rs::tests::the_manual_liveliness_count_of_the_announcement_counts_up

Status: done — write, assert_liveliness, dispose and unregister_instance of a MANUAL_BY_PARTICIPANT writer cause a ParticipantMessageData with MANUAL_LIVELINESS_UPDATE at the next tick (instead of a check at the rate of the smallest lease) and raise the manualLivelinessCount of the SPDP announcement.

§8.7.2.2.3 LIVELINESS MANUAL_BY_TOPIC

Spec: §8.7.2.2.3, p. 140 — “The standard RTPS Messages that result from calling write(), dispose(), or unregister_instance() on a Writer Entity suffice to assert the liveliness of a Writer with LIVELINESS QoS set to MANUAL_BY_TOPIC. When assert_liveliness() is called, the Writer must send a Heartbeat Message with final flag and liveliness flag set.”

Repo: crates/rtps/src/reliable_writer.rs (liveliness_heartbeat); crates/dcps/src/runtime.rs (assert_writer_liveliness_eid)

Tests: crates/rtps/src/reliable_writer.rs::tests::liveliness_heartbeat_is_a_final_heartbeat_with_the_liveliness_flag, crates/dcps/tests/liveliness_qos.rs::linux::assert_liveliness_keeps_a_manual_writer_alive_at_a_remote_reader, crates/dcps/src/runtime.rs::tests::a_manual_writer_goes_not_alive_when_silent_and_back_when_it_writes

Status: done

§8.7.2.2.4 TIME_BASED_FILTER on the writer side

Spec: §8.7.2.2.4, p. 140 — “Implementations may optimize bandwidth usage by applying a time-based filter on the Writer side. … When one or more data updates are filtered out on the Writer side, implementations must send a Gap Submessage instead, indicating which samples were filtered out. This Submessage must be sent before the next update”.

Repo: —

Tests: —

Status: open — an optional function; ZeroDDS applies TIME_BASED_FILTER only on the reader side (tbf_should_deliver) and sends no GAP for time-filtered samples.

§8.7.2.2.5 RELIABILITY

Spec: §8.7.2.2.5, p. 140 — “Implementations must meet the reliable RTPS protocol requirements for interoperability, defined in 8.4.2.”

Repo: —

Tests: —

Status: n/a (informative) — a reference; the requirements are listed under §8.4.2.

§8.7.2.2.6 DESTINATION_ORDER BY_SOURCE_TIMESTAMP

Spec: §8.7.2.2.6, p. 140 — “In order to implement the DDS_BY_SOURCE_TIMESTAMP_DESTINATIONORDER_QOS policy, implementations must include an InfoTimestamp Submessage with every update from a Writer.”

Repo: crates/rtps/src/reliable_writer.rs (append_info_ts before every DATA and every DATA_FRAG); crates/dcps/src/runtime.rs (every write gets a source timestamp)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_stamped_prepends_info_ts_before_data, crates/rtps/src/reliable_writer.rs::tests::write_lifecycle_prepends_info_ts_before_data, crates/rtps/src/reliable_writer.rs::tests::resend_carries_original_info_ts

Status: done

§8.7.2.2.7 WRITER_DATA_LIFECYCLE autodispose

Spec: §8.7.2.2.7, p. 140 — “If autodispose_unregistered_instances is enabled, Data Messages that unregister an instance must also dispose it.”

Repo: crates/dcps/src/publisher.rs (unregister_instance: DISPOSED with UNREGISTERED under autodispose_unregistered_instances)

Tests: crates/dcps/tests/writer_data_lifecycle_qos.rs::autodispose_default_true_unregister_disposes, crates/dcps/tests/lifecycle_wire_e2e.rs::linux::unregister_with_autodispose_false_propagates_unregister_only

Status: done

§8.7.3 Filtering on the reader side

Spec: §8.7.3, p. 140 — “When filtering on the Reader side only, samples which do not pass the filter are simply dropped by the middleware. In this case, no further extensions to RTPS are needed.”

Repo: crates/dcps/src/subscriber.rs (filter of the ContentFilteredTopic)

Tests: crates/dcps/tests/content_filtered_reader.rs::a_reader_on_a_content_filtered_topic_delivers_what_the_filter_accepts, crates/dcps/tests/content_filter.rs::filter_drops_samples_that_return_false

Status: done

§8.7.3 Filtering on the writer side

Spec: §8.7.3, p. 140 — “In order to support Writer side filtering, standard RTPS extension mechanisms are used to: Include Reader filter information during the Endpoint discovery phase. Include filter results with each data sample.” §8.7.3.4, p. 142: “Writer side filtering constitutes an optimization and is optional”.

Repo: —

Tests: —

Status: open — an optional function; ZeroDDS does not filter on the writer side. The filter information of the reader in SEDP is listed under §8.7.3.1.

§8.7.3 Hints by the writer: ALIVE_FILTERED, ContentFilterInfo, omitted data

Spec: §8.7.3, p. 140 — “The Writer may indicate to a Reader that a Sample has been filtered … by sending a directed Data message that includes only the key information (DataFlag=0), indicating in the Inline Qos that the instance state is ALIVE_FILTERED.” “Alternatively, the Writer may not send a Data message at all. This is only allowed if the previous sample for that Instance was already filtered for that Reader”.

Repo: —

Tests: —

Status: open — part of the optional filtering on the writer side (§8.7.3), which ZeroDDS does not perform.

§8.7.3.1 ContentFilterProperty_t in DiscoveredReaderData

Spec: §8.7.3.1, p. 141 — “RTPS adds an additional ContentFilterProperty_t field to DiscoveredReaderData, defined in Table 8.86.”

Repo: crates/rtps/src/subscription_data.rs (SubscriptionBuiltinTopicData::content_filter, ContentFilterProperty)

Tests: crates/rtps/src/subscription_data.rs::tests::subscription_with_content_filter_roundtrip_le, crates/dcps/src/runtime.rs::tests::the_content_filter_travels_in_the_subscription_and_is_reannounced

Status: done

§8.7.3.1 Table 8.86 contentFilteredTopicName

Spec: §8.7.3.1, p. 141, Table 8.86 — “contentFilteredTopicName: string — Name of the Content-filtered Topic associated with the Reader. Must have non-zero length.”

Repo: crates/rtps/src/subscription_data.rs (ContentFilterProperty::content_filtered_topic_name); crates/dcps/src/participant.rs (create_contentfilteredtopic refuses an empty name)

Tests: crates/rtps/src/subscription_data.rs::tests::content_filter_property_roundtrip_le, crates/dcps/src/participant.rs::tests::create_contentfilteredtopic_rejects_empty_name

Status: done

§8.7.3.1 Table 8.86 relatedTopicName

Spec: §8.7.3.1, p. 141, Table 8.86 — “relatedTopicName: string — Name of the Topic related to the Content-filtered Topic. Must have non-zero length.”

Repo: crates/rtps/src/subscription_data.rs (ContentFilterProperty::related_topic_name); crates/dcps/src/topic.rs (ContentFilteredTopic::property)

Tests: crates/rtps/src/subscription_data.rs::tests::content_filter_property_roundtrip_le

Status: done

§8.7.3.1 Table 8.86 filterClassName

Spec: §8.7.3.1, p. 141, Table 8.86 — “filterClassName: string … Must have non-zero length. RTPS predefines the following values: “DDSSQL” Default filter class name if none specified.”

Repo: crates/rtps/src/subscription_data.rs (filter_class::DDSSQL); crates/dcps/src/topic.rs (ContentFilteredTopic::content_filter_property: DDSSQL or the registered class)

Tests: crates/rtps/src/subscription_data.rs::tests::content_filter_property_roundtrip_le, crates/dcps/src/runtime.rs::tests::the_content_filter_travels_in_the_subscription_and_is_reannounced, crates/dcps/tests/custom_content_filter.rs::a_registered_filter_class_is_named_announced_and_applied

Status: done

§8.7.3.1 Table 8.86 filterExpression

Spec: §8.7.3.1, p. 141, Table 8.86 — “filterExpression: string — The actual filter expression. Must be a valid expression for the filter class specified using filterClassName. Must have non-zero length.”

Repo: crates/rtps/src/subscription_data.rs (ContentFilterProperty::filter_expression); crates/dcps/src/participant.rs (create_contentfilteredtopic refuses an empty expression)

Tests: crates/rtps/src/subscription_data.rs::tests::content_filter_property_roundtrip_le, crates/dcps/src/participant.rs::tests::create_contentfilteredtopic_rejects_empty_expression

Status: done

§8.7.3.1 Table 8.86 expressionParameters

Spec: §8.7.3.1, p. 141, Table 8.86 — “expressionParameters: stringSequence — Defines the value for each parameter in the filter expression. Can have zero length if the filter expression contains no parameters.”

Repo: crates/rtps/src/subscription_data.rs (ContentFilterProperty::expression_parameters)

Tests: crates/rtps/src/subscription_data.rs::tests::content_filter_property_roundtrip_le, crates/dcps/src/runtime.rs::tests::the_content_filter_travels_in_the_subscription_and_is_reannounced

Status: done

§8.7.3.1 A writer without the matching filter class

Spec: §8.7.3.1, p. 141 — “In order for the Writer to apply the filter, it must have been configured to handle filters of the specified filter class. If not, the Writer will simply ignore the filter information and not filter any data samples.”

Repo: —

Tests: —

Status: open — part of the optional filtering on the writer side (§8.7.3), which ZeroDDS does not perform.

§8.7.3.1 Changed filter parameters through endpoint discovery

Spec: §8.7.3.1, p. 141 — “Each time the parameters are modified, the updated information is exchanged using the Endpoint discovery protocol.”

Repo: crates/dcps/src/runtime.rs (update_user_reader_content_filter)

Tests: crates/dcps/src/runtime.rs::tests::the_content_filter_travels_in_the_subscription_and_is_reannounced

Status: done

§8.7.3.2 Indicating a filtered sample

Spec: §8.7.3.2, p. 141 — “When this happens, the Writer can use a Data submessage that does not contain a Data payload (DataFlag=0) and sets FilteredFlag=1, see 8.3.8.2.2.”

Repo: —

Tests: —

Status: open — part of the optional filtering on the writer side (§8.7.3), which ZeroDDS does not perform. The Data submessage has no FilteredFlag; the FilteredFlag belongs to StatusInfo_t (§9.6.4.9).

§8.7.3.3 GAP instead of DATA and filter results in the inline QoS

Spec: §8.7.3.3, p. 142 — “In that case, the Data submessage is replaced by a Gap submessage.” “The sample passes some or all of the filters. In that case, the sample must still be sent and the writer must include information with the Data submessage on what filters were applied and the according result.”

Repo: —

Tests: —

Status: open — part of the optional filtering on the writer side (§8.7.3), which ZeroDDS does not perform.

§8.7.3.3 Table 8.87 filterResult

Spec: §8.7.3.3, p. 142, Table 8.87 — “filterResult: FilterResult_t — For each filter signature, the results indicate whether the sample passed the filter.”

Repo: —

Tests: —

Status: open — part of the optional filtering on the writer side (§8.7.3), which ZeroDDS does not perform; PID_CONTENT_FILTER_INFO is not sent.

§8.7.3.3 Table 8.87 filterSignatures

Spec: §8.7.3.3, p. 142, Table 8.87 — “filterSignatures: FilterSignature_t[] — A list of filters that were applied to the sample.”

Repo: —

Tests: —

Status: open — part of the optional filtering on the writer side (§8.7.3), which ZeroDDS does not perform; PID_CONTENT_FILTER_INFO is not sent.

§8.7.3.4 Readers filter when the writer does not

Spec: §8.7.3.4, p. 142 — “Samples will always be filtered on the Reader side if: The Writer side did not apply any filtering. The Writer side did not apply the filter expected by the Reader. … The Reader side does not support Writer side filtering”.

Repo: crates/dcps/src/subscriber.rs (filter per received sample)

Tests: crates/dcps/tests/content_filtered_reader.rs::a_reader_on_a_content_filtered_topic_delivers_what_the_filter_accepts, crates/dcps/tests/content_filter.rs::filter_applies_also_to_read_peek

Status: done

§8.7.3.4 Filter class DDSSQL

Spec: §8.7.3.4, p. 143 — “If an implementation supports Content-filtered Topics, it must at least recognize the “DDSSQL” filter class, as mandated by the DDS specification.”

Repo: crates/dcps/src/topic.rs (ContentFilteredTopic, SQL filter); crates/rtps/src/subscription_data.rs (filter_class::DDSSQL)

Tests: crates/dcps/tests/content_filtered_reader.rs::a_reader_on_a_content_filtered_topic_delivers_what_the_filter_accepts, crates/dcps/tests/content_filtered_reader.rs::a_field_the_type_does_not_answer_delivers_nothing

Status: done

§8.7.3.4 Custom filter classes can be registered

Spec: §8.7.3.4, p. 143 — “For all other filter classes, both implementations must allow the user to register the same custom filter class.”

Repo: crates/dcps/src/topic.rs (ContentFilter, ContentFilteredTopic); crates/dcps/src/participant.rs (DomainParticipant::register_contentfilter, lookup_contentfilter, unregister_contentfilter, create_contentfilteredtopic_with_class)

Tests: crates/dcps/tests/custom_content_filter.rs::a_registered_filter_class_is_named_announced_and_applied, crates/dcps/tests/custom_content_filter.rs::the_registry_refuses_what_it_cannot_serve

Status: done — the application registers a filter class per participant and type (register_contentfilter::<T>(name, Arc<dyn ContentFilter<T>>); DDSSQL is the implementation’s own class and cannot be registered; names up to 256 octets). create_contentfilteredtopic_with_class names the class; the class checks expression and parameters (compile, at creation and at set_filter_parameters) and filters the samples of a DataReader on the topic (evaluate). The class name goes out as filterClassName in the reader’s PID_CONTENT_FILTER_PROPERTY. A class a peer has not registered is ignored by it per §8.7.3.4, and the samples are filtered on the reader side; ZeroDDS does not filter on the writer side.

§8.7.3.4 Information for ALIVE_FILTERED despite filtering at the writer

Spec: §8.7.3.4, p. 143 — “Even if the Writer is performing writer-side filtering, the Writer must provide enough information for the Reader to correctly transition the instance state to ALIVE_FILTERED.”

Repo: —

Tests: —

Status: open — part of the optional filtering on the writer side (§8.7.3), which ZeroDDS does not perform; every sample goes to every matched reader.

§8.7.4 Instance state changes through Data and inline QoS

Spec: §8.7.4, p. 143 — “RTPS uses regular Data Submessages and the in-line QoS parameter extension mechanism to communicate instance state changes. The serialized information within the inline QoS contains the new InstanceState”.

Repo: crates/dcps/src/runtime.rs (write_user_lifecycle); crates/rtps/src/reliable_writer.rs (write_lifecycle: PID_STATUS_INFO)

Tests: crates/dcps/tests/lifecycle_wire_e2e.rs::linux::dispose_propagates_over_wire_to_reader, crates/dcps/tests/lifecycle_wire_decode.rs::reader_push_lifecycle_disposed_sets_instance_state

Status: done

§8.7.4 Only the key in the SerializedPayload

Spec: §8.7.4, p. 143 — “When RTPS sends a Data Submessage to communicate instance state changes it may include only the Key of the Data-Object within the SerializedPayload submessage element”.

Repo: crates/dcps/src/runtime.rs (write_user_lifecycle: lifecycle_serialized_key)

Tests: crates/dcps/tests/lifecycle_wire_e2e.rs::linux::dispose_marker_carries_the_key_fields_of_a_string_keyed_type

Status: done

§8.7.4 Registration only with the first value

Spec: §8.7.4, p. 143 — “An implementation of RTPS is not required to propagate registration changes until the DDS DataWriter writes the first value for that Data-Object instance.”

Repo: —

Tests: —

Status: n/a (informative) — no requirement.

§8.7.4 A value that does not pass the filter

Spec: §8.7.4, p. 143 — “If the previous update to the instance passed the filter, then the Writer must send a Data Submessage that either includes the data value, or else indicates the InstanceState is ALIVE_FILTERED.” “If the previous update to the instance did not pass the filter, then the Writer may omit sending the Data Submessage to the Reader.”

Repo: —

Tests: —

Status: open — part of the optional filtering on the writer side (§8.7.3), which ZeroDDS does not perform; ZeroDDS sends every value.

§8.7.4 Dispose and unregister message

Spec: §8.7.4, pp. 143–144 — “This so called “dispose/unregister message” shall be sent if any of the following conditions is met: 1. The Reader does not have a Content Filter. 2. The Writer has previously sent a Data message to the Reader for that same instance. 3. The Reader has OWNERSHIP QosPolicy kind EXCLUSIVE …”

Repo: crates/dcps/src/runtime.rs (write_user_lifecycle: to every matched reader)

Tests: crates/dcps/tests/lifecycle_wire_e2e.rs::linux::dispose_propagates_over_wire_to_reader, crates/dcps/tests/lifecycle_wire_e2e.rs::linux::instance_goes_no_writers_when_its_last_writer_disappears

Status: done — ZeroDDS sends the message in every case.

§8.7.5 PID_GROUP_SEQ_NUM and PID_WRITER_GROUP_INFO

Spec: §8.7.5, p. 144 — “In order to support group ordered access, RTPS uses the in-line QoS parameter extension mechanism to include additional information with each CacheChange. … PID_GROUP_SEQ_NUM to contain the group sequence number. PID_WRITER_GROUP_INFO to contain the WriterGroupInfo_t”.

Repo: —

Tests: crates/rtps/src/reliable_writer.rs::tests::a_group_writers_data_carries_its_group_sequence_number, crates/rtps/src/reliable_writer.rs::tests::a_writer_outside_a_group_sends_no_group_parameter, crates/rtps/src/inline_qos.rs::tests::group_seq_num_is_a_cdr_sequence_number_with_pid_0x0064, crates/rtps/src/inline_qos.rs::tests::writer_group_info_carries_the_four_digest_octets_with_pid_0x0065

Status: done

§8.7.5 Table 8.88 WriterGroupInfo_t writerSet

Spec: §8.7.5, p. 144, Table 8.88 — “writerSet: GroupDigest_t — Identifies the set of Writer EntityIds that are announced in the DiscoveredWriterData that belonged to the Publisher at the time the sample was written.”

Repo: —

Tests: crates/rtps/src/inline_qos.rs::tests::writer_group_info_carries_the_four_digest_octets_with_pid_0x0065, crates/rtps/src/writer_group.rs::tests::the_writer_set_follows_the_writers, crates/rtps/src/group_digest.rs::tests::two_writers_digest_as_section_9_3_2_5_computes_it

Status: done

§8.7.5 Group sequence number on every Data and the first DataFrag

Spec: §8.7.5, p. 144 — “When a Publisher is configured with access scope GROUP, all Data submessages and the first DataFrag submessage from any Writer within the Publisher are accompanied with a GROUP sequence number sent as part of the in-line QoS. The GROUP sequence number is a strictly monotonically increasing sequence number originating from the Publisher.”

Repo: —

Tests: crates/rtps/src/reliable_writer.rs::tests::a_group_writers_data_carries_its_group_sequence_number, crates/rtps/src/reliable_writer.rs::tests::a_dispose_carries_the_set_and_group_parameters_of_its_change, crates/rtps/src/writer_group.rs::tests::group_sequence_numbers_rise_by_one_per_change_from_one, crates/rtps/src/fragment_assembler.rs::tests::the_first_fragments_inline_qos_reaches_the_completed_sample

Status: done

§8.7.5 Subscriber: commit by group sequence number

Spec: §8.7.5, pp. 144–145 — “A sample with GROUP sequence number GSN can be committed to the DDS DataReader from the Subscriber’s history cache if any of the following conditions apply: GSN-1 has been already been committed. It has been determined that none of the remote DataWriters that match reliable DataReaders have GSN-1.”

Repo: crates/dcps/src/group_order.rs (GroupOrder), crates/dcps/src/subscriber.rs (SubscriberInner::release_group)

Tests: crates/dcps/src/group_order.rs::tests::samples_of_two_writers_go_out_in_group_sequence_order, crates/dcps/src/group_order.rs::tests::a_number_no_counted_writer_has_is_passed_once_a_heartbeat_announced_it, crates/dcps/src/group_order.rs::tests::a_counted_writer_whose_heartbeat_range_holds_the_number_is_waited_for, crates/dcps/src/group_order.rs::tests::a_gap_rules_the_number_out_for_its_writer, crates/dcps/src/group_order.rs::tests::a_number_waits_for_the_copy_of_every_reader_of_its_writer, crates/dcps/tests/group_access_e2e.rs::a_reader_of_one_topic_gets_its_samples_without_the_others_numbers_over_udp, crates/dcps/tests/group_access_e2e.rs::two_readers_of_one_topic_each_get_every_sample_over_udp

Status: done

§8.7.5 Only writers with liveliness

Spec: §8.7.5, p. 145 — “The above rules should only take into consideration DataWriters that have not lost their liveliness, see 8.7.2.2.3.”

Repo: crates/dcps/src/runtime.rs (DcpsRuntime::user_reader_counted_writers)

Tests: crates/dcps/src/runtime.rs::tests::a_writer_that_lost_its_liveliness_is_not_counted_for_the_group_order

Status: done

§8.7.6 Publisher and subscriber coherent sets

Spec: §8.7.6, p. 145 — “A “Publisher coherent set” is defined as the set of all CacheChanges performed by all DataWriters in the Publisher delimited by the operations begin_coherent_changes() and end_coherent_changes().” “What constitutes a “Subscriber coherent set” depends on the PRESENTATION access_scope of the Subscriber”.

Repo: —

Tests: crates/dcps/tests/group_access_e2e.rs::a_group_coherent_set_across_two_topics_appears_after_its_end_over_udp, crates/dcps/tests/group_access_e2e.rs::a_group_coherent_set_across_two_topics_appears_after_its_end_same_runtime, crates/dcps/tests/coherent_changes_e2e.rs::group_coherent_reader_sees_the_set_only_after_end_coherent_changes

Status: done

§8.7.6 Discard incomplete coherent sets

Spec: §8.7.6, p. 145 — “Incomplete coherent sets shall not be added to the history of the RTPS DataReaders and the corresponding CacheChanges shall be discarded by the Subscriber.”

Repo: —

Tests: crates/dcps/src/group_order.rs::tests::a_set_short_of_one_member_is_discarded_and_counted, crates/rtps/src/reliable_reader.rs::tests::a_set_short_of_a_change_ends_incomplete, crates/rtps/src/reliable_reader.rs::tests::a_set_ended_by_a_sample_is_reported_in_front_of_it_when_incomplete, crates/dcps/src/subscriber.rs::tests::an_incomplete_set_is_discarded, crates/dcps/tests/group_access_e2e.rs::a_reader_made_inside_a_set_does_not_get_its_tail_same_runtime

Status: done

§8.7.6 TOPIC scope: PID_COHERENT_SET with the first sequence number

Spec: §8.7.6, p. 146 — “a coherent set is uniquely identified by the sequence number of the first sample update belonging to the coherent set. All sample updates belonging to the same coherent set contain an in-line QoS parameter with this same sequence number.” “the same approach is followed for DataFrag Submessages.”

Repo: —

Tests: crates/rtps/src/reliable_writer.rs::tests::coherent_set_member_data_carries_pid_0x0056_with_set_first_sn_octets, crates/rtps/src/inline_qos.rs::tests::coherent_set_param_is_pid_0x0056_with_sequence_number_layout

Status: done

§8.7.6 End of a writer’s coherent set

Spec: §8.7.6, p. 146 — “The end of a Writer’s coherent set is defined by the arrival of one of the following: A Data Submessage from this Writer that belongs to a new coherent set. A Data Submessage from this Writer that does not contain a coherent set in-line QoS parameter or alternatively, contains a coherent set in-line QoS parameter with value SEQUENCENUMBER_UNKNOWN.”

Repo: —

Tests: crates/rtps/src/reliable_writer.rs::tests::end_coherent_set_emits_ecs_data_with_d_and_k_clear, crates/rtps/src/reliable_reader.rs::tests::end_of_coherent_set_data_is_delivered_as_a_terminator, crates/dcps/src/subscriber.rs::tests::every_end_of_coherent_set_form_releases_the_writers_set, crates/dcps/src/subscriber.rs::tests::a_sample_outside_any_set_releases_the_set_ahead_of_itself, crates/dcps/src/subscriber.rs::tests::a_member_of_a_new_set_releases_the_earlier_set, crates/rtps/src/inline_qos.rs::tests::find_coherent_set_reads_sequencenumber_unknown_as_no_set

Status: done

§8.7.6 GROUP scope: three inline QoS parameters

Spec: §8.7.6, p. 146 — “All Data submessages and the first DataFrag submessage belonging to the same group coherent set shall have three in-line QoS parameters: The PID_GROUP_SEQ_NUM … The PID_COHERENT_SET … The PID_GROUP_COHERENT_SET”.

Repo: —

Tests: crates/rtps/src/reliable_writer.rs::tests::a_group_coherent_set_carries_the_parameters_of_table_9_23, crates/rtps/src/reliable_writer.rs::tests::a_participant_set_to_go_without_it_gets_no_group_coherent_set_pid, crates/rtps/src/reliable_writer.rs::tests::a_participant_set_to_coherent_sets_only_gets_no_group_information

Status: done

§8.7.6 ECS Data submessage from all writers

Spec: §8.7.6, p. 146 — “A group’s coherent set is marked as being finished by sending an End Coherent Set (ECS) Data submessage from all Writers within the Publisher.” Properties: no serializedPayload, group sequence number of the last sample + 1, not filtered, does not count towards resource limits, inline QoS PID_GROUP_SEQ_NUM, PID_GROUP_COHERENT_SET, PID_WRITER_GROUP_INFO.

Repo: —

Tests: crates/rtps/src/reliable_writer.rs::tests::a_group_coherent_set_carries_the_parameters_of_table_9_23, crates/dcps/src/group_order.rs::tests::a_set_waits_for_the_end_of_every_counted_writer

Status: done

§8.7.6 No writers added or removed during a coherent set

Spec: §8.7.6, p. 146 — “Note that Writers are not allowed to be added or removed from a Publisher from the time that a coherent set begins until after it ends.”

Repo: —

Tests: crates/dcps/tests/group_access_e2e.rs::a_writer_is_not_created_or_deleted_while_a_group_coherent_set_is_open

Status: done

§8.7.6 DataReader: commit a group coherent set

Spec: §8.7.6, p. 147 — “The group coherent set becomes ready to be committed to the DDS DataReader once an ECS sample is committed to the Subscriber and the ECS sample meets the criteria for being committed to the DDS DataReader. Once the group coherent set becomes ready to be committed the Subscriber shall determine if the subscriber-relevant coherent set is complete and if so, make it available to the application.”

Repo: —

Tests: crates/dcps/src/group_order.rs::tests::the_group_coherent_set_of_table_9_23_goes_out_whole_after_its_end, crates/dcps/src/group_order.rs::tests::a_set_is_complete_per_reader_of_each_writer, crates/dcps/tests/group_access_e2e.rs::a_dispose_in_a_group_coherent_set_waits_for_its_end_over_udp

Status: done

§8.7.6 Inline QoS of a coherent-set member on the first DataFrag

Spec: §8.7.6, p. 146 — “The remainder of the discussion only refers to Data Submessages, but the same approach is followed for DataFrag Submessages.”

Repo: —

Tests: crates/rtps/src/reliable_writer.rs::tests::an_oversized_coherent_set_member_goes_out_as_marked_fragments, crates/rtps/src/fragment_assembler.rs::tests::the_first_fragments_inline_qos_reaches_the_completed_sample

Status: done

§8.7.7 Directed write: PID_DIRECTED_WRITE

Spec: §8.7.7, p. 147 — “RTPS supports directed writes by using the in-line QoS parameter extension mechanism. The serialized information denotes the GUIDs of the targeted reader(s).”

Repo: crates/rtps/src/inline_qos.rs (directed_write_param, find_directed_write, directed_write_accepts); crates/rtps/src/parameter_list.rs (pid::DIRECTED_WRITE); crates/rtps/src/reliable_reader.rs (addressed_elsewhere)

Tests: crates/rtps/src/inline_qos.rs::tests::directed_write_param_carries_target_guid, crates/rtps/src/inline_qos.rs::tests::find_directed_write_returns_target_when_present, crates/rtps/src/reliable_reader.rs::tests::a_directed_sample_is_absorbed_by_a_reader_it_does_not_name

Status: done — encoding and reading of the parameter; the receive path reads every PID_DIRECTED_WRITE of a DATA, not only the first. No ZeroDDS writer sends a directed write; the spec offers it to the writer and does not require it.

§8.7.7 Directed write: only the addressed reader takes it

Spec: §8.7.7, p. 147 — “When a writer sends a directed sample, only recipients with a matching GUID accept the sample; all other recipients acknowledge but absorb the sample, as if it were a GAP message.”

Repo: crates/rtps/src/reliable_reader.rs (addressed_elsewhere, irrelevant_change_set); crates/rtps/src/inline_qos.rs (directed_write_accepts)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_directed_sample_is_absorbed_by_a_reader_it_does_not_name, crates/rtps/src/inline_qos.rs::tests::directed_write_matches_reader_returns_false_for_other_target

Status: done — a reader that no PID_DIRECTED_WRITE of the DATA names acknowledges the sample and absorbs it as after a GAP; a named reader takes it. Measured: green on the Linux test host.

§8.7.8 Property lists

Spec: §8.7.8, p. 147 — “The RTPS protocol supports Property Lists as in-line parameters. Properties can then be propagated during Discovery or as in-line QoS.”

Repo: crates/rtps/src/property_list.rs (WirePropertyList); crates/rtps/src/participant_data.rs (properties, PID_PROPERTY_LIST)

Tests: crates/rtps/src/property_list.rs::tests::multi_property_roundtrip_be, crates/rtps/src/participant_data.rs::tests::participant_data_properties_roundtrip

Status: done — ZeroDDS carries property lists in SPDP; not in SEDP and not as inline QoS.

§8.7.9 Original writer info: mark the forwarding

Spec: §8.7.9, p. 147 — “This service that forwards messages needs to indicate that the forwarded message belongs to the message-stream of another writer, such that if the reader receives the same messages from another source … it can treat them as duplicates.”

Repo: crates/dcps/src/runtime.rs (write_user_sample_on_behalf, write_user_lifecycle_on_behalf, write_user_sample_relayed); crates/durability-service/src/lib.rs (write_replay_sample); crates/routing-service/src/forwarding.rs (relay mode)

Tests: crates/dcps/src/runtime.rs::tests::a_sample_written_on_behalf_of_another_writer_is_that_writers, crates/dcps/src/runtime.rs::tests::a_dispose_written_on_behalf_of_another_writer_is_that_writers, crates/durability-service/src/lib.rs::tests::a_replayed_sample_goes_out_on_behalf_of_its_writer, crates/routing-service/tests/relay_route.rs::a_relay_route_forwards_on_behalf_of_the_writer, crates/rtps/src/reliable_writer.rs::tests::a_lifecycle_marker_keeps_its_own_inline_qos_on_every_send

Status: done — a writer sends a sample, a dispose or an unregister on behalf of another with PID_ORIGINAL_WRITER_INFO, on the first send and on every repair. The durability service sends its stored samples so, the routing service in relay mode (Route::relay) every sample and every lifecycle marker. Measured: green on the Linux test host.

§8.7.9 Original writer info: hand-over to the reader of the original

Spec: §8.7.9, p. 147 — “When a RTPS Reader receives this information, it will treat it as a normal CacheChange, but once the CacheChange is ready to be committed to the DDS DataReader, it will not commit it. Instead, it will hand if off to the HistoryCache of the RTPS Reader that is communicating with the RTPS Writer indicated in the ORIGINAL_WRITER_INFO in-line QoS”.

Repo: crates/rtps/src/reliable_reader.rs (original_writer_of, commit_released, commit_forwarded, set_forwarder_trusted)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_forwarded_change_is_the_originals_and_its_direct_copy_a_duplicate, crates/rtps/src/reliable_reader.rs::tests::a_change_from_the_original_is_not_handed_out_again_when_forwarded, crates/rtps/src/reliable_reader.rs::tests::a_forwarded_change_waiting_in_the_originals_cache_is_a_duplicate, crates/rtps/src/reliable_reader.rs::tests::a_forwarded_change_the_original_gapped_is_handed_out, crates/rtps/src/reliable_reader.rs::tests::changes_forwarded_before_the_original_matched_are_not_delivered_again, crates/rtps/src/reliable_reader.rs::tests::an_untrusted_forwarder_delivers_as_itself, crates/rtps/src/reliable_reader.rs::tests::a_writer_that_comes_back_starts_a_new_stream

Status: done — a change with PID_ORIGINAL_WRITER_INFO goes out as the original writer’s, with its sequence number, also where the reader has no proxy of the original; one the reader has from the original or another forwarder already is a duplicate. A writer the reader does not trust as forwarder delivers as itself (under DDS-Security only with <relay> in the grant, dds-security-1.2 §7.1.1.4). Measured: green on the Linux test host.

§8.7.9 Table 8.89 originalWriterGUID

Spec: §8.7.9, p. 147, Table 8.89 — “originalWriterGUID: GUID_t — The GUID of the RTPS Writer that first generated the message.”

Repo: crates/rtps/src/inline_qos.rs (original_writer_info_param)

Tests: crates/rtps/src/inline_qos.rs::tests::original_writer_info_param_24_byte_layout_le, crates/rtps/src/inline_qos.rs::tests::original_writer_info_roundtrip_be

Status: done — encoded, sent and evaluated on receipt (items under §8.7.9).

§8.7.9 Table 8.89 originalWriterSN

Spec: §8.7.9, p. 147, Table 8.89 — “originalWriterSN: SequenceNumber_t — The Sequence Number of the CacheChange as sent from the original writer.”

Repo: crates/rtps/src/inline_qos.rs (original_writer_info_param)

Tests: crates/rtps/src/inline_qos.rs::tests::original_writer_info_roundtrip_le

Status: done — encoded, sent and evaluated on receipt (items under §8.7.9).

§8.7.10 Compute the KeyHash from the data

Spec: §8.7.10, p. 148 — “When the key hash is not received by a DataReader, it should be computed from the data itself. If there is no data in the submessage, then a default zero-valued key hash should be used by the DataReader.”

Repo: crates/dcps/src/runtime.rs (reader_key_hash_context); crates/dcps/src/key_hash.rs

Tests: crates/dcps/src/runtime.rs::tests::alive_sample_without_key_hash_gets_the_types_computed_hash, crates/dcps/src/runtime.rs::tests::lifecycle_marker_without_key_hash_gets_the_alive_instances_hash_and_holder

Status: done

§8.7.10 Compute the KeyHash by §9.6.4.8

Spec: §8.7.10, p. 148 — “A Key Hash, if present, shall be computed as described in 9.6.4.3.”

Repo: crates/dcps/src/key_hash.rs

Tests: crates/dcps/src/key_hash.rs::tests::a_holder_over_sixteen_is_hashed, crates/dcps/src/key_hash.rs::tests::a_u32_goes_out_big_endian

Status: done — the reference to §9.6.4.3 is wrong in the spec; the computation is in §9.6.4.8.

§9 Platform Specific Model (PSM): UDP/IP

§9.1 PSM UDP/IP: introduction

Spec: §9.1, p. 149 — “This clause defines the Platform Specific Model (PSM) that maps the Protocol PIM to UDP/IP.”

Repo: —

Tests: —

Status: n/a (informative) — rationale for the choice of UDP/IP, no requirement.

§9.2.1 Name space

Spec: §9.2.1, p. 149 — “All the definitions in this document are part of the “RTPS” name-space.”

Repo: —

Tests: —

Status: n/a (informative) — convention of the document.

§9.2.2 IDL representation and CDR wire form

Spec: §9.2.2, p. 149 — “These definitions use the OMG IDL … When these structures are sent on the wire, they are encoded using the corresponding CDR representation.”

Repo: —

Tests: —

Status: n/a (informative) — convention; the individual mappings are listed under §9.3 and §9.4.

§9.2.3 Representation of bits and bytes

Spec: §9.2.3, pp. 149–150 — “the leftmost bit (bit 7) is the most significant bit”; bytes in rows of four.

Repo: —

Tests: —

Status: n/a (informative) — notation of the document.

§9.3.1 GUID from GuidPrefix and EntityId

Spec: §9.3.1, p. 150 — “The PIM defines the GUID as composed of a GuidPrefix_t prefix capable of holding 12 bytes, and an EntityId_t entityId capable of holding 4 bytes.”

Repo: crates/rtps/src/wire_types.rs (Guid, Guid::to_bytes)

Tests: crates/rtps/src/wire_types.rs::tests::guid_layout_is_prefix_then_entity_id, crates/rtps/src/wire_types.rs::tests::guid_roundtrip

Status: done

§9.3.1.1 GuidPrefix_t

Spec: §9.3.1.1, p. 150 — “typedef octet GuidPrefix_t[12];”

Repo: crates/rtps/src/wire_types.rs (GuidPrefix)

Tests: crates/rtps/src/wire_types.rs::tests::guid_prefix_roundtrip

Status: done

§9.3.1.1 GUIDPREFIX_UNKNOWN

Spec: §9.3.1.1, p. 150 — “#define GUIDPREFIX_UNKNOWN {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}”.

Repo: crates/rtps/src/wire_types.rs (GuidPrefix::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::guid_prefix_unknown_is_zero

Status: done

§9.3.1.2 EntityId_t

Spec: §9.3.1.2, p. 150 — “struct EntityId_t { OctetArray3 entityKey; octet entityKind; };”

Repo: crates/rtps/src/wire_types.rs (EntityId)

Tests: crates/rtps/src/wire_types.rs::tests::entity_id_roundtrip, crates/rtps/src/wire_types.rs::tests::entity_id_user_writer_with_key_layout

Status: done

§9.3.1.2 ENTITYID_UNKNOWN

Spec: §9.3.1.2, p. 150 — “#define ENTITYID_UNKNOWN {{0x00, 0x00, 0x00}, 0x00}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::entity_id_unknown_is_four_zero_octets

Status: done

§9.3.1.2 entityKey unique within the participant

Spec: §9.3.1.2, p. 150 — “When not pre-defined (see below), the entityKey field within the EntityId_t can be chosen arbitrarily by the middleware implementation as long as the resulting EntityId_t is unique within the Participant.”

Repo: crates/dcps/src/runtime.rs (DcpsRuntime::next_entity_key, entity_key_in_use, pinned_entity_keys, new_group_entity_id, reserve_user_writer_id, reserve_user_reader_id)

Tests: crates/dcps/src/runtime.rs::tests::entity_keys_are_unique_across_groups_reserved_and_registered_endpoints, crates/dcps/src/runtime.rs::tests::a_wrapped_entity_key_counter_skips_the_key_of_a_live_writer

Status: done — the counter (24 bit) hands out every key once; after the wrap it skips the keys of registered writers, readers and announced topics and those of Publishers, Subscribers and of reserved, not yet registered endpoints. The key of a deleted endpoint is handed out again; a reserved key that is never registered stays taken.

§9.3.1.2 entityKind: kind of entity in the two upper bits

Spec: §9.3.1.2, p. 150 — “The information on whether the object is a built-in entity, a vendor-specific entity, or a user-defined entity is encoded in the two most-significant bits of the entityKind.” “a vendor-specific Entity … can therefore be ignored by another vendor’s implementation”.

Repo: crates/rtps/src/wire_types.rs (EntityKind::from_byte, EntityKind::Other)

Tests: crates/rtps/src/wire_types.rs::tests::entity_kind_octet_round_trips, crates/rtps/src/wire_types.rs::tests::entity_id_unnamed_kind_byte_is_kept

Status: done

§9.3.1.2 Table 9.1 unknown

Spec: §9.3.1.2, p. 151, Table 9.1 — “unknown — 0x00 — 0xc0”.

Repo: crates/rtps/src/wire_types.rs (EntityKind::Unknown, EntityKind::Other(0xC0))

Tests: crates/rtps/src/wire_types.rs::tests::topic_kind_follows_entity_kind_octet_of_table_9_1, crates/rtps/src/wire_types.rs::tests::entity_kind_octet_round_trips

Status: done

§9.3.1.2 Table 9.1 Participant

Spec: §9.3.1.2, p. 151, Table 9.1 — “Participant — N/A — 0xc1”.

Repo: crates/rtps/src/wire_types.rs (EntityKind::Participant)

Tests: crates/rtps/src/wire_types.rs::tests::entity_id_participant_constant

Status: done

§9.3.1.2 Table 9.1 Writer (with Key)

Spec: §9.3.1.2, p. 151, Table 9.1 — “Writer (with Key) — 0x02 — 0xc2”.

Repo: crates/rtps/src/wire_types.rs (UserWriterWithKey, BuiltinWriterWithKey)

Tests: crates/rtps/src/wire_types.rs::tests::topic_kind_follows_entity_kind_octet_of_table_9_1

Status: done

§9.3.1.2 Table 9.1 Writer (no Key)

Spec: §9.3.1.2, p. 151, Table 9.1 — “Writer (no Key) — 0x03 — 0xc3”.

Repo: crates/rtps/src/wire_types.rs (UserWriterNoKey, BuiltinWriterNoKey)

Tests: crates/rtps/src/wire_types.rs::tests::topic_kind_follows_entity_kind_octet_of_table_9_1

Status: done

§9.3.1.2 Table 9.1 Reader (no Key)

Spec: §9.3.1.2, p. 151, Table 9.1 — “Reader (no Key) — 0x04 — 0xc4”.

Repo: crates/rtps/src/wire_types.rs (UserReaderNoKey, BuiltinReaderNoKey)

Tests: crates/rtps/src/wire_types.rs::tests::topic_kind_follows_entity_kind_octet_of_table_9_1

Status: done

§9.3.1.2 Table 9.1 Reader (with Key)

Spec: §9.3.1.2, p. 151, Table 9.1 — “Reader (with Key) — 0x07 — 0xc7”.

Repo: crates/rtps/src/wire_types.rs (UserReaderWithKey, BuiltinReaderWithKey)

Tests: crates/rtps/src/wire_types.rs::tests::topic_kind_follows_entity_kind_octet_of_table_9_1

Status: done

§9.3.1.2 Table 9.1 Writer Group

Spec: §9.3.1.2, p. 151, Table 9.1 — “Writer Group — 0x08 — 0xc8”.

Repo: crates/rtps/src/wire_types.rs (EntityKind::Other, octet kept unchanged)

Tests: crates/rtps/src/wire_types.rs::tests::topic_kind_follows_entity_kind_octet_of_table_9_1, crates/rtps/src/wire_types.rs::tests::entity_kind_octet_round_trips

Status: done

§9.3.1.2 Table 9.1 Reader Group

Spec: §9.3.1.2, p. 151, Table 9.1 — “Reader Group — 0x09 — 0xc9”.

Repo: crates/rtps/src/wire_types.rs (EntityKind::Other, octet kept unchanged)

Tests: crates/rtps/src/wire_types.rs::tests::topic_kind_follows_entity_kind_octet_of_table_9_1, crates/rtps/src/wire_types.rs::tests::entity_kind_octet_round_trips

Status: done

§9.3.1.3 Meaning of the predefined EntityIds

Spec: §9.3.1.3, p. 151 — “The meaning of these Entity IDs cannot change in this major version (2) of the protocol, but future minor versions may add additional reserved Entity IDs.”

Repo: —

Tests: —

Status: n/a (informative) — a requirement on future editions of the specification.

§9.3.1.3 Table 9.2 ENTITYID_PARTICIPANT

Spec: §9.3.1.3, p. 151, Table 9.2 — “ENTITYID_PARTICIPANT = {{00,00,01},c1}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::PARTICIPANT)

Tests: crates/rtps/src/wire_types.rs::tests::entity_id_participant_constant

Status: done

§9.3.1.3 Table 9.2 ENTITYID_SEDP_BUILTIN_TOPICS_ANNOUNCER

Spec: §9.3.1.3, p. 151, Table 9.2 — “ENTITYID_SEDP_BUILTIN_TOPICS_ANNOUNCER = {{00,00,02},c2}”.

Repo: EntityId::SEDP_BUILTIN_TOPICS_WRITER (crates/rtps/src/wire_types.rs)

Tests: crates/rtps/src/wire_types.rs::tests::the_entity_ids_of_table_9_2_are_those_of_the_table

Status: done — the constant carries {{00,00,02},c2}; the test checks all values of Table 9.2.

§9.3.1.3 Table 9.2 ENTITYID_SEDP_BUILTIN_TOPICS_DETECTOR

Spec: §9.3.1.3, p. 151, Table 9.2 — “ENTITYID_SEDP_BUILTIN_TOPICS_DETECTOR = {{00,00,02},c7}”.

Repo: EntityId::SEDP_BUILTIN_TOPICS_READER (crates/rtps/src/wire_types.rs)

Tests: crates/rtps/src/wire_types.rs::tests::the_entity_ids_of_table_9_2_are_those_of_the_table

Status: done — the constant carries {{00,00,02},c7}; the test checks all values of Table 9.2.

§9.3.1.3 Table 9.2 ENTITYID_SEDP_BUILTIN_PUBLICATIONS_ANNOUNCER

Spec: §9.3.1.3, p. 151, Table 9.2 — “ENTITYID_SEDP_BUILTIN_PUBLICATIONS_ANNOUNCER = {{00,00,03},c2}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::SEDP_BUILTIN_PUBLICATIONS_WRITER)

Tests: crates/rtps/src/wire_types.rs::tests::sedp_publications_writer_layout

Status: done

§9.3.1.3 Table 9.2 ENTITYID_SEDP_BUILTIN_PUBLICATIONS_DETECTOR

Spec: §9.3.1.3, p. 151, Table 9.2 — “ENTITYID_SEDP_BUILTIN_PUBLICATIONS_DETECTOR = {{00,00,03},c7}”.

Repo: EntityId::SEDP_BUILTIN_PUBLICATIONS_READER (crates/rtps/src/wire_types.rs)

Tests: crates/rtps/src/wire_types.rs::tests::the_entity_ids_of_table_9_2_are_those_of_the_table

Status: done — the constant carries {{00,00,03},c7}; the test checks all values of Table 9.2.

§9.3.1.3 Table 9.2 ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_ANNOUNCER

Spec: §9.3.1.3, p. 151, Table 9.2 — “ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_ANNOUNCER = {{00,00,04},c2}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::SEDP_BUILTIN_SUBSCRIPTIONS_WRITER)

Tests: crates/discovery/tests/vendor_discovery_frames.rs::fastdds_announcements_read_and_write_back

Status: done — the test sorts captured announcements by this EntityId.

§9.3.1.3 Table 9.2 ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_DETECTOR

Spec: §9.3.1.3, p. 151, Table 9.2 — “ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_DETECTOR = {{00,00,04},c7}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::SEDP_BUILTIN_SUBSCRIPTIONS_READER)

Tests: crates/rtps/src/wire_types.rs::tests::sedp_subscriptions_reader_layout

Status: done

§9.3.1.3 Table 9.2 ENTITYID_SPDP_BUILTIN_PARTICIPANT_ANNOUNCER

Spec: §9.3.1.3, p. 151, Table 9.2 — “ENTITYID_SPDP_BUILTIN_PARTICIPANT_ANNOUNCER = {{00,01,00},c2}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::SPDP_BUILTIN_PARTICIPANT_WRITER)

Tests: crates/rtps/src/wire_types.rs::tests::spdp_builtin_participant_writer_layout

Status: done

§9.3.1.3 Table 9.2 ENTITYID_SPDP_BUILTIN_PARTICIPANT_DETECTOR

Spec: §9.3.1.3, p. 151, Table 9.2 — “ENTITYID_SPDP_BUILTIN_PARTICIPANT_DETECTOR = {{00,01,00},c7}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::SPDP_BUILTIN_PARTICIPANT_READER)

Tests: crates/rtps/src/wire_types.rs::tests::spdp_builtin_participant_reader_layout

Status: done

§9.3.1.3 Table 9.2 ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER

Spec: §9.3.1.3, p. 151, Table 9.2 — “ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER = {{00,02,00},c2}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::BUILTIN_PARTICIPANT_MESSAGE_WRITER)

Tests: crates/dcps/tests/cyclone_live_wlp.rs::cyclone_live_wlp_handshake

Status: done — the test runs only with --ignored and a Cyclone ddsperf.

§9.3.1.3 Table 9.2 ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER

Spec: §9.3.1.3, p. 151, Table 9.2 — “ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER = {{00,02,00},c7}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::BUILTIN_PARTICIPANT_MESSAGE_READER)

Tests: crates/dcps/tests/cyclone_live_wlp.rs::cyclone_live_wlp_handshake

Status: done — the test runs only with --ignored and a Cyclone ddsperf.

§9.3.1.3 Table 9.3 DDS-Security: range {ff,00,00}–{ff,ff,ff}

Spec: §9.3.1.3, p. 152, Table 9.3 — “EntityIds that have both an entityKey in the range {ff, 00, 00} – {ff, ff, ff} and an entityKind in the range 0xc0-0xff (inclusive).”

Repo: crates/rtps/src/wire_types.rs (EntityId::SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER and the other secure built-in EntityIds)

Tests: crates/rtps/src/wire_types.rs::tests::all_12_secure_entityids_roundtrip, crates/rtps/src/wire_types.rs::tests::secure_publications_writer_layout

Status: done

§9.3.1.3 Table 9.3 DDS-Security: {{00,02,01},c3} and {{00,02,01},c4}

Spec: §9.3.1.3, p. 152, Table 9.3 — “DDS-Security 1.1 — {{00, 02, 01}, c3} and {{00, 02, 01}, c4}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER, EntityId::BUILTIN_PARTICIPANT_STATELESS_MESSAGE_READER)

Tests: crates/discovery/src/security/stateless.rs::tests::writer_has_expected_entity_id, crates/discovery/src/security/stateless.rs::tests::reader_has_expected_entity_id

Status: done

§9.3.1.3 Table 9.3 DDS-XTypes: TypeLookup EntityIds

Spec: §9.3.1.3, p. 152, Table 9.3 — “DDS-XTypes 1.2 — {{00, 03, 00}, c3}, {{00, 03, 00}, c4}, {{00, 03, 01}, c3}, {{00, 03, 01}, c4}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::TL_SVC_REQ_WRITER, TL_SVC_REQ_READER, TL_SVC_REPLY_WRITER, TL_SVC_REPLY_READER)

Tests: crates/discovery/src/type_lookup/endpoints.rs::tests::entity_ids_match_spec_constants

Status: done

§9.3.1.4 Table 9.4 Client (0x05)

Spec: §9.3.1.4, p. 152, Table 9.4 — “Client — 0x05”; “These EntityIds should not be used by future versions of the protocol unless they are used with the same meaning as in versions prior to 2.2.”

Repo: —

Tests: —

Status: n/a (informative) — deprecated id; ZeroDDS does not use it.

§9.3.1.4 Table 9.4 Server (0x06)

Spec: §9.3.1.4, p. 152, Table 9.4 — “Server — 0x06”.

Repo: —

Tests: —

Status: n/a (informative) — deprecated id; ZeroDDS does not use it.

§9.3.1.4 Table 9.4 writerApplications

Spec: §9.3.1.4, p. 152, Table 9.4 — “writerApplications — {{00,00,01},c2}”.

Repo: —

Tests: —

Status: n/a (informative) — deprecated id; ZeroDDS does not use it.

§9.3.1.4 Table 9.4 readerApplications

Spec: §9.3.1.4, p. 152, Table 9.4 — “readerApplications — {{00,00,01},c7}”.

Repo: —

Tests: —

Status: n/a (informative) — deprecated id; ZeroDDS does not use it.

§9.3.1.4 Table 9.4 writerClients

Spec: §9.3.1.4, p. 152, Table 9.4 — “writerClients — {{00,00,05},c2}”.

Repo: —

Tests: —

Status: n/a (informative) — deprecated id; ZeroDDS does not use it.

§9.3.1.4 Table 9.4 readerClients

Spec: §9.3.1.4, p. 152, Table 9.4 — “readerClients — {{00,00,05},c7}”.

Repo: —

Tests: —

Status: n/a (informative) — deprecated id; ZeroDDS does not use it.

§9.3.1.4 Table 9.4 writerServices

Spec: §9.3.1.4, p. 152, Table 9.4 — “writerServices — {{00,00,06},c2}”.

Repo: —

Tests: —

Status: n/a (informative) — deprecated id; ZeroDDS does not use it.

§9.3.1.4 Table 9.4 readerServices

Spec: §9.3.1.4, p. 152, Table 9.4 — “readerServices — {{00,00,06},c7}”.

Repo: —

Tests: —

Status: n/a (informative) — deprecated id; ZeroDDS does not use it.

§9.3.1.4 Table 9.4 writerManagers

Spec: §9.3.1.4, p. 152, Table 9.4 — “writerManagers — {{00,00,07},c2}”.

Repo: —

Tests: —

Status: n/a (informative) — deprecated id; ZeroDDS does not use it.

§9.3.1.4 Table 9.4 readerManagers

Spec: §9.3.1.4, p. 152, Table 9.4 — “readerManagers — {{00,00,07},c7}”.

Repo: —

Tests: —

Status: n/a (informative) — deprecated id; ZeroDDS does not use it.

§9.3.1.4 Table 9.4 writerApplicationsSelf

Spec: §9.3.1.4, p. 152, Table 9.4 — “writerApplicationsSelf — {{00,00,08},c2}”.

Repo: —

Tests: —

Status: n/a (informative) — deprecated id; ZeroDDS does not use it.

§9.3.1.5 GUID_t

Spec: §9.3.1.5, p. 152 — “struct GUID_t { GuidPrefix_t guidPrefix; EntityId_t entityId; } ;”

Repo: crates/rtps/src/wire_types.rs (Guid)

Tests: crates/rtps/src/wire_types.rs::tests::guid_layout_is_prefix_then_entity_id

Status: done

§9.3.1.5 First two octets of the guidPrefix = vendorId

Spec: §9.3.1.5, pp. 152–153 — “implementations of the RTPS protocol shall set the first two bytes of the guidPrefix to match their assigned vendorId … guidPrefix[0] = vendorId[0] guidPrefix[1] = vendorId[1]”.

Repo: crates/rtps/src/wire_types.rs (GuidPrefix::zerodds); crates/dcps/src/participant.rs (random_guid_prefix)

Tests: crates/rtps/src/wire_types.rs::tests::guid_prefix_host_id_follows_the_vendor_id

Status: partial — the first two octets are 01 F0, not a value assigned by the OMG (blocked item under §8.3.5.2). DcpsRuntime::start also accepts a freely chosen prefix; under DDS-Security the prefix derived from the identity replaces the one built. DDS-Security 1.2 §10.3.3 Table 59 (validate_local_identity) sets its first 48 bits: the first bit 1, then 47 bits of the SHA-256 of the SubjectName; by the more specific spec the vendorId is not in them (crates/security-pki/src/guid_adjust.rs, test adjusted_prefix_sets_high_bit_and_is_deterministic_per_identity).

§9.3.1.5 GUID_UNKNOWN

Spec: §9.3.1.5, p. 153 — “#define GUID_UNKNOWN{ GUIDPREFIX_UNKNOWN, ENTITYID_UNKNOWN }”.

Repo: crates/rtps/src/wire_types.rs (Guid::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::guid_prefix_unknown_is_zero, crates/rtps/src/wire_types.rs::tests::entity_id_unknown_is_four_zero_octets

Status: done

§9.3.2.1 DomainId_t

Spec: §9.3.2.1, p. 153 — “typedef unsigned long DomainId_t;”

Repo: crates/rtps/src/participant_data.rs (domain_id: Option<u32>, PID_DOMAIN_ID with 4 octets)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§9.3.2.1 Time_t structure

Spec: §9.3.2.1, p. 153 — “struct Time_t { unsigned long seconds; // time in seconds unsigned long fraction; // time in sec/2^32 };”

Repo: crates/rtps/src/header_extension.rs (HeTimestamp); crates/rtps/src/submessages.rs (InfoTimestampSubmessage)

Tests: crates/rtps/src/submessages.rs::tests::info_timestamp_roundtrip_le, crates/rtps/src/submessages.rs::tests::info_timestamp_roundtrip_be, crates/rtps/src/header_extension.rs::tests::roundtrip_all_fields_set_be

Status: done — seconds and fraction are each an unsigned long (HeTimestamp::seconds: u32), 4 + 4 octets in the byte order of the submessage; second values from 2^31 on stay positive (the test roundtrip_all_fields_set_be uses 0xFFFF_FFFD). §9.4.2.9 shows long seconds; the structure of §9.3.2.1 applies.

§9.3.2.1 Time_t: reserved values and unsigned seconds

Spec: §9.3.2.1, p. 153 — “TIME_ZERO: seconds = 0, fraction = 0; TIME_INVALID: seconds = 0xffffffff, fraction = 0xffffffff; TIME_INFINITE: seconds = 0xffffffff, fraction = 0xfffffffe”.

Repo: crates/dcps/src/time.rs (time_to_he_timestamp, he_timestamp_to_time); crates/rtps/src/header_extension.rs (HeTimestamp, TIME_INVALID)

Tests: crates/dcps/src/time.rs::tests::the_reserved_time_t_values_cross_the_wire_as_the_spec_gives_them, crates/rtps/src/receiver_state.rs::tests::the_initial_state_is_the_one_of_table_8_17, crates/rtps/src/header_extension.rs::tests::roundtrip_all_fields_set_be

Status: done — Time::INVALID goes on the wire as {0xffffffff, 0xffffffff} and Time::INFINITE as {0xffffffff, 0xfffffffe} and is read back so; HeTimestamp::seconds is u32, TIME_INVALID has seconds 0xFFFFFFFF. The callers in dcps, xrce-agent and opcua-bridge are adapted (cargo check --tests and clippy green). Whether another vendor sends the special values as a source timestamp is not checked.

§9.3.2.1 Duration_t, DURATION_ZERO, DURATION_INFINITE

Spec: §9.3.2.1, p. 153 — “DURATION_ZERO: seconds = 0, fraction = 0; DURATION_INFINITE: seconds = 0x7fffffff, fraction = 0xffffffff; struct Duration_t { long seconds; unsigned long fraction; };”

Repo: crates/qos/src/duration.rs (Duration::INFINITE, Duration::ZERO)

Tests: crates/qos/src/duration.rs::tests::infinite_constant_matches_spec, crates/qos/src/duration.rs::tests::zero_is_default_and_zero

Status: done

§9.3.2.1 VendorId_t and VENDORID_UNKNOWN

Spec: §9.3.2.1, p. 153 — “VENDORID_UNKNOWN: VendorId_t[0] = 0, VendorId_t[1] = 0; typedef octet VendorId_t[2];”

Repo: crates/rtps/src/wire_types.rs (VendorId, VendorId::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::vendor_id_unknown_is_two_zero_octets, crates/rtps/src/wire_types.rs::tests::vendor_id_roundtrip

Status: done

§9.3.2.1 SEQUENCENUMBER_UNKNOWN

Spec: §9.3.2.1, p. 153 — “SEQUENCENUMBER_UNKNOWN: high = -1, low = 0”.

Repo: crates/rtps/src/wire_types.rs (SequenceNumber::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::sequence_number_unknown_high_minus_one_low_zero

Status: done

§9.3.2.1 FragmentNumber_t

Spec: §9.3.2.1, p. 153 — “typedef unsigned long FragmentNumber_t;”

Repo: crates/rtps/src/wire_types.rs (FragmentNumber(u32))

Tests: crates/rtps/src/wire_types.rs::tests::fragment_number_roundtrip_le_be, crates/rtps/src/wire_types.rs::tests::fragment_number_wire_size_is_four

Status: done

§9.3.2.1 LOCATOR_KIND_INVALID, _RESERVED, _UDPv4, _UDPv6

Spec: §9.3.2.1, pp. 153–154 — “const long LOCATOR_KIND_INVALID = -1; const long LOCATOR_KIND_RESERVED = 0; const long LOCATOR_KIND_UDPv4 = 1; const long LOCATOR_KIND_UDPv6 = 2;”

Repo: crates/rtps/src/wire_types.rs (LocatorKind::Invalid, Reserved, UdpV4, UdpV6)

Tests: crates/rtps/src/wire_types.rs::tests::locator_reserved_constant_kind_is_zero, crates/rtps/src/wire_types.rs::tests::locator_udp_v4_any_kind_is_one, crates/rtps/src/wire_types.rs::tests::locator_udp_v6_any_kind_is_two

Status: done

§9.3.2.1 LOCATOR_PORT_INVALID, LOCATOR_ADDRESS_INVALID, LOCATOR_INVALID

Spec: §9.3.2.1, p. 154 — “const unsigned long LOCATOR_PORT_INVALID = 0; LOCATOR_ADDRESS_INVALID: {0,…,0}; LOCATOR_INVALID: kind = LOCATOR_KIND_INVALID, port = LOCATOR_PORT_INVALID, address = LOCATOR_ADDRESS_INVALID”.

Repo: crates/rtps/src/wire_types.rs (Locator::INVALID)

Tests: crates/rtps/src/wire_types.rs::tests::locator_invalid_constant_matches_spec, crates/rtps/src/wire_types.rs::tests::locator_invalid_kind_decoded

Status: done

§9.3.2.1 Locator_t

Spec: §9.3.2.1, p. 154 — “struct Locator_t { long kind; unsigned long port; octet address[16]; };”

Repo: crates/rtps/src/wire_types.rs (Locator, Locator::to_bytes_le)

Tests: crates/rtps/src/wire_types.rs::tests::locator_udp_v4_layout, crates/rtps/src/wire_types.rs::tests::locator_roundtrip_le

Status: done

§9.3.2.1 BEST_EFFORT = 1, RELIABLE = 2

Spec: §9.3.2.1, p. 154 — “The values of the following constants as defined in the DDS Specification should be mapped to the below values before being sent on the wire. const long BEST_EFFORT = 1; const long RELIABLE = 2;”

Repo: crates/qos/src/policies/reliability.rs (ReliabilityKind::BestEffort = 1, Reliable = 2); crates/rtps/src/publication_data.rs

Tests: crates/rtps/src/publication_data.rs::tests::reliability_try_from_u32_rejects_unknown, crates/qos/src/policies/reliability.rs::tests::best_effort_lt_reliable

Status: done

§9.3.2.1 Count_t

Spec: §9.3.2.1, p. 154 — “typedef long Count_t;”

Repo: crates/rtps/src/submessages.rs (count: i32 in ACKNACK, HEARTBEAT, HEARTBEAT_FRAG, NACK_FRAG)

Tests: crates/rtps/src/submessages.rs::tests::acknack_submessage_roundtrip_le, crates/rtps/src/submessages.rs::tests::heartbeat_submessage_roundtrip_le

Status: done

§9.3.2.1 ProtocolVersion_t

Spec: §9.3.2.1, p. 154 — “struct ProtocolVersion_t { octet major; octet minor; };”

Repo: crates/rtps/src/wire_types.rs (ProtocolVersion)

Tests: crates/rtps/src/wire_types.rs::tests::protocol_version_roundtrip, crates/rtps/src/wire_types.rs::tests::protocol_version_aliases_match_spec

Status: done

§9.3.2.1 KeyHash_t, StatusInfo_t, ParameterId_t

Spec: §9.3.2.1, p. 154 — “typedef octet KeyHash_t[16]; typedef octet StatusInfo_t[4]; typedef short ParameterId_t;”

Repo: crates/rtps/src/inline_qos.rs (PID_KEY_HASH with 16 octets, PID_STATUS_INFO with 4 octets); crates/rtps/src/parameter_list.rs (Parameter::id: u16)

Tests: crates/rtps/src/submessages.rs::tests::data_frag_key_hash_roundtrips_both_byte_orders, crates/dcps/tests/lifecycle_wire_decode.rs::reader_push_lifecycle_disposed_sets_instance_state

Status: done — ParameterId_t is kept as u16; the bits 0x8000 and 0x4000 are evaluated as bit fields (§9.4.2.11.2).

§9.3.2.1 ContentFilterProperty_t

Spec: §9.3.2.1, p. 154 — “struct ContentFilterProperty_t { string<256> contentFilteredTopicName; string<256> relatedTopicName; string<256> filterClassName; string filterExpression; sequence expressionParameters; };”

Repo: crates/rtps/src/subscription_data.rs (ContentFilterProperty)

Tests: crates/rtps/src/subscription_data.rs::tests::content_filter_property_roundtrip_le, crates/rtps/src/subscription_data.rs::tests::content_filter_names_are_bounded_by_string_256

Status: done — order, encoding and the bound of 256 octets for the three names.

§9.3.2.1 ContentFilterProperty_t: string<256>

Spec: §9.3.2.1, p. 154 — “string<256> contentFilteredTopicName; string<256> relatedTopicName; string<256> filterClassName;”

Repo: crates/rtps/src/subscription_data.rs (encode_content_filter_property_le, decode_content_filter_property); crates/dcps/src/participant.rs (create_contentfilteredtopic)

Tests: crates/rtps/src/subscription_data.rs::tests::content_filter_names_are_bounded_by_string_256

Status: done — encoding and decoding bound the three names to 256 octets; create_contentfilteredtopic refuses a longer name. A ContentFilterProperty with a name that is too long or otherwise unreadable counts as absent: the reader is taken without a filter (it filters itself), counted in DcpsRuntime::unreadable_content_filters and logged as sedp.content_filter.unreadable.

§9.3.2.1 ContentFilterInfo_t, FilterResult_t, FilterSignature_t

Spec: §9.3.2.1, p. 154 — “typedef sequence FilterResult_t; typedef long FilterSignature_t[4]; … struct ContentFilterInfo_t { FilterResult_t filterResult; FilterSignatureSequence filterSignatures; };”

Repo: —

Tests: —

Status: open — the types are missing in the code; part of the optional filtering on the writer side (§8.7.3), which ZeroDDS does not perform.

§9.3.2.1 Property_t and EntityName_t

Spec: §9.3.2.1, p. 154 — “struct Property_t { string name; string value; }; typedef string EntityName_t;”

Repo: crates/rtps/src/property_list.rs (WirePropertyList)

Tests: crates/rtps/src/property_list.rs::tests::single_property_roundtrip_le, crates/rtps/src/property_list.rs::tests::multi_property_roundtrip_be

Status: done — EntityName_t (PID_ENTITY_NAME) is listed under §9.6.3.2.

§9.3.2.1 OriginalWriterInfo_t

Spec: §9.3.2.1, p. 154 — “struct OriginalWriterInfo_t { GUID_t originalWriterGUID; SequenceNumber_t originalWriterSN; ParameterList originalWriterQos; };”

Repo: crates/rtps/src/inline_qos.rs (original_writer_info_param, find_original_writer_info)

Tests: crates/rtps/src/inline_qos.rs::tests::original_writer_info_param_24_byte_layout_le, crates/rtps/src/inline_qos.rs::tests::original_writer_info_roundtrip_le, crates/rtps/src/inline_qos.rs::tests::table_9_20_directed_write_original_writer_info_and_secure_group_info

Status: done — the wire form of the parameter is originalWriterGUID and originalWriterSN, 24 octets (§9.6.4.7; Table 8.89 names the same two attributes); originalWriterQos of the IDL structure has no counterpart in the wire form or in Table 8.89. The send and receive paths are done under §8.7.9.

§9.3.2.1 GroupDigest_t

Spec: §9.3.2.1, p. 155 — “typedef octet GroupDigest_t[4];”

Repo: crates/rtps/src/group_digest.rs (GroupDigest, GroupDigest::of_entities)

Tests: crates/rtps/src/group_digest.rs::tests::two_writers_digest_as_section_9_3_2_5_computes_it, crates/rtps/src/group_digest.rs::tests::the_digest_does_not_depend_on_the_order_given, crates/rtps/src/group_digest.rs::tests::the_empty_group_is_zero_and_not_the_hash_of_an_empty_sequence

Status: done

§9.3.2.1 BuiltinEndpointSet_t (IDL)

Spec: §9.3.2.1, p. 155 — “bitmask BuiltinEndpointSet_t { @position(0) DISC_BUILTIN_ENDPOINT_PARTICIPANT_ANNOUNCER, … @position(29) DISC_BUILTIN_ENDPOINT_TOPICS_DETECTOR };”

Repo: crates/rtps/src/participant_data.rs (endpoint_flag)

Tests: crates/rtps/src/participant_data.rs::tests::endpoint_flag_bit_positions_match_spec

Status: done — the positions are listed one by one under §9.3.2.12.

§9.3.2.1 BuiltinEndpointQos_t

Spec: §9.3.2.1, p. 155 — “bitmask BuiltinEndpointQos_t { @position(0) BEST_EFFORT_PARTICIPANT_MESSAGE_DATA_READER };”

Repo: crates/rtps/src/participant_data.rs (builtin_endpoint_qos::BEST_EFFORT_PARTICIPANT_MESSAGE_DATA_READER)

Tests: crates/rtps/src/participant_data.rs::tests::manual_liveliness_count_and_builtin_endpoint_qos_go_out_and_read_back, crates/dcps/src/wlp.rs::tests::the_reader_is_treated_as_builtin_endpoint_qos_says

Status: done — bitmask with @position(0) BEST_EFFORT_PARTICIPANT_MESSAGE_DATA_READER.

§9.3.2.1 ProtocolId_t (PROTOCOL_RTPS)

Spec: §9.3.2.1, p. 155 — “PROTOCOL_RTPS: ProtocolId_t[0] = ‘R’ … ProtocolId_t[3] = ‘S’; typedef octet ProtocolId_t[4];”

Repo: crates/rtps/src/header.rs (RTPS_MAGIC)

Tests: crates/rtps/src/header.rs::tests::header_layout_first_four_bytes_are_rtps_magic

Status: done

§9.3.2.1 MessageLength_t and MESSAGE_LENGTH_INVALID

Spec: §9.3.2.1, p. 155 — “typedef unsigned long MessageLength_t; const MessageLength_t MESSAGE_LENGTH_INVALID = 0;”

Repo: crates/rtps/src/header_extension.rs (message_length: Option<u32>, MESSAGE_LENGTH_INVALID)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_message_length_only_le, crates/rtps/src/datagram.rs::tests::a_header_extension_announcing_message_length_invalid_refuses_the_message

Status: done — u32, 32 bit unsigned; MESSAGE_LENGTH_INVALID is 0 and the initial value of the receiver (None). A HeaderExtension with that value is invalid (messageLength smaller than the RTPS header and the HeaderExtension, §8.3.7.3); the whole message is refused.

§9.3.2.1 UExtension4_t, WExtension8_t, Checksum32_t, Checksum64_t, Checksum128_t

Spec: §9.3.2.1, p. 155 — “typedef octet UExtension4_t[4]; typedef octet WExtension8_t[8]; typedef octet Checksum32_t[4]; typedef octet Checksum64_t[8]; typedef octet Checksum128_t[16];”

Repo: crates/rtps/src/header_extension.rs (uextension4: [u8; 4], wextension8: [u8; 8], ChecksumValue)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_all_fields_set_le, crates/rtps/src/header_extension.rs::tests::checksum_kind_wire_size

Status: done — the byte order of the checksums is listed under §9.4.2.15.

§9.3.2.2 Time_t in NTP format

Spec: §9.3.2.2, p. 156 — “time = seconds + (fraction / 2^(32))”.

Repo: crates/dcps/src/time.rs (time_to_he_timestamp, he_timestamp_to_time); crates/qos/src/duration.rs (fraction_of_nanosec)

Tests: crates/qos/src/duration.rs::tests::a_whole_nanosecond_survives_the_way_there_and_back, crates/rtps/tests/reliable_e2e.rs::e2e_source_timestamp_round_trips

Status: done

§9.3.2.3 Duration_t in NTP format

Spec: §9.3.2.3, p. 156 — “time = seconds + (fraction / 2^(32))”. “Versions of the RTPS specification previous to version 2.4 did not specify the representation of Duration_t, therefore implementations should take into account the vendor and protocol version when interpreting these fields.”

Repo: crates/qos/src/duration.rs (Duration, to_bytes_le, from_bytes_le)

Tests: crates/qos/src/duration.rs::tests::from_millis_splits_correctly, crates/qos/src/duration.rs::tests::to_from_bytes_le_roundtrip

Status: done — there is no distinction by vendor and protocol version before 2.4.

§9.3.2.4 Locator_t: IPv4 address

Spec: §9.3.2.4, p. 156 — “If the Locator_t kind is LOCATOR_KIND_UPDv4, the address contains an IPv4 address. In this case, the leading 12 octets of the address must be zero.”

Repo: crates/rtps/src/wire_types.rs (Locator::udp_v4)

Tests: crates/rtps/src/wire_types.rs::tests::locator_udp_v4_layout

Status: done

§9.3.2.4 Locator_t: IPv6 address

Spec: §9.3.2.4, p. 156 — “If the Locator_t kind is LOCATOR_KIND_UPDv6, the address contains an IPv6 address.”

Repo: crates/rtps/src/wire_types.rs (Locator::udp_v6)

Tests: crates/rtps/src/wire_types.rs::tests::locator_udp_v6_constructor_keeps_full_address, crates/rtps/src/wire_types.rs::tests::locator_udp_v6_roundtrip_le

Status: done

§9.3.2.4 Ranges of the locator kinds

Spec: §9.3.2.4, p. 156 — “0x00000003 - 0x01ffffff (inclusive) are reserved for vendor-specific Locator_t kinds … 0x02000000 - 0x02ffffff (inclusive) are reserved for future use by the RTPS specification … 0x03000000 and greater are reserved for Locator_t kinds that identify a transport developed by a third-party”.

Repo: crates/rtps/src/wire_types.rs (LocatorKind, LocatorKind::from_i32, set_tcp_kinds_fast_dds); crates/dcps/src/runtime.rs (RuntimeConfig::tcp_locator_kinds_fast_dds, key transport.tcp_locator_kinds)

Tests: crates/rtps/src/wire_types.rs::tests::the_zerodds_locator_kinds_are_in_the_vendor_specific_range, crates/rtps/src/wire_types.rs::tests::the_tcp_kinds_are_vendor_range_by_default_and_fast_dds_by_setting, crates/rtps/src/wire_types.rs::tests::locator_kind_rejects_unknown, crates/transport-tcp/src/tcp_transport.rs::tests::locator_kinds_are_zerodds_vendor_range_values, crates/dcps/tests/runtime_config_layering.rs::the_tcp_locator_kinds_are_a_setting, crates/transport-shm/src/posix.rs::tests::locator_kind_is_the_vendor_reserved_shm_value, crates/transport-uds/src/lib.rs::tests::locator_kind_is_the_vendor_reserved_uds_value, crates/rtps/src/submessages.rs::tests::info_reply_leaves_out_a_locator_of_a_kind_it_does_not_know

Status: done — all kinds besides UDPv4 (1) and UDPv6 (2) lie in the vendor range 3 to 0x01ffffff: Shm, Uds, Tsn (0x01F0_0001 to 0x01F0_0003) and now Tcpv4 (0x01F0_0004) and Tcpv6 (0x01F0_0005). ZeroDDS sends the values 4 and 8 of Fast DDS (and of the DDS-TCP-PSM) only with the named setting transport.tcp_locator_kinds: fast-dds (environment ZERODDS_TCP_LOCATOR_KINDS, man page, example configuration); both values are read. A kind the receiver does not know does not invalidate an INFO_REPLY, the locator is left out. Expected Fast DDS behaviour: with fast-dds it recognises the TCP locators of ZeroDDS (kinds 4 and 8); without the setting it ignores kinds in the vendor range and opens no TCP connection to ZeroDDS. Not measured.

§9.3.2.5 GroupDigest_t

Spec: §9.3.2.5, p. 156 — “The GroupDigest_t is computed from an EntityIdSet_t by first computing a 128 bit MD5 Digest (IETF RFC 1321) applied to the CDR Big-Endian serialization of the structure EntityIdSet_t. The GroupDigest_t is the leading 4 octets of the MD5 Digest. The empty group is represented by a zero value of the GroupDigest_t.”

Repo: crates/rtps/src/group_digest.rs (GroupDigest, GroupDigest::of_entities)

Tests: crates/rtps/src/group_digest.rs::tests::two_writers_digest_as_section_9_3_2_5_computes_it, crates/rtps/src/group_digest.rs::tests::the_digest_does_not_depend_on_the_order_given, crates/rtps/src/group_digest.rs::tests::the_empty_group_is_zero_and_not_the_hash_of_an_empty_sequence

Status: done

§9.3.2.6 Checksum32_t, Checksum64_t, Checksum128_t

Spec: §9.3.2.6, p. 157 — “Checksum32_t represents a 32-bit checksum. Checksum64_t, and Checksum128_t represent a 64-bit, and 128-bit checksum, respectively.”

Repo: crates/rtps/src/header_extension.rs (ChecksumValue::Crc32c, Crc64, Md5)

Tests: crates/rtps/src/header_extension.rs::tests::checksum_kind_wire_size, crates/rtps/src/header_extension.rs::tests::checksum_value_kind_matches

Status: done

§9.3.2.7 MessageLength_t

Spec: §9.3.2.7, p. 157 — “This type is used to represent the length of an RTPS message. The representation uses a 32-bit unsigned integer.”

Repo: crates/rtps/src/header_extension.rs (message_length: Option<u32>)

Tests: crates/rtps/src/header_extension.rs::tests::wire_layout_le_message_length_correct, crates/rtps/src/header_extension.rs::tests::wire_layout_be_message_length_correct

Status: done

§9.3.2.8 UExtension4_t

Spec: §9.3.2.8, p. 157 — “This type is used to represent an undefined 4-byte value.”

Repo: crates/rtps/src/header_extension.rs (uextension4: [u8; 4])

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_uextension4_be

Status: done

§9.3.2.9 WExtension8_t

Spec: §9.3.2.9, p. 157 — “This type is used to represent an undefined 8-byte value.”

Repo: crates/rtps/src/header_extension.rs (wextension8: [u8; 8])

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_wextension8_le

Status: done

§9.3.2.10 SequenceNumber_t

Spec: §9.3.2.10, p. 157 — “struct SequenceNumber_t { long high; unsigned long low; }; … sequence_number = low + high * 2^(32)”.

Repo: crates/rtps/src/wire_types.rs (SequenceNumber::to_bytes_le, from_bytes_le, to_bytes_be, from_bytes_be)

Tests: crates/rtps/src/wire_types.rs::tests::sequence_number_split_high_low, crates/rtps/src/wire_types.rs::tests::sequence_number_roundtrip_be

Status: done

§9.3.2.11 ChangeCount_t

Spec: §9.3.2.11, p. 157 — “This type is used to represent a 64-bit count. … struct ChangeCount_t { long high; unsigned long low; }; … change_count = low + high * 2^(32)”.

Repo: crates/rtps/src/submessages.rs (GapSubmessage::filtered_count: Option<u64>, write_body, read_body)

Tests: crates/rtps/src/submessages.rs::tests::gap_filtered_count_is_eight_octets_high_then_low, crates/rtps/src/submessages.rs::tests::gap_with_filtered_count_roundtrip_le

Status: done — ChangeCount_t is held as u64: high (long) and low (unsigned long) are eight octets in the byte order of the submessage, change_count = low + high * 2^32; a negative high is no count and is refused.

§9.3.2.12 BuiltinEndpointSet_t: positions 0 to 5

Spec: §9.3.2.12, pp. 157–158 — “@position(0) DISC_BUILTIN_ENDPOINT_PARTICIPANT_ANNOUNCER, @position(1) …_PARTICIPANT_DETECTOR, @position(2) …_PUBLICATIONS_ANNOUNCER, @position(3) …_PUBLICATIONS_DETECTOR, @position(4) …_SUBSCRIPTIONS_ANNOUNCER, @position(5) …_SUBSCRIPTIONS_DETECTOR”.

Repo: crates/rtps/src/participant_data.rs (endpoint_flag::PARTICIPANT_ANNOUNCER to SUBSCRIPTIONS_DETECTOR)

Tests: crates/rtps/src/participant_data.rs::tests::endpoint_flag_bit_positions_match_spec

Status: done

§9.3.2.12 BuiltinEndpointSet_t: positions 6 to 9 deprecated

Spec: §9.3.2.12, p. 158 — “/* Positions 6-9 were deprecated in version 2.4 */“; §9.3.2.1:”These bits should not be used by versions of the protocol equal to or newer than the deprecated version”.

Repo: crates/rtps/src/participant_data.rs (ALL_STANDARD without the bits 6 to 9)

Tests: crates/rtps/src/participant_data.rs::tests::endpoint_flag_all_standard_excludes_secure_bits, crates/dcps/src/runtime.rs::tests::spdp_announces_standard_bits_by_default

Status: done

§9.3.2.12 BuiltinEndpointSet_t: positions 10 and 11

Spec: §9.3.2.12, p. 158 — “@position(10) BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER, @position(11) BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_READER”.

Repo: crates/rtps/src/participant_data.rs (endpoint_flag::PARTICIPANT_MESSAGE_DATA_WRITER, …_READER)

Tests: crates/rtps/src/participant_data.rs::tests::endpoint_flag_bit_positions_match_spec

Status: done

§9.3.2.12 BuiltinEndpointSet_t: positions 12 to 15 (XTypes)

Spec: §9.3.2.12, p. 158 — “Positions 12-15 are reserved by DDS-XTypes 1.2 and its revisions thereof”.

Repo: crates/rtps/src/participant_data.rs (endpoint_flag::TYPE_LOOKUP_REQUEST, TYPE_LOOKUP_REPLY)

Tests: crates/dcps/tests/type_lookup_e2e.rs::announces_type_lookup_endpoints_in_spdp, crates/discovery/src/capabilities.rs::tests::type_lookup_capabilities_require_the_four_distinct_vendor_bits

Status: done

§9.3.2.12 BuiltinEndpointSet_t: positions 16 to 27 (DDS-Security)

Spec: §9.3.2.12, p. 158 — “Positions 16-27 are reserved by DDS-Security 1.1 and revisions thereof”.

Repo: crates/rtps/src/participant_data.rs (endpoint_flag::ALL_SECURE)

Tests: crates/rtps/src/participant_data.rs::tests::endpoint_flag_all_secure_covers_bits_16_to_27

Status: done

§9.3.2.12 BuiltinEndpointSet_t: positions 28 and 29

Spec: §9.3.2.12, p. 158 — “@position(28) DISC_BUILTIN_ENDPOINT_TOPICS_ANNOUNCER, @position(29) DISC_BUILTIN_ENDPOINT_TOPICS_DETECTOR”.

Repo: crates/rtps/src/participant_data.rs (endpoint_flag::TOPICS_ANNOUNCER, TOPICS_DETECTOR)

Tests: crates/rtps/src/participant_data.rs::tests::endpoint_flag_bit_positions_match_spec, crates/discovery/src/sedp/stack.rs::tests::the_topics_bits_wire_the_topics_writer_and_reader

Status: done

§9.4.1 Submessages on 32-bit boundaries

Spec: §9.4.1, p. 158 — “The PSM aligns each Submessage on a 32-bit boundary with respect to the start of the Message.”

Repo: crates/rtps/src/message_builder.rs (MessageBuilder::check_aligned)

Tests: crates/rtps/src/message_builder.rs::tests::nothing_is_appended_after_an_unaligned_submessage, crates/rtps/src/message_builder.rs::tests::four_small_datas_aggregate_into_one_datagram

Status: done — the decoder does not require the alignment on reception.

§9.4.1 Message length from the transport

Spec: §9.4.1, p. 158 — “A Message has a well-known length. This length is not sent explicitly by the RTPS protocol but is part of the underlying transport with which Messages are sent. In the case of UDP/IP, the length of the Message is the length of the UDP payload.”

Repo: crates/rtps/src/datagram.rs (decode_datagram: length of the datagram passed in)

Tests: crates/rtps/src/datagram.rs::tests::decode_handles_last_submessage_zero_length, crates/transport-udp/src/udp_transport.rs::tests::loopback_send_and_recv_delivers_datagram

Status: done

§9.4.2 Mapping of the submessage elements

Spec: §9.4.2, p. 158 — “This sub clause describes the PSM mapping for each of the SubmessageElements defined by the PIM.”

Repo: —

Tests: —

Status: n/a (informative) — introduction; the elements follow one by one.

§9.4.2.1 EntityId

Spec: §9.4.2.1, p. 159 — “typedef EntityId_t EntityId;” wire form octet value[4].

Repo: crates/rtps/src/wire_types.rs (EntityId::to_bytes, EntityId::from_bytes)

Tests: crates/rtps/src/wire_types.rs::tests::entity_id_roundtrip

Status: done

§9.4.2.2 GuidPrefix

Spec: §9.4.2.2, p. 159 — “typedef GuidPrefix_t GuidPrefix;” wire form octet value[12].

Repo: crates/rtps/src/wire_types.rs (GuidPrefix::to_bytes)

Tests: crates/rtps/src/wire_types.rs::tests::guid_prefix_roundtrip, crates/rtps/src/header.rs::tests::header_guid_prefix_at_bytes_8_to_19

Status: done

§9.4.2.3 VendorId

Spec: §9.4.2.3, p. 159 — “typedef VendorId_t VendorId;” wire form octet vendorId[2].

Repo: crates/rtps/src/wire_types.rs (VendorId::to_bytes)

Tests: crates/rtps/src/wire_types.rs::tests::vendor_id_roundtrip, crates/rtps/src/header.rs::tests::header_vendor_id_at_bytes_6_7

Status: done

§9.4.2.4 ProtocolVersion

Spec: §9.4.2.4, pp. 159–160 — “typedef ProtocolVersion_t ProtocolVersion;” wire form octet major | octet minor.

Repo: crates/rtps/src/wire_types.rs (ProtocolVersion::to_bytes)

Tests: crates/rtps/src/wire_types.rs::tests::protocol_version_roundtrip, crates/rtps/src/header.rs::tests::header_protocol_version_at_bytes_4_5

Status: done

§9.4.2.5 SequenceNumber

Spec: §9.4.2.5, p. 160 — wire form long high, unsigned long low.

Repo: crates/rtps/src/wire_types.rs (SequenceNumber::to_bytes_le, to_bytes_be)

Tests: crates/rtps/src/wire_types.rs::tests::sequence_number_roundtrip_le, crates/rtps/src/wire_types.rs::tests::sequence_number_roundtrip_be

Status: done

§9.4.2.6 SequenceNumberSet: structure and wire form

Spec: §9.4.2.6, pp. 160–161 — “struct SequenceNumberSet { SequenceNumber_t bitmapBase; LongSeq8 bitmap; };” wire form: bitmapBase, unsigned long numBits, long bitmap[M] with “M = (numBits+31)/32”. “The numBits field encodes both the number of significant bits and the number of bitmap elements.”

Repo: crates/rtps/src/submessages.rs (SequenceNumberSet::write_to, read_from)

Tests: crates/rtps/src/submessages.rs::tests::snset_wire_size_zero_bits_is_12_bytes, crates/rtps/src/submessages.rs::tests::snset_wire_size_33_bits_is_20_bytes, crates/rtps/src/submessages.rs::tests::snset_roundtrip_be

Status: done

§9.4.2.6 SequenceNumberSet: membership by bit position

Spec: §9.4.2.6, p. 160 — “(bitmap[deltaN/ 32] & (1 << (31 - deltaN%32))) == (1 << (31 - deltaN%32)) where deltaN = seqNum - seqNumSet.bitmapBase”; “In the bitmap, the bit corresponding to sequence number bitmapBase is on the left.”

Repo: crates/rtps/src/submessages.rs (SequenceNumberSet::from_missing, iter_set: bit 31 - offset % 32)

Tests: crates/rtps/tests/proptest_roundtrip.rs::seqnum_set_iter_matches_missing, crates/rtps/src/submessages.rs::tests::snset_roundtrip_le

Status: done

§9.4.2.6 SequenceNumberSet: validity

Spec: §9.4.2.6, p. 160 — “A valid SequenceNumberSet must satisfy the following conditions: bitmapBase >= 1; 0 <= numBits <= 256; there are M=(numBits+31)/32 longs containing the pertinent bits”.

Repo: crates/rtps/src/submessages.rs (SequenceNumberSet::read_from)

Tests: crates/rtps/src/submessages.rs::validity_tests::gap_and_sequence_number_set_validity_rules, crates/rtps/src/submessages.rs::tests::seqnumset_rejects_num_bits_above_256, crates/rtps/src/submessages.rs::tests::snset_decode_rejects_truncated_bitmap, crates/rtps/tests/vendor_frames.rs::the_empty_acknack_of_opendds_and_rti_is_invalid_by_default, crates/rtps/tests/vendor_frames.rs::opendds_session_re_encodes_byte_for_byte, crates/rtps/tests/vendor_frames.rs::rti_session_re_encodes_byte_for_byte, crates/rtps/src/submessages.rs::validity_tests::the_empty_set_with_base_zero_is_accepted_only_on_request

Status: done — bitmapBase >= 1, numBits <= 256 and the number of bitmap words are checked. Vendor form: OpenDDS 3.34.0 and RTI Connext 7.7.0 send readerSNState 0/0: (bitmapBase 0, numBits 0) as the ACKNACK of a reader without samples (measured in tools/wire-capture/rtps-sessions: 40 and 8 ACKNACKs). Default: invalid. The setting wire.accept_empty_acknack_base_zero (env ZERODDS_WIRE_ACCEPT_EMPTY_ACKNACK_BASE_ZERO, default false) accepts exactly this empty set in an ACKNACK, for the process.

§9.4.2.6 Table 9.5 example 1234/12:00110

Spec: §9.4.2.6, p. 161, Table 9.5 — “Example of bitmap: meaning of “1234/12:00110””.

Repo: crates/rtps/src/submessages.rs (SequenceNumberSet: iter_set, write_to, read_from)

Tests: crates/rtps/src/submessages.rs::tests::the_bitmap_1234_12_00110_of_table_9_5_names_1236_and_1237

Status: done — bitmapBase 1234, numBits 12, bits 00110: the numbers 1236 and 1237 are set, 1234, 1235 and 1238 to 1245 are not; the bit for bitmapBase is on the left (most significant bit of the first word). The test writes and reads the example in both byte orders.

§9.4.2.7 FragmentNumber

Spec: §9.4.2.7, p. 161 — “typedef FragmentNumber_t FragmentNumber;” wire form unsigned long value.

Repo: crates/rtps/src/wire_types.rs (FragmentNumber::to_bytes_le)

Tests: crates/rtps/src/wire_types.rs::tests::fragment_number_roundtrip_le_be

Status: done

§9.4.2.8 FragmentNumberSet: structure and wire form

Spec: §9.4.2.8, pp. 161–162 — “struct FragmentNumberSet { FragmentNumber_t bitmapBase; LongSeq8 bitmap; };” “The interpretation matches that of a SequenceNumberSet.” Wire form: bitmapBase, numBits, long bitmap[M].

Repo: crates/rtps/src/submessages.rs (FragmentNumberSet::write_to, read_from)

Tests: crates/rtps/src/submessages.rs::tests::fnset_wire_size_formula, crates/rtps/src/submessages.rs::tests::fnset_roundtrip_be, crates/rtps/src/submessages.rs::tests::fnset_rejects_num_bits_above_256

Status: done

§9.4.2.8 FragmentNumberSet: validity

Spec: §9.4.2.8, p. 162 — “The interpretation matches that of a SequenceNumberSet.” (§9.4.2.6: “bitmapBase >= 1”, “0 <= numBits <= 256”).

Repo: crates/rtps/src/submessages.rs (FragmentNumberSet::read_from)

Tests: crates/rtps/src/submessages.rs::validity_tests::fragment_submessages_validity_rules, crates/rtps/src/submessages.rs::tests::fnset_rejects_num_bits_above_256

Status: done — bitmapBase >= 1 and numBits <= 256 are checked.

§9.4.2.9 Timestamp

Spec: §9.4.2.9, p. 162 — “typedef Time_t Timestamp;” wire form long seconds, unsigned long fraction.

Repo: crates/rtps/src/submessages.rs (InfoTimestampSubmessage, timestamp_body)

Tests: crates/rtps/src/submessages.rs::tests::info_timestamp_roundtrip_le, crates/rtps/src/submessages.rs::tests::info_timestamp_roundtrip_be

Status: done — HeTimestamp::seconds is i32 as in the wire form; §9.3.2.1 names unsigned long seconds (open item under §9.3.2.1 Time_t).

§9.4.2.10 LocatorList

Spec: §9.4.2.10, pp. 162–163 — “typedef sequence<Locator_t, 8> LocatorList;” wire form unsigned long numLocators, then the locators with long kind, unsigned long port, octet address[16].

Repo: crates/rtps/src/submessages.rs (InfoReplySubmessage, read_locator_list)

Tests: crates/rtps/src/submessages.rs::tests::info_reply_with_multicast_roundtrip_be, crates/rtps/src/submessages.rs::tests::info_reply_empty_unicast_list_is_valid, crates/rtps/src/submessages.rs::validity_tests::info_reply_locator_list_holds_at_most_8_locators

Status: done — the wire layout and the limit of 8 locators are as specified.

§9.4.2.10 LocatorList at most 8 locators

Spec: §9.4.2.10, p. 162 — “typedef sequence<Locator_t, 8> LocatorList;”

Repo: crates/rtps/src/submessages.rs (InfoReplySubmessage::read_locator_list)

Tests: crates/rtps/src/submessages.rs::validity_tests::info_reply_locator_list_holds_at_most_8_locators

Status: done — a list of more than 8 locators is refused.

§9.4.2.11 Parameter: alignment and length

Spec: §9.4.2.11, p. 163 — “Each Parameter within the ParameterList starts aligned on a 4-byte boundary with respect to the start of the ParameterList.” “The length encodes the number of octets following the length to reach the ID of the next parameter … the length is always a multiple of four.”

Repo: crates/rtps/src/parameter_list.rs (ParameterList::to_bytes, from_bytes_with_consumed: length % 4 != 0 is refused)

Tests: crates/rtps/src/parameter_list.rs::tests::decode_rejects_non_aligned_length, crates/rtps/src/parameter_list.rs::tests::parameter_value_is_padded_to_4_bytes

Status: done

§9.4.2.11 Parameter: CDR reset per value

Spec: §9.4.2.11, p. 163 — “The value contains the CDR representation of the Parameter type that corresponds to the specified parameterId. For alignment purposes, the CDR stream is logically reset for each parameter value”.

Repo: crates/rtps/src/publication_data.rs, crates/rtps/src/participant_data.rs (every value is encoded from offset 0)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full, crates/discovery/tests/vendor_discovery_frames.rs::cyclone_announcements_read_and_write_back

Status: done

§9.4.2.11 Several parameters with the same ParameterId

Spec: §9.4.2.11, p. 163 — “The ParameterList may contain multiple Parameters with the same value for the parameterId. This is used to provide a collection of values for that kind of Parameter.”

Repo: crates/rtps/src/parameter_list.rs (ParameterList::find_all)

Tests: crates/rtps/src/participant_data.rs::tests::decode_retains_all_repeated_unicast_locators_in_order_le_and_be, crates/rtps/src/parameter_list.rs::tests::roundtrip_multiple_parameters

Status: done

§9.4.2.11 PID_SENTINEL

Spec: §9.4.2.11, p. 164 — “#define PID_SENTINEL (1)”; “The PID_SENTINEL is used to terminate the parameter list and its length is ignored.”

Repo: crates/rtps/src/parameter_list.rs (pid::SENTINEL; from_bytes_with_consumed ends at the sentinel without evaluating its length)

Tests: crates/rtps/src/parameter_list.rs::tests::empty_parameter_list_is_just_sentinel, crates/rtps/src/parameter_list.rs::tests::decode_rejects_missing_sentinel

Status: done

§9.4.2.11 PID_PAD

Spec: §9.4.2.11, p. 164 — “#define PID_PAD (0)”; “The PID_PAD is used to enforce alignment of the parameter that follows and its length can be anything (as long as it is a multiple of 4).”

Repo: crates/rtps/src/parameter_list.rs (pid::PAD, ParameterList::from_bytes_with_consumed)

Tests: crates/rtps/src/parameter_list.rs::tests::pid_pad_is_skipped

Status: done

§9.4.2.11 Sentinel not required in the HeaderExtension

Spec: §9.4.2.11, p. 164 — “The presence of the PID_SENTINEL is not required in the ParameterList that appears in the HeaderExtension. See 9.4.5.2. The presence of the PID_SENTINEL is required in all other cases.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::decode_body, ParameterList::from_bytes_sentinel_optional)

Tests: crates/rtps/src/header_extension.rs::tests::decode_takes_a_parameter_list_without_sentinel, crates/rtps/src/parameter_list.rs::tests::decode_rejects_missing_sentinel

Status: done — the parameters of the HeaderExtension are read without PID_SENTINEL; in all other cases the sentinel is required (decode_rejects_missing_sentinel).

§9.4.2.11 Table 9.6 bit 0x8000: vendor-specific

Spec: §9.4.2.11, p. 165, Table 9.6 — “ParameterId & 8000 — 0 — Reserved ParameterId. — 1 — Vendor-specific ParameterId. Will not be recognized by other vendors’ implementations.”

Repo: crates/rtps/src/parameter_list.rs (VENDOR_SPECIFIC_BIT); crates/rtps/src/publication_data.rs (vendor parameters by vendorId)

Tests: crates/discovery/tests/vendor_discovery_frames.rs::rti_announcements_read_and_write_back, crates/rtps/src/parameter_list.rs::tests::a_vendor_specific_must_understand_pid_of_another_vendor_is_an_error

Status: done

§9.4.2.11 Table 9.6 bit 0x4000 = 0: skip if unknown

Spec: §9.4.2.11, p. 165, Table 9.6 — “ParameterId & 4000 — 0 — If the ParameterId is not recognized, skip and ignore the parameter.”

Repo: crates/rtps/src/parameter_list.rs (validate_must_understand_in_data_pipeline); decoders in crates/rtps/src/publication_data.rs

Tests: crates/rtps/src/publication_data.rs::tests::unknown_pids_are_skipped, crates/rtps/src/parameter_list.rs::tests::validate_must_understand_in_data_pipeline_optional_unknown_pid_passes

Status: done

§9.4.2.11 Table 9.6 bit 0x4000 = 1: an error if unknown

Spec: §9.4.2.11, p. 165, Table 9.6 — “1 — If the ParameterId is not recognized, treat it as an error. If the ParameterId appears in the HeaderExtension, ignore the entire RTPS message. If the ParameterId appears in any other Submessage, ignore the Submessage and continue with the next Submessage in the RTPS message, if any.”

Repo: crates/rtps/src/datagram.rs (decode_submessage); crates/rtps/src/parameter_list.rs (validate_must_understand_in_data_pipeline, is_known_vendor_pid)

Tests: crates/rtps/src/datagram.rs::tests::a_data_with_an_unknown_must_understand_pid_is_skipped, crates/rtps/src/datagram.rs::tests::a_data_with_a_vendor_specific_must_understand_pid_is_skipped, crates/rtps/src/parameter_list.rs::tests::a_vendor_specific_must_understand_pid_of_another_vendor_is_an_error

Status: done — in the HeaderExtension the whole message is dropped; a DATA or DATA_FRAG with an unrecognized PID with bit 0x4000 is skipped and the next submessage is read. That holds in the vendor-specific range (bit 0x8000) too: there only the ZeroDDS PIDs (0x8001, 0x8002) from a ZeroDDS sender are recognized.

§9.4.2.11 Table 9.7 DDS-Security: 0x1000–0x10ff, 0x5000–0x50ff

Spec: §9.4.2.11, p. 165, Table 9.7 — “DDS-Security 1.1 — 0x1000-0x10ff and 0x5000-0x50ff”.

Repo: crates/rtps/src/parameter_list.rs (pid::IDENTITY_TOKEN, PERMISSIONS_TOKEN, PARTICIPANT_SECURITY_INFO and others)

Tests: crates/rtps/src/parameter_list.rs::tests::is_standard_pid_recognises_dds_security_pids

Status: done

§9.4.2.11 Table 9.7 DDS-XTypes: 0x0069, 0x0072–0x0075, 0x3f01–0x3fff, 0x7f01–0x7fff

Spec: §9.4.2.11, p. 165, Table 9.7 — “DDS-XTypes 1.2 — 0x0069; 0x0072-0x0075; 0x3f01-0x3fff; 0x7f01-0x7fff”.

Repo: crates/rtps/src/parameter_list.rs (pid::IGNORE = 0x3F03, PID_DATA_REPRESENTATION, PID_TYPE_CONSISTENCY, PID_TYPE_INFORMATION)

Tests: crates/rtps/src/parameter_list.rs::tests::pid_ignore_skipped_in_pl_cdr_decode, crates/discovery/tests/vendor_discovery_frames.rs::cyclone_announcements_read_and_write_back

Status: done

§9.4.2.11 Missing PID: default; unknown PID by Table 9.6

Spec: §9.4.2.11, p. 165 — “If a ParameterId is expected, but not present, the protocol will assume the default value. Similarly, if a ParameterId is present but not recognized, the protocol will either skip and ignore the parameter or treat the parameter as an incompatible QoS.”

Repo: crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs, crates/rtps/src/participant_data.rs

Tests: crates/rtps/src/publication_data.rs::tests::an_absent_reliability_parameter_reads_as_reliable_on_a_publication, crates/rtps/src/publication_data.rs::tests::the_infinite_defaults_are_left_out_and_read_back, crates/rtps/src/subscription_data.rs::tests::the_readers_infinite_defaults_are_left_out_and_read_back, crates/rtps/src/publication_data.rs::tests::unknown_pids_are_skipped

Status: done — the default per PID is listed under §9.6.3.2, the must-understand behaviour under Table 9.6.

§9.4.2.12 SerializedPayload

Spec: §9.4.2.12, p. 165 — “For the purpose of interoperability, all implementations must however use a consistent representation (See, 10 Serialized Payload Representation).”

Repo: —

Tests: —

Status: n/a (informative) — a reference; the representation is listed under §10.

§9.4.2.13 Count

Spec: §9.4.2.13, p. 166 — “typedef Count_t Count;” wire form long value.

Repo: crates/rtps/src/submessages.rs (count: i32)

Tests: crates/rtps/src/submessages.rs::tests::acknack_submessage_roundtrip_le, crates/rtps/src/submessages.rs::tests::nack_frag_roundtrip_be

Status: done

§9.4.2.14 ChangeCount

Spec: §9.4.2.14, p. 166 — “typedef ChangeCount_t ChangeCount;” wire form long high, unsigned long low (8 octets).

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::gap_filtered_count_is_eight_octets_high_then_low, crates/rtps/src/submessages.rs::tests::gap_with_filtered_count_roundtrip_le

Status: done

§9.4.2.15 Table 9.8 ChecksumFlags (0,0)

Spec: §9.4.2.15, p. 166, Table 9.8 — “0, 0 — N/A — The messageChecksum is not included in the HeaderExtension”.

Repo: crates/rtps/src/header_extension.rs (ChecksumKind::None)

Tests: crates/rtps/src/header_extension.rs::tests::checksum_kind_roundtrip, crates/rtps/src/header_extension.rs::tests::empty_he_le_roundtrip

Status: done

§9.4.2.15 Table 9.8 ChecksumFlags (0,1) CRC-32C

Spec: §9.4.2.15, p. 166, Table 9.8 — “0, 1 — Checksum32_t — … the big-endian representation of the CRC-32C (Castagnoli) checksum of the RTPS message. … It shall be serialized into the 4-bytes of the Checksum32_t type using CDR big endian encoding.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::message_checksum, seal_message, verify_message, encode_body, decode_body); crates/rtps/src/datagram.rs (decode_submessage)

Tests: crates/rtps/src/header_extension.rs::tests::checksum_compute_crc32c_matches_rfc4960_vector, crates/rtps/src/header_extension.rs::tests::the_checksums_of_tables_9_10_and_9_12, crates/rtps/src/header_extension.rs::tests::a_sealed_message_verifies_and_a_changed_one_does_not

Status: done

§9.4.2.15 Table 9.8 ChecksumFlags (1,0) CRC-64/XZ

Spec: §9.4.2.15, pp. 166–167, Table 9.8 — “1, 0 — Checksum64_t — … the big-endian representation of the CRC-64/XZ checksum of the RTPS message. … CDR big endian encoding.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::message_checksum, seal_message, verify_message, encode_body, decode_body); crates/rtps/src/datagram.rs (decode_submessage)

Tests: crates/rtps/src/header_extension.rs::tests::checksum_compute_crc64_xz_matches_known_vector, crates/rtps/src/header_extension.rs::tests::the_checksums_of_tables_9_10_and_9_12, crates/rtps/src/header_extension.rs::tests::a_sealed_message_verifies_and_a_changed_one_does_not

Status: done

§9.4.2.15 Table 9.8 ChecksumFlags (1,1) MD5

Spec: §9.4.2.15, p. 167, Table 9.8 — “1,1 — Checksum128_t — The messageChecksum is a 128-bit checksum. It shall hold the MD5 digest of the RTPS message.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::message_checksum, seal_message, verify_message, encode_body, decode_body); crates/rtps/src/datagram.rs (decode_submessage)

Tests: crates/rtps/src/header_extension.rs::tests::checksum_compute_md5_matches_rfc1321_vector, crates/rtps/src/header_extension.rs::tests::a_sealed_message_verifies_and_a_changed_one_does_not

Status: done

§9.4.2.15 Checksum: byte order, range, verification

Spec: §9.4.2.15, p. 167 — “the checksum shall be computed over the content of the RTPS Message, which includes the RTPS Header and HeaderExtension submessage. Moreover, for the purpose of computing the checksum, all the bytes of the messageChecksum field in the RTPS HeaderExtension shall be set to zero.”; Table 9.8: “CDR big endian encoding”.

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::message_checksum, seal_message, verify_message, encode_body, decode_body); crates/rtps/src/datagram.rs (decode_submessage)

Tests: crates/rtps/src/header_extension.rs::tests::a_sealed_message_verifies_and_a_changed_one_does_not, crates/rtps/src/header_extension.rs::tests::the_checksum_is_big_endian_in_a_little_endian_header_extension, crates/rtps/src/datagram.rs::tests::a_message_with_a_wrong_checksum_is_refused_and_counted

Status: done — CRC-32C and CRC-64 are in big endian, the checksum is over the whole message with the field zeroed, and the receiver checks it.

§9.4.2.15 Table 9.9 parameters of CRC-32C

Spec: §9.4.2.15, p. 168, Table 9.9 — width 32 bits, polynomial 0x1EDC6F41, input and result reflected, initial value and final XOR 0xFFFFFFFF.

Repo: crates/foundation (crc32c)

Tests: crates/rtps/src/header_extension.rs::tests::checksum_compute_crc32c_matches_rfc4960_vector

Status: done

§9.4.2.15 Table 9.10 examples CRC-32C

Spec: §9.4.2.15, p. 168, Table 9.10 — “Example Checksum32_t computation”: 00 00 00 00 → 0x48674BC7, FF FF FF FF → 0xFFFFFFFF, 33 22 55 AA BB CC DD EE FF → 0xB59CA09B.

Repo: crates/rtps/src/header_extension.rs (ChecksumValue::compute)

Tests: crates/rtps/src/header_extension.rs::tests::the_checksums_of_tables_9_10_and_9_12

Status: done — the three examples of the table.

§9.4.2.15 Table 9.11 parameters of CRC-64/XZ

Spec: §9.4.2.15, p. 168, Table 9.11 — width 64 bits, polynomial 0x42F0E1EBA9EA3693, input and result reflected, initial value and final XOR 0xFFFFFFFFFFFFFFFF.

Repo: crates/foundation (crc64_xz)

Tests: crates/rtps/src/header_extension.rs::tests::checksum_compute_crc64_xz_matches_known_vector

Status: done

§9.4.2.15 Table 9.12 examples CRC-64/XZ

Spec: §9.4.2.15, p. 169, Table 9.12 — “Example Checksum64_t computation”: 00 00 00 00 → 0xF4A586351E1B9F4B, FF FF FF FF → 0xFFFFFFFF00000000, 33 22 55 AA BB CC DD EE FF → 0x701ECEB219A8E5D5.

Repo: crates/rtps/src/header_extension.rs (ChecksumValue::compute)

Tests: crates/rtps/src/header_extension.rs::tests::the_checksums_of_tables_9_10_and_9_12

Status: done — the three examples of the table.

§9.4.2.16 MessageLength

Spec: §9.4.2.16, p. 169 — “typedef MessageLength_t MessageLength;” wire form unsigned long length.

Repo: crates/rtps/src/header_extension.rs (message_length)

Tests: crates/rtps/src/header_extension.rs::tests::wire_layout_le_message_length_correct

Status: done

§9.4.2.17 UExtension4

Spec: §9.4.2.17, p. 169 — “typedef UExtension4_t UExtension4;” wire form octet value[4].

Repo: crates/rtps/src/header_extension.rs (uextension4)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_uextension4_be

Status: done

§9.4.2.18 WExtension8

Spec: §9.4.2.18, p. 169 — “typedef WExtension8_t WExtension8;” wire form octet value[8].

Repo: crates/rtps/src/header_extension.rs (wextension8)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_wextension8_le

Status: done

§9.4.2.19 GroupDigest

Spec: §9.4.2.19, pp. 169–170 — “typedef GroupDigest_t GroupDigest;” wire form octet value[4].

Repo: crates/rtps/src/group_digest.rs (GroupDigest, GroupDigest::of_entities)

Tests: crates/rtps/src/group_digest.rs::tests::two_writers_digest_as_section_9_3_2_5_computes_it, crates/rtps/src/group_digest.rs::tests::the_digest_does_not_depend_on_the_order_given, crates/rtps/src/group_digest.rs::tests::the_empty_group_is_zero_and_not_the_hash_of_an_empty_sequence

Status: done

§9.4.3.1 LocatorUDPv4

Spec: §9.4.3.1, p. 170, Table 9.13 — “The LocatorUDPv4 SubmessageElement is identical to a LocatorList SubmessageElement containing a single locator of kind LOCATOR_KIND_UDPv4.” Wire form unsigned long address, unsigned long port.

Repo: crates/rtps/src/submessages.rs (InfoReplyIp4Submessage::write_locator_udpv4, read_locator_udpv4)

Tests: crates/rtps/src/submessages.rs::tests::locator_udpv4_is_two_unsigned_longs_in_the_byte_order_of_the_submessage, crates/rtps/src/submessages.rs::tests::info_reply_ip4_with_multicast_roundtrip_be

Status: done — address and port are each an unsigned long in the byte order of the submessage; 192.0.2.10 is the number 0xC000020A (first octet most significant). Before, the address was four octets in network order in every byte order, which differs in the little-endian case. 2.5 does not define LocatorUDPv4_t; the mapping of a.b.c.d to the number is an assumption. No vendor is measured.

Spec: §9.4.4, p. 170 — wire form 'R' 'T' 'P' 'S', ProtocolVersion version, VendorId vendorId, GuidPrefix guidPrefix. “The structure of the Header cannot change in this major version (2) of the protocol.”

Repo: crates/rtps/src/header.rs (RtpsHeader::to_bytes, from_bytes)

Tests: crates/rtps/src/header.rs::tests::header_roundtrip, crates/rtps/src/header.rs::tests::header_total_size_is_20_bytes

Status: done

§9.4.4 Use an assigned VendorId

Spec: §9.4.4, p. 170 — “To be compliant with the DDS Interoperability Specification a vendor must have a reserved Vendor ID and use it.”

Repo: —

Tests: —

Status: blocked — assignment of a VendorId by the OMG (applied for); lifted once the OMG assigns the value and VendorId::ZERODDS carries it. Until then ZeroDDS sends 0x01F0 (crates/rtps/src/wire_types.rs, by its comment an interim value), a value the OMG list does not hold (assigned up to {0x01,0x1C}, {0x01,0x1D} and {0x01,0x1E} reserved).

§9.4.5.1 SubmessageHeader

Spec: §9.4.5.1, p. 171 — “struct SubmessageHeader { octet submessageId; octet flags; unsigned short submessageLength; /* octetsToNextHeader */ };” “This general structure cannot change in this major version (2) of the protocol.”

Repo: crates/rtps/src/submessage_header.rs (SubmessageHeader::to_bytes, from_bytes)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_header_layout_le, crates/rtps/src/submessage_header.rs::tests::submessage_header_layout_be

Status: done

§9.4.5.1.1 SubmessageKind RTPS_HE = 0x00

Spec: §9.4.5.1.1, p. 171 — “@value(0x00) RTPS_HE, /* HeaderExtension */“.

Repo: crates/rtps/src/header_extension.rs (SUBMESSAGE_ID_HEADER_EXTENSION = 0x00), crates/rtps/src/datagram.rs (decode_datagram)

Tests: crates/rtps/tests/cyclone_he_must_understand.rs::local_encoder_produces_must_understand_bit, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§9.4.5.1.1 SubmessageKind PAD = 0x01

Spec: §9.4.5.1.1, p. 171 — “@value(0x01) PAD, /* Pad */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::Pad)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_octets_match_spec_table_8_13

Status: done

§9.4.5.1.1 SubmessageKind ACKNACK = 0x06

Spec: §9.4.5.1.1, p. 171 — “@value(0x06) ACKNACK /* AckNack */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::AckNack)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_acknack_is_0x06

Status: done

§9.4.5.1.1 SubmessageKind HEARTBEAT = 0x07

Spec: §9.4.5.1.1, p. 171 — “@value(0x07) HEARTBEAT /* Heartbeat */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::Heartbeat)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_heartbeat_is_0x07

Status: done

§9.4.5.1.1 SubmessageKind GAP = 0x08

Spec: §9.4.5.1.1, p. 171 — “@value(8x08) GAP /* Gap */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::Gap)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_gap_is_0x08

Status: done

§9.4.5.1.1 SubmessageKind INFO_TS = 0x09

Spec: §9.4.5.1.1, p. 171 — “@value(0x09) INFO_TS /* InfoTimestamp */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::InfoTs)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_octets_match_spec_table_8_13

Status: done

§9.4.5.1.1 SubmessageKind INFO_SRC = 0x0c

Spec: §9.4.5.1.1, p. 171 — “@value(0x0c) INFO_SRC /* InfoSource */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::InfoSrc)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_octets_match_spec_table_8_13

Status: done

§9.4.5.1.1 SubmessageKind INFO_REPLY_IP4 = 0x0d

Spec: §9.4.5.1.1, p. 171 — “@value(0x0d) INFO_REPLY_IP4 /* InfoReplyIp4 */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::InfoReplyIp4)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_octets_match_spec_table_8_13

Status: done

§9.4.5.1.1 SubmessageKind INFO_DST = 0x0e

Spec: §9.4.5.1.1, p. 171 — “@value(0x0e) INFO_DST /* InfoDestination */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::InfoDst)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_octets_match_spec_table_8_13

Status: done

§9.4.5.1.1 SubmessageKind INFO_REPLY = 0x0f

Spec: §9.4.5.1.1, p. 171 — “@value(0x0f) INFO_REPLY /* InfoReply */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::InfoReply)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_octets_match_spec_table_8_13

Status: done

§9.4.5.1.1 SubmessageKind NACK_FRAG = 0x12

Spec: §9.4.5.1.1, p. 171 — “@value(0x12) NACK_FRAG /* NackFrag */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::NackFrag)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_octets_match_spec_table_8_13

Status: done

§9.4.5.1.1 SubmessageKind HEARTBEAT_FRAG = 0x13

Spec: §9.4.5.1.1, p. 171 — “@value(0x13) HEARTBEAT_FRAG /* HeartbeatFrag */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::HeartbeatFrag)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_octets_match_spec_table_8_13

Status: done

§9.4.5.1.1 SubmessageKind DATA = 0x15

Spec: §9.4.5.1.1, p. 171 — “@value(0x15) DATA /* Data */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::Data)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_data_is_0x15

Status: done

§9.4.5.1.1 SubmessageKind DATA_FRAG = 0x16

Spec: §9.4.5.1.1, p. 171 — “@value(0x16) DATA_FRAG /* DataFrag */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::DataFrag)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_octets_match_spec_table_8_13

Status: done

§9.4.5.1.1 The meaning of the SubmessageIds is fixed

Spec: §9.4.5.1.1, p. 171 — “The meaning of the Submessage IDs cannot be modified in this major version (2). Additional Submessages can be added in higher minor versions.”

Repo: —

Tests: —

Status: n/a (informative) — a requirement on future editions of the specification.

§9.4.5.1.1 Ids 0x80–0xff by vendorId

Spec: §9.4.5.1.1, p. 171 — “Submessages with ID’s 0x80 to 0xff (inclusive) are vendor-specific; they will not be defined by future versions of the protocol. Their interpretation is dependent on the vendorId that is current when the Submessage is encountered.”

Repo: crates/rtps/src/datagram.rs (decode_datagram, ParsedSubmessage::Unknown)

Tests: crates/rtps/src/datagram.rs::tests::decode_skips_an_unknown_submessage_whatever_its_flags

Status: done — ZeroDDS defines no submessage of its own; every id 0x80–0xff is passed over.

§9.4.5.1.1.1 Table 9.14 DDS-Security 0x30–0x3f

Spec: §9.4.5.1.1.1, p. 172, Table 9.14 — “DDS-Security 1.1 — 0x30-0x3f”.

Repo: crates/security-rtps/src/codec.rs (SEC_PREFIX = 0x31, SEC_BODY, SEC_POSTFIX, SRTPS_PREFIX, SRTPS_POSTFIX)

Tests: crates/security-rtps/src/codec.rs::tests::constants_match_spec, crates/security-rtps/src/codec.rs::tests::three_submessages_carry_spec_ids_flags_and_lengths_in_order

Status: done

§9.4.5.1.2 EndiannessFlag in the least significant bit

Spec: §9.4.5.1.2, p. 172 — “The PSM maps the EndiannessFlag flag into the least-significant bit (LSB) of the flags. … E=0 means big-endian, E=1 means little-endian. … E = SubmessageHeader.flags & 0x01”.

Repo: crates/rtps/src/submessage_header.rs (FLAG_E_LITTLE_ENDIAN = 0x01)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_header_is_little_endian_flag, crates/rtps/src/submessage_header.rs::tests::submessage_header_roundtrip_be

Status: done

§9.4.5.1.2 X flags: send zero, ignore on reception

Spec: §9.4.5.1.2, p. 172 — “Implementations of RTPS version 2.5 should set these to zero when sending and ignore these when receiving.”

Repo: crates/rtps/src/submessages.rs (the encoders set only the defined flags; the decoders read only these); crates/rtps/src/datagram.rs

Tests: crates/rtps/src/datagram.rs::tests::x_flags_are_zero_when_sending_and_ignored_when_receiving, crates/rtps/src/datagram.rs::tests::decode_heartbeat_preserves_final_and_liveliness_flags, crates/rtps/src/datagram.rs::tests::data_frag_spec_and_cyclone_flag_oracle

Status: done — the encoders of HEARTBEAT, ACKNACK, GAP, HEARTBEAT_FRAG, NACK_FRAG, INFO_TS, INFO_SRC, INFO_REPLY, INFO_REPLY_IP4 and DATA set only E and the flags defined for the submessage; the decoders give the same value with all other flag bits set. For unknown submessages §8.3.4.1 rule 3 applies.

§9.4.5.1.3 octetsToNextHeader as a ushort

Spec: §9.4.5.1.3, p. 172 — “The representation of this field is a CDR unsigned short (ushort).”

Repo: crates/rtps/src/submessage_header.rs (octets_to_next_header: u16)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_header_roundtrip_le

Status: done

§9.4.5.1.3 octetsToNextHeader > 0

Spec: §9.4.5.1.3, p. 172 — “In case octetsToNextHeader > 0, it is the number of octets from the first octet of the contents of the Submessage until the first octet of the header of the next Submessage … OR it is the number of octets remaining in the Message”.

Repo: crates/rtps/src/datagram.rs (decode_datagram: body_end)

Tests: crates/rtps/src/datagram.rs::tests::encode_decode_two_data_submessages, crates/rtps/src/datagram.rs::tests::pad_submessage_is_skipped_and_the_data_behind_it_still_decodes

Status: done

§9.4.5.1.3 octetsToNextHeader == 0 except PAD and INFO_TS

Spec: §9.4.5.1.3, p. 172 — “In case octetsToNextHeader==0 and the kind of Submessage is NOT PAD or INFO_TS, the Submessage is the last Submessage in the Message and extends up to the end of the Message.”

Repo: crates/rtps/src/datagram.rs (decode_datagram)

Tests: crates/rtps/src/datagram.rs::tests::decode_handles_last_submessage_zero_length

Status: done

§9.4.5.1.3 octetsToNextHeader == 0 for PAD and INFO_TS

Spec: §9.4.5.1.3, p. 172 — “In case the octetsToNextHeader==0 and the kind of Submessage is PAD or INFO_TS, the next Submessage header starts immediately after the current Submessage header OR the PAD or INFO_TS is the last Submessage in the Message.”

Repo: crates/rtps/src/datagram.rs (decode_datagram)

Tests: crates/rtps/src/datagram.rs::tests::an_info_ts_without_a_body_is_not_the_last_submessage, crates/rtps/src/datagram.rs::tests::pad_submessage_is_skipped_and_re_encoded_byte_for_byte

Status: done

§9.4.5.2 HeaderExtension: wire form

Spec: §9.4.5.2, p. 173 — RTPS_HE |P|C|C|W|U|T|L|E|, then messageLength [L], rtpsSendTimestamp [T], uExtension4 [U], wExtension8 [W], messageChecksum [CC != 00], parameters [P].

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::encode_body, decode_body)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_all_fields_set_le, crates/rtps/src/header_extension.rs::tests::roundtrip_all_fields_set_be, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§9.4.5.2 HeaderExtension LengthFlag (0x02)

Spec: §9.4.5.2, p. 173 — “L = SubmessageHeader.flags & 0x02”.

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_L)

Tests: crates/rtps/src/header_extension.rs::tests::flag_byte_with_message_length, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§9.4.5.2 HeaderExtension TimestampFlag (0x04)

Spec: §9.4.5.2, p. 173 — “The TimestampFlag is represented with the literal ‘T’.” (expression in the text: “T = SubmessageHeader.flags & 0x04”).

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_W, bit 2)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_timestamp_le, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§9.4.5.2 HeaderExtension UExtension4Flag (0x08)

Spec: §9.4.5.2, p. 173 — “U = SubmessageHeader.flags & 0x08”.

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_U)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_uextension4_be, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§9.4.5.2 HeaderExtension WExtension8Flag (0x10)

Spec: §9.4.5.2, p. 173 — “W = SubmessageHeader.flags & 0x10”.

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_V, bit 4)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_wextension8_le, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§9.4.5.2 HeaderExtension ChecksumFlags C1 (0x40), C2 (0x20)

Spec: §9.4.5.2, p. 173 — “C1 = SubmessageHeader.flags & 0x40; C2 = SubmessageHeader.flags & 0x20”.

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_C_MASK, ChecksumKind::from_flags)

Tests: crates/rtps/src/header_extension.rs::tests::checksum_kind_roundtrip, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§9.4.5.2 HeaderExtension ParametersFlag (0x80)

Spec: §9.4.5.2, p. 174 — “P = SubmessageHeader.flags & 0x80”.

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_P)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_parameter_list, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§9.4.5.3 AckNack: wire form

Spec: §9.4.5.3, p. 174 — ACKNACK |X|X|X|X|X|X|F|E|, readerId, writerId, SequenceNumberSet readerSNState, Count count.

Repo: crates/rtps/src/submessages.rs (AckNackSubmessage::write_body, read_body)

Tests: crates/rtps/src/submessages.rs::tests::acknack_submessage_roundtrip_le

Status: done

§9.4.5.3 AckNack FinalFlag (0x02)

Spec: §9.4.5.3, p. 174 — “The PSM maps the FinalFlag flag into the 2nd least-significant bit (LSB) of the flags. … F = SubmessageHeader.flags & 0x02”.

Repo: crates/rtps/src/submessages.rs (ACKNACK_FLAG_FINAL = 0x02)

Tests: crates/rtps/src/datagram.rs::tests::decode_acknack_preserves_final_flag, crates/rtps/src/submessages.rs::tests::acknack_submessage_with_final_flag

Status: done

§9.4.5.3 AckNack F = 0: the writer answers with a Heartbeat

Spec: §9.4.5.3, p. 174 — “F=1 means the reader does not require a Heartbeat from the writer. F=0 means the writer must respond to the AckNack message with a Heartbeat message.”

Repo: crates/rtps/src/reliable_writer.rs (note_acknack_final_flag, tick); crates/rtps/src/reader_proxy.rs (heartbeat_asked, heartbeat_is_asked); calls in crates/dcps/src/runtime.rs, crates/discovery/src/sedp/stack.rs, crates/dcps/src/type_lookup_transport.rs

Tests: crates/rtps/src/reliable_writer.rs::tests::an_acknack_with_the_final_flag_clear_is_answered_by_a_heartbeat

Status: done — an ACKNACK with F = 0 is answered by a HEARTBEAT, at once when the reader had none yet, otherwise a period after the last one at the earliest; user, SEDP and TypeLookup writers.

§9.4.5.4 Data: wire form

Spec: §9.4.5.4, p. 174 — DATA |X|X|X|N|K|D|Q|E|, extraFlags, octetsToInlineQos, readerId, writerId, writerSN, inlineQos [Q], serializedPayload [D || K].

Repo: crates/rtps/src/submessages.rs (DataSubmessage::write_body, read_body_into)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_roundtrip_le, crates/rtps/tests/cyclone_compliance.rs::cyclone_data_cdr2_roundtrip_bit_identical

Status: done

§9.4.5.4 Data InlineQosFlag (0x02)

Spec: §9.4.5.4, p. 175 — “Q = SubmessageHeader.flags & 0x02”.

Repo: crates/rtps/src/submessages.rs (DATA_FLAG_INLINE_QOS = 0x02)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_all_valid_flags_combined_roundtrip, crates/rtps/tests/vendor_frames.rs::cyclone_session_re_encodes_byte_for_byte

Status: done

§9.4.5.4 Data DataFlag (0x04)

Spec: §9.4.5.4, p. 175 — “D = SubmessageHeader.flags & 0x04”.

Repo: crates/rtps/src/submessages.rs (DATA_FLAG_DATA = 0x04)

Tests: crates/rtps/tests/cyclone_compliance.rs::cyclone_data_cdr2_payload_decodes_and_carries_payload, crates/rtps/src/submessages.rs::tests::data_submessage_all_valid_flags_combined_roundtrip

Status: done

§9.4.5.4 Data KeyFlag (0x08)

Spec: §9.4.5.4, p. 175 — “K = SubmessageHeader.flags & 0x08”.

Repo: crates/rtps/src/submessages.rs (DATA_FLAG_KEY = 0x08)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_key_flag_roundtrip, crates/discovery/src/sedp/reader.rs::tests::handle_data_reports_a_cyclone_dispose_without_key_hash_as_removed

Status: done

§9.4.5.4 Data NonStandardPayloadFlag (0x10)

Spec: §9.4.5.4, p. 175 — “N = SubmessageHeader.flags & 0x10”.

Repo: crates/rtps/src/submessages.rs (DATA_FLAG_NON_STANDARD = 0x10)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_non_standard_flag_roundtrip

Status: done

§9.4.5.4 Data: combinations of D and K

Spec: §9.4.5.4, p. 175 — “D=0 and K=0 means that there is no serializedPayload SubmessageElement. D=1 and K=0 means that the serializedPayload SubmessageElement contains the serialized Data. D=0 and K=1 means that the serializedPayload SubmessageElement contains the serialized Key.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage); crates/rtps/src/reliable_reader.rs (handle_data_into)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_roundtrip_be_with_empty_payload, crates/dcps/tests/lifecycle_wire_e2e.rs::linux::dispose_marker_carries_the_key_fields_of_a_string_keyed_type

Status: done

§9.4.5.4 Data: D = 1 and K = 1 invalid

Spec: §9.4.5.4, p. 175 — “D=1 and K=1 is an invalid combination in this version of the protocol.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::read_body_into)

Tests: crates/rtps/src/submessages.rs::validity_tests::data_with_writer_sn_not_positive_or_with_d_and_k_is_invalid

Status: done — a DATA with D = 1 and K = 1 is refused, with the rest of the message.

§9.4.5.4 Data extraFlags zero

Spec: §9.4.5.4, p. 175 — “This version of the protocol should set all the bits in the extraFlags to zero.”

Repo: crates/rtps/src/reliable_writer.rs (extra_flags: 0)

Tests: crates/rtps/src/submessages.rs::tests::data_frag_decode_accepts_nonzero_extra_flags_silently, crates/rtps/tests/cyclone_compliance.rs::zerodds_writer_produces_compatible_data_layout

Status: done

§9.4.5.4 Data octetsToInlineQos

Spec: §9.4.5.4, p. 175 — “Implementations of the protocol that are processing a received submessage should always use the octetsToInlineQos to skip any submessage header elements it does not expect or understand and continue to process the inlineQos SubmessageElement”.

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::octets_to_inline_qos_skips_header_elements_of_a_later_version, crates/rtps/src/submessages.rs::tests::data_submessage_octets_to_inline_qos_is_16

Status: done

§9.4.5.5 DataFrag: wire form

Spec: §9.4.5.5, p. 176 — DATA_FRAG |X|X|X|X|N|K|Q|E|, extraFlags, octetsToInlineQos, readerId, writerId, writerSN, fragmentStartingNum, ushort fragmentsInSubmessage, ushort fragmentSize, unsigned long sampleSize, inlineQos [Q], serializedPayload.

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::write_body, read_body)

Tests: crates/rtps/src/submessages.rs::tests::data_frag_roundtrip_le, crates/rtps/src/submessages.rs::tests::data_frag_roundtrip_be

Status: done

§9.4.5.5 DataFrag InlineQosFlag (0x02)

Spec: §9.4.5.5, p. 176 — “Q = SubmessageHeader.flags & 0x02”.

Repo: crates/rtps/src/submessages.rs (DATA_FRAG_FLAG_INLINE_QOS = 0x02)

Tests: crates/rtps/src/datagram.rs::tests::data_frag_spec_and_cyclone_flag_oracle

Status: done

§9.4.5.5 DataFrag KeyFlag (0x04)

Spec: §9.4.5.5, p. 176 — “K = SubmessageHeader.flags & 0x04”.

Repo: crates/rtps/src/submessages.rs (DATA_FRAG_FLAG_KEY = 0x04)

Tests: crates/rtps/src/datagram.rs::tests::data_frag_spec_and_cyclone_flag_oracle

Status: done

§9.4.5.5 DataFrag NonStandardPayloadFlag (0x08)

Spec: §9.4.5.5, p. 176 — “N = SubmessageHeader.flags & 0x08”.

Repo: crates/rtps/src/submessages.rs (DATA_FRAG_FLAG_NON_STANDARD = 0x08)

Tests: crates/rtps/src/datagram.rs::tests::data_frag_spec_and_cyclone_flag_oracle, crates/rtps/src/submessages.rs::tests::data_frag_flags_survive_roundtrip

Status: done

§9.4.5.6 Gap: wire form

Spec: §9.4.5.6, p. 177 — GAP |X|X|X|X|X|F|G|E|, readerId, writerId, gapStart, gapList, gapStartGSN [G], gapEndGSN [G], ChangeCount filteredCount [F].

Repo: crates/rtps/src/submessages.rs (GapSubmessage::write_body, read_body)

Tests: crates/rtps/src/submessages.rs::tests::gap_filtered_count_is_eight_octets_high_then_low, crates/rtps/src/submessages.rs::tests::gap_with_filtered_count_roundtrip_le

Status: done

§9.4.5.6 Gap GroupInfoFlag (0x02)

Spec: §9.4.5.6, p. 177 — “G = SubmessageHeader.flags & 0x02”.

Repo: crates/rtps/src/submessages.rs (GAP_FLAG_GROUP_INFO = 0x02)

Tests: crates/rtps/src/submessages.rs::tests::the_gap_flags_are_those_of_9_4_5_6

Status: done

§9.4.5.6 Gap FilteredCountFlag (0x04)

Spec: §9.4.5.6, p. 177 — “F = SubmessageHeader.flags & 0x04”.

Repo: crates/rtps/src/submessages.rs (GAP_FLAG_FILTERED_COUNT = 0x04)

Tests: crates/rtps/src/submessages.rs::tests::the_gap_flags_are_those_of_9_4_5_6

Status: done

§9.4.5.6 Gap gapStartGSN and gapEndGSN

Spec: §9.4.5.6, p. 177 — “G=1 means the Gap also includes a gapStartGSN and a gapEndGSN.”

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::gap_with_group_info_roundtrip_be, crates/rtps/src/submessages.rs::tests::gap_decode_rejects_invalid_group_sequence_numbers, crates/rtps/src/submessages.rs::tests::a_gap_end_gsn_one_below_its_start_is_an_empty_range_and_valid, crates/rtps/src/submessages.rs::tests::the_gap_flags_are_those_of_9_4_5_6

Status: done

§9.4.5.7 Heartbeat: wire form

Spec: §9.4.5.7, p. 178 — HEARTBEAT |X|X|X|X|G|L|F|E|, readerId, writerId, firstSN, lastSN, Count count, currentGSN/firstGSN/lastGSN [G].

Repo: crates/rtps/src/submessages.rs (HeartbeatSubmessage::write_body, read_body)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_submessage_roundtrip_le, crates/rtps/tests/cyclone_compliance.rs::cyclone_heartbeat_decodes

Status: done — the part after count is listed under “Heartbeat: group fields”.

§9.4.5.7 Heartbeat FinalFlag (0x02)

Spec: §9.4.5.7, p. 178 — “F = SubmessageHeader.flags & 0x02”.

Repo: crates/rtps/src/submessages.rs (HEARTBEAT_FLAG_FINAL = 0x02)

Tests: crates/rtps/src/datagram.rs::tests::decode_heartbeat_preserves_final_and_liveliness_flags

Status: done

§9.4.5.7 Heartbeat LivelinessFlag (0x04)

Spec: §9.4.5.7, p. 178 — “L = SubmessageHeader.flags & 0x04”.

Repo: crates/rtps/src/submessages.rs (HEARTBEAT_FLAG_LIVELINESS = 0x04)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_submessage_liveliness_flag_roundtrip, crates/rtps/src/datagram.rs::tests::decode_heartbeat_preserves_final_and_liveliness_flags

Status: done

§9.4.5.7 Heartbeat GroupInfoFlag (0x08)

Spec: §9.4.5.7, p. 178 — “G = SubmessageHeader.flags & 0x08”.

Repo: crates/rtps/src/submessages.rs (HEARTBEAT_FLAG_GROUP_INFO = 0x08)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_with_group_info_roundtrip_le, crates/rtps/src/submessages.rs::tests::the_group_info_is_the_three_sequence_numbers_of_9_4_5_7

Status: done

§9.4.5.7 Heartbeat: group fields

Spec: §9.4.5.7, p. 178 — “G=1 means the HeartBeat includes the currentGSN, firstGSN, and lastGSN.”

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::the_group_info_is_the_three_sequence_numbers_of_9_4_5_7, crates/rtps/src/submessages.rs::tests::heartbeat_with_group_info_roundtrip_le, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_heartbeat_carries_the_groups_numbers

Status: done

§9.4.5.8 HeartBeatFrag: wire form

Spec: §9.4.5.8, p. 179 — HEARTBEAT_FRAG |X|X|X|X|X|X|X|E|, readerId, writerId, writerSN, lastFragmentNum, count.

Repo: crates/rtps/src/submessages.rs (HeartbeatFragSubmessage)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_frag_roundtrip_le, crates/rtps/src/datagram.rs::tests::decode_heartbeat_frag_roundtrip

Status: done

§9.4.5.9 InfoDestination: wire form

Spec: §9.4.5.9, p. 179 — INFO_DST |X|X|X|X|X|X|X|E|, GuidPrefix guidPrefix.

Repo: crates/rtps/src/datagram.rs (ParsedSubmessage::InfoDestination)

Tests: crates/rtps/src/datagram.rs::tests::info_dst_body_of_exactly_twelve_decodes, crates/rtps/src/datagram.rs::tests::info_dst_decodes_to_typed_destination_prefix

Status: done

§9.4.5.10 InfoReply: wire form

Spec: §9.4.5.10, p. 179 — INFO_REPLY |X|X|X|X|X|X|M|E|, LocatorList unicastLocatorList, LocatorList multicastLocatorList [M].

Repo: crates/rtps/src/submessages.rs (InfoReplySubmessage)

Tests: crates/rtps/src/submessages.rs::tests::info_reply_unicast_only_roundtrip_le, crates/rtps/src/submessages.rs::tests::info_reply_with_multicast_roundtrip_be

Status: done

§9.4.5.10 InfoReply MulticastFlag (0x02)

Spec: §9.4.5.10, p. 180 — “M = SubmessageHeader.flags & 0x02”.

Repo: crates/rtps/src/submessages.rs (INFO_REPLY_FLAG_MULTICAST = 0x02)

Tests: crates/rtps/src/submessages.rs::tests::info_reply_with_multicast_roundtrip_le, crates/rtps/src/datagram.rs::tests::decode_info_reply_with_multicast_via_datagram

Status: done

§9.4.5.11 InfoSource: wire form

Spec: §9.4.5.11, p. 180 — INFO_SRC |X|X|X|X|X|X|X|E|, long unused, ProtocolVersion version, VendorId vendorId, GuidPrefix guidPrefix.

Repo: crates/rtps/src/submessages.rs (InfoSourceSubmessage)

Tests: crates/rtps/src/submessages.rs::tests::info_source_wire_size_is_20, crates/rtps/src/submessages.rs::tests::info_source_unused_field_roundtrips

Status: done

§9.4.5.12 InfoTimestamp: wire form

Spec: §9.4.5.12, p. 180 — INFO_TS |X|X|X|X|X|X|I|E|, Timestamp timestamp [only if I==0].

Repo: crates/rtps/src/submessages.rs (InfoTimestampSubmessage)

Tests: crates/rtps/src/submessages.rs::tests::info_timestamp_roundtrip_le, crates/rtps/src/submessages.rs::tests::info_timestamp_decode_with_invalidate_ignores_body

Status: done

§9.4.5.12 InfoTimestamp InvalidateFlag (0x02)

Spec: §9.4.5.12, p. 180 — “I = SubmessageHeader.flags & 0x02”.

Repo: crates/rtps/src/submessages.rs (INFO_TIMESTAMP_FLAG_INVALIDATE = 0x02)

Tests: crates/rtps/src/submessages.rs::tests::info_timestamp_invalidate_flag_yields_empty_body, crates/rtps/src/datagram.rs::tests::receiver_walk_info_timestamp_invalidate_clears_have_timestamp

Status: done

§9.4.5.13 Pad: wire form

Spec: §9.4.5.13, pp. 180–181 — PAD |X|X|X|X|X|X|X|E| octetsToNextHeader.

Repo: crates/rtps/src/datagram.rs (decode_datagram: PAD is skipped)

Tests: crates/rtps/src/datagram.rs::tests::pad_submessage_is_skipped_and_re_encoded_byte_for_byte

Status: done

§9.4.5.14 NackFrag: wire form

Spec: §9.4.5.14, p. 181 — NACK_FRAG |X|X|X|X|X|X|X|E|, readerId, writerId, writerSN, FragmentNumberSet fragmentNumberState, count.

Repo: crates/rtps/src/submessages.rs (NackFragSubmessage)

Tests: crates/rtps/src/submessages.rs::tests::nack_frag_roundtrip_le, crates/rtps/src/datagram.rs::tests::decode_nack_frag_roundtrip

Status: done

§9.4.5.15 InfoReplyIp4: wire form

Spec: §9.4.5.15, p. 181 — INFO_REPLY_IP4 |X|X|X|X|X|X|M|E|, LocatorUDPv4 unicastLocator, LocatorUDPv4 multicastLocator [M]. “Its use and interpretation are identical to those of an InfoReply Submessage containing a single unicast and possibly a single multicast locator”.

Repo: crates/rtps/src/submessages.rs (InfoReplyIp4Submessage)

Tests: crates/rtps/src/submessages.rs::tests::locator_udpv4_is_two_unsigned_longs_in_the_byte_order_of_the_submessage, crates/rtps/src/submessages.rs::tests::info_reply_ip4_unicast_only_roundtrip_le, crates/rtps/src/datagram.rs::tests::receiver_walk_info_reply_ip4_sets_reply_locators

Status: done — structure (unicast LocatorUDPv4, with the M flag a multicast LocatorUDPv4), flags (E, M) and effect are right; the address follows LocatorUDPv4 (item under §9.4.3.1).

§9.4.5.15 InfoReplyIp4 MulticastFlag (0x02)

Spec: §9.4.5.15, p. 182 — “M = SubmessageHeader.flags & 0x02”.

Repo: crates/rtps/src/submessages.rs (InfoReplyIp4Submessage::write_body, read_body)

Tests: crates/rtps/src/submessages.rs::tests::info_reply_ip4_with_multicast_roundtrip_be

Status: done

§9.5 One message per UDP datagram

Spec: §9.5, p. 182 — “When RTPS is used over UDP/IP, a Message is the contents (payload) of exactly one UDP/IP Datagram.”

Repo: crates/transport-udp/src/udp_transport.rs (UdpTransport)

Tests: crates/transport-udp/tests/e2e.rs::e2e_write_udp_read_single_datagram, crates/transport-udp/src/udp_transport.rs::tests::without_the_cache_a_largest_datagram_arrives

Status: done

§9.6.1 ParameterIds in the HeaderExtension

Spec: §9.6.1, p. 182 — “This version of the protocol does not specify any ParameterId that may appear in the HeaderExtension. … Compliant implementations encountering an unrecognized ParameterId within the HeaderExtension shall either skip and the parameter or reject the entire RTPS Message, as specified in Table 9.6.”

Repo: crates/rtps/src/datagram.rs (decode_datagram: validate_must_understand_in_data_pipeline on the parameters of the HeaderExtension)

Tests: crates/rtps/tests/cyclone_he_must_understand.rs::the_decoder_refuses_a_header_extension_with_an_unknown_must_understand_pid, crates/rtps/src/header_extension.rs::tests::roundtrip_with_parameter_list, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension, crates/rtps/src/parameter_list.rs::tests::a_vendor_specific_must_understand_pid_of_another_vendor_is_an_error

Status: done — an unrecognized PID with bit 0x4000 in the HeaderExtension drops the message, a vendor-specific one included (see Table 9.6); one without the bit is skipped.

§9.6.2.1 Table 9.15 SPDP_WELL_KNOWN_MULTICAST_PORT

Spec: §9.6.2.1, p. 182, Table 9.15 — “Multicast — SPDP_WELL_KNOWN_MULTICAST_PORT — PB + DG * domainId + d0”.

Repo: crates/rtps/src/wire_types.rs (spdp_multicast_port)

Tests: crates/rtps/src/wire_types.rs::tests::all_four_ports_follow_the_spec_formula, crates/rtps/src/wire_types.rs::tests::spdp_multicast_port_domain_0_is_7400

Status: done

§9.6.2.1 Table 9.15 SPDP_WELL_KNOWN_UNICAST_PORT

Spec: §9.6.2.1, p. 182, Table 9.15 — “Unicast — SPDP_WELL_KNOWN_UNICAST_PORT — PB + DG * domainId + d1 + PG * participantId”.

Repo: crates/rtps/src/wire_types.rs (spdp_unicast_port)

Tests: crates/rtps/src/wire_types.rs::tests::domain_zero_ports_match_the_worked_spec_example, crates/dcps/src/runtime.rs::tests::spdp_unicast_port_follows_rtps_formula

Status: done

§9.6.2.1 A unique participantId per node and domain

Spec: §9.6.2.1, p. 182 — “Each Participant on the same node and in the same domain must use a unique participantId.” “participantId values ideally start at 0 and are incremented for each additional Participant on the same node and in the same domain.”

Repo: crates/dcps/src/runtime.rs (DcpsRuntime::start: participantId 0 to 119, the first free SPDP unicast port; otherwise a free port)

Tests: crates/dcps/src/runtime.rs::tests::two_runtimes_discover_each_other_via_spdp, crates/dcps/src/runtime.rs::tests::expand_initial_peer_ip_only_yields_well_known_port_range

Status: done — if none of the 120 ports is free, ZeroDDS binds any port and is reachable only through multicast.

§9.6.2.1 SEDP on the ports of SPDP

Spec: §9.6.2.1, p. 182 — “The default ports used by the SEDP built-in Endpoints match those used by the SPDP. If a node chooses not to use the default ports for the SEDP, it can include the new port numbers as part of the information exchanged during the SPDP.”

Repo: crates/dcps/src/runtime.rs (metatraffic locators = the SPDP unicast socket and the SPDP multicast group)

Tests: crates/dcps/src/runtime.rs::tests::two_runtimes_discover_each_other_via_spdp

Status: done

§9.6.2.2 Table 9.16 user traffic: multicast port

Spec: §9.6.2.2, p. 183, Table 9.16 — “Multicast — PB + DG * domainId + d2”. “User-defined Endpoints may choose to not use the default ports.”

Repo: crates/rtps/src/wire_types.rs (user_traffic_multicast_port); crates/dcps/src/runtime.rs (transport.user_multicast)

Tests: crates/rtps/src/wire_types.rs::tests::all_four_ports_follow_the_spec_formula, crates/dcps/src/runtime.rs::tests::the_user_multicast_port_is_d2_and_announced_unless_turned_off

Status: done — ZeroDDS endpoints announce the multicast locator on PB + DG * domainId + d2 (default; transport.user_multicast: false for a host without multicast). Expected: Cyclone DDS (announces 239.255.0.1 on d2), Fast DDS and OpenDDS accept an announced multicast locator or ignore it; ZeroDDS writers themselves send to unicast locators only.

§9.6.2.2 Table 9.16 user traffic: unicast port

Spec: §9.6.2.2, p. 183, Table 9.16 — “Unicast — PB + DG * domainId + d3 + PG * participantId”. “In that case, remote Endpoints obtain the port number as part of the information exchanged during the Simple Endpoint Discovery Protocol.”

Repo: crates/rtps/src/wire_types.rs (user_traffic_unicast_port); crates/dcps/src/runtime.rs (user socket on a freely chosen port, announced as the default unicast locator)

Tests: crates/rtps/src/wire_types.rs::tests::the_four_ports_of_one_participant_are_distinct, crates/dcps/src/runtime.rs::tests::announce_locators_automatic_is_non_empty_and_includes_probe

Status: done — ZeroDDS does not use the default port but announces the port bound, as the subclause permits.

§9.6.2.3 Default values PB, DG, PG, d0–d3

Spec: §9.6.2.3, p. 183 — “PB = 7400 DG = 250 PG = 2 d0 = 0 d1 = 10 d2 = 1 d3 = 11”.

Repo: crates/rtps/src/wire_types.rs (SPDP_PORT_BASE, SPDP_DOMAIN_GAIN, SPDP_PARTICIPANT_GAIN and the offsets)

Tests: crates/rtps/src/wire_types.rs::tests::port_formula_constants_match_spec

Status: done

§9.6.2.3 Parameters customisable by the user

Spec: §9.6.2.3, p. 183 — “Implementations must expose these parameters so they can be customized by the user.”

Repo: crates/rtps/src/wire_types.rs (PortMapping); crates/dcps/src/runtime.rs (RuntimeConfig::port_mapping, select_user_transport, user_port_fallbacks, transport.user_multicast); man/man5/zerodds.yaml.5

Tests: crates/rtps/src/wire_types.rs::tests::the_port_mapping_formulas_use_the_given_parameters, crates/dcps/tests/runtime_config_layering.rs::the_port_mapping_parameters_are_settings, crates/dcps/src/runtime.rs::tests::the_spdp_unicast_port_follows_the_configured_port_mapping, crates/dcps/src/runtime.rs::tests::the_user_unicast_socket_takes_the_d3_port_of_its_participant_id, crates/dcps/src/runtime.rs::tests::a_taken_user_port_is_counted_and_the_socket_takes_an_ephemeral_one, crates/dcps/src/runtime.rs::tests::the_user_multicast_port_is_d2_and_announced_unless_turned_off

Status: done — PB, DG, PG and d0 to d3 are settings (file and environment, 0..=65535, default the spec’s values). The runtime binds the discovery ports (d0, d1) and the user unicast socket to PB + DG * domainId + d3 + PG * participantId, with the participantId of the SPDP unicast socket; if the port is taken the socket takes an ephemeral port, which is counted (user_port_fallbacks) and logged as the event transport.user_unicast.port_taken. The user multicast port d2 is bound with transport.user_multicast (join of the SPDP group, reception, announcement as the default multicast locator); default on (the default locators of §9.6.2.3 include d2), false for a host without multicast. A peer otherwise reaches it at its unicast locators. Measured in tools/wire-capture/rtps-sessions (locators of the SPDP announcements): Fast DDS 2.6.10 and RTI 7.7.0 bind d1/d3 + PG * participantId (Fast DDS 23160/23161, 23162/23163; RTI 22910/22911, 22912/22913); Cyclone 11.0.1 takes ephemeral ports for metatraffic and user data (the same port) and announces default multicast 239.255.0.1 on d2; OpenDDS 3.34.0 takes an ephemeral metatraffic port and announces 127.0.0.1:12345 as user locator (no d3 port). Not measured: a run against the vendors with the port change, and the behaviour of ZeroDDS writers towards announced multicast locators (they send to unicast locators only).

§9.6.2.4 Default multicast address 239.255.0.1

Spec: §9.6.2.4, p. 183 — “DefaultMulticastLocator = {LOCATOR_KIND_UDPv4, “239.255.0.1”, PB + DG * domainId + d0}. All Participants must announce and listen on this multicast address.”

Repo: crates/rtps/src/wire_types.rs (SPDP_DEFAULT_MULTICAST_ADDRESS); crates/dcps/src/runtime.rs (spdp_multicast_group, joining and announcing)

Tests: crates/rtps/src/wire_types.rs::tests::spdp_default_multicast_is_239_255_0_1, crates/discovery/tests/spdp_loopback_e2e.rs::loopback_multicast_self_discovery

Status: done — the group is configurable; without multicast ZeroDDS works with initial peers.

§9.6.2.4 Default announcement rate 30 seconds

Spec: §9.6.2.4, p. 183 — “The default rate by which SPDP periodic announcements are sent equals 30 seconds. SPDPbuiltinParticipantWriter. resendPeriod = {30, 0};”

Repo: crates/dcps/src/runtime.rs (DEFAULT_SPDP_PERIOD, default_spdp_period_for); man/man5/zerodds.yaml.5; packaging/linux/configs/zerodds.yaml.example

Tests: crates/dcps/src/runtime.rs::tests::a_short_lease_without_a_period_beacons_three_times_a_lease, crates/dcps/tests/runtime_config_layering.rs::the_protocol_timing_parameters_are_settings

Status: done — DEFAULT_SPDP_PERIOD = 30 s (YAML default, man page, example configuration); the former 5 s stay reachable through discovery.spdp_period_ms: 5000. A lease under 90 s shortens the default to a third (§8.5.3.1).

§9.6.3.1 ParticipantMessageData: structure and wire form

Spec: §9.6.3.1, p. 184 — “struct ParticipantMessageData { GuidPrefix_t participantGuidPrefix; OctetArray4 kind; OctetSeq data; };” wire form: GuidPrefix_t participantGuidPrefix (12 octets), octet[4] kind, unsigned long data.length, octet[] data.value.

Repo: crates/rtps/src/participant_message_data.rs (ParticipantMessageData, to_cdr, from_cdr)

Tests: crates/rtps/src/participant_message_data.rs::tests::participant_message_data_octets_are_those_of_9_6_3_1, crates/rtps/src/participant_message_data.rs::tests::participant_message_data_reads_the_fast_dds_beat, crates/rtps/src/participant_message_data.rs::tests::participant_message_data_roundtrip_with_topic_token

Status: done

§9.6.3.1 ParticipantMessageData: values of kind

Spec: §9.6.3.1, p. 184 — “#define PARTICIPANT_MESSAGE_DATA_KIND_UNKNOWN {0x00, 0x00, 0x00, 0x00} #define PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE {0x00, 0x00, 0x00, 0x01} #define PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE {0x00, 0x00, 0x00, 0x02}”; “kind.value[0] & 0x80 == 1 // vendor specific kind”.

Repo: crates/rtps/src/participant_message_data.rs (PARTICIPANT_MESSAGE_DATA_KIND_*, ParticipantMessageData::is_vendor_kind)

Tests: crates/rtps/src/participant_message_data.rs::tests::participant_message_data_kind_constants_match_spec, crates/rtps/src/participant_message_data.rs::tests::participant_message_data_octets_are_those_of_9_6_3_1, crates/rtps/src/participant_message_data.rs::tests::participant_message_data_reads_the_fast_dds_beat

Status: done

§9.6.3.1 ParticipantMessageData: data at least 128 octets

Spec: §9.6.3.1, p. 184 — “Implementations can decide the upper length of the data field but must be able to support at least 128 bytes.”

Repo: crates/rtps/src/participant_message_data.rs (MAX_DATA_LEN = 4096)

Tests: crates/rtps/src/participant_message_data.rs::tests::participant_message_data_rejects_overlong_data, crates/rtps/src/participant_message_data.rs::tests::participant_message_data_encoder_caps_data_length

Status: done

§9.6.3.2 IDL of the SPDP and SEDP data types

Spec: §9.6.3.2, pp. 184–185 — “struct SPDPdiscoveredParticipantData { … ParticipantProxy participantProxy; Duration_t leaseDuration; }; struct DiscoveredWriterData { … WriterProxy mWriterProxy; }; struct DiscoveredReaderData { … ReaderProxy mReaderProxy; ContentFilterProperty_t contentFilter; }; struct DiscoveredTopicData { DDS::TopicBuiltinTopicData ddsTopicData; };”

Repo: crates/rtps/src/participant_data.rs, crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs, crates/rtps/src/topic_data.rs

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies, crates/rtps/tests/sedp_qos_roundtrip.rs::subscription_data_roundtrip_preserves_reader_qos_policies

Status: done — the missing attributes are listed under §8.5.3.2 and §8.5.4.4.

§9.6.3.2 Discovery data as a ParameterList in CDR

Spec: §9.6.3.2, p. 185 — “the wire-representation of the SerializedData within the Data Submessage uses the format of a ParameterList SubmessageElement. … Within each parameter, the parameter value is represented using CDR.”

Repo: crates/rtps/src/participant_data.rs (to_pl_cdr_le, to_pl_cdr_be, from_pl_cdr_le); crates/rtps/src/publication_data.rs (to_pl_cdr_le)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_first_4_bytes_are_pl_cdr_le_encapsulation, crates/discovery/tests/vendor_discovery_frames.rs::opendds_announcements_read_and_write_back

Status: done

§9.6.3.2 A vendor-specific EDP through a parameterId of its own

Spec: §9.6.3.2, p. 185 — “As this is a vendor-specific parameterId, other vendors’ implementations would simply ignore the parameter and the information it contains.”

Repo: crates/rtps/src/publication_data.rs (vendor parameters by vendorId)

Tests: crates/rtps/src/publication_data.rs::tests::a_foreign_vendors_0x8002_is_not_read_as_a_type_identifier

Status: done

§9.6.3.2 No redundant parameters

Spec: §9.6.3.2, p. 185 — “For optimization, implementations of the protocol shall not include a parameter in the Data submessage if it contains information that is redundant with other parameters already present in that same Data submessage.”

Repo: crates/rtps/src/participant_data.rs, crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full, crates/rtps/src/publication_data.rs::tests::roundtrip_le

Status: done — the individual cases are under Table 9.17.

§9.6.3.2 Table 9.17 SPDPdiscoveredParticipantData: ParticipantProxy::guidPrefix

Spec: §9.6.3.2, p. 185, Table 9.17 — “SPDPdiscoveredParticipantData — ParticipantProxy::guidPrefix — ParticipantBuiltinTopicData::key”.

Repo: crates/rtps/src/participant_data.rs (to_pl_cdr_le: only PID_PARTICIPANT_GUID)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_decode_requires_guid_pid

Status: done

§9.6.3.2 Table 9.17 DiscoveredReaderData: ReaderProxy::remoteReaderGuid

Spec: §9.6.3.2, p. 185, Table 9.17 — “DiscoveredReaderData — ReaderProxy::remoteReaderGuid — SubscriptionBuiltinTopicData::key”.

Repo: crates/rtps/src/subscription_data.rs (to_pl_cdr_le: only PID_ENDPOINT_GUID)

Tests: crates/rtps/src/subscription_data.rs::tests::roundtrip_le

Status: done

§9.6.3.2 Table 9.17 DiscoveredWriterData: WriterProxy::remoteWriterGuid

Spec: §9.6.3.2, p. 185, Table 9.17 — “DiscoveredWriterData — WriterProxy::remoteWriterGuid — PublicationBuiltinTopicData::key”.

Repo: crates/rtps/src/publication_data.rs (to_pl_cdr_le: only PID_ENDPOINT_GUID)

Tests: crates/rtps/src/publication_data.rs::tests::decode_rejects_missing_endpoint_guid

Status: done

§9.6.3.2 Key-only DATA of the built-in topics

Spec: §9.6.3.2, p. 185 — “In the case of a DATA submessage containing the SPDPdiscoveredParticipantData with KeyFlag=1, the only parameterId present within the ParameterList shall be the PID_PARTICIPANT_GUID. In the case of a DATA submessage containing one of SEDPdiscoveredPublicationData, SEDPdiscoveredSubscriptionData, or SEDPdiscoveredTopicData with KeyFlag=1, the only parameterId present within the ParameterList shall be the PID_ENDPOINT_GUID.”

Repo: crates/rtps/src/parameter_list.rs (spdp_participant_key_pl_cdr_le, sedp_endpoint_key_pl_cdr_le); crates/discovery/src/spdp.rs (serialize_departure)

Tests: crates/discovery/src/spdp.rs::tests::a_departure_reads_back_as_departed_with_key_and_status, crates/rtps/src/parameter_list.rs::tests::sedp_endpoint_key_matches_the_measured_cyclone_octets

Status: done

§9.6.3.2 Table 9.18/9.19 PID_PAD

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_PAD — 0x0000 — N/A”; Table 9.19, p. 187 — “PID_PAD — - — N/A”.

Repo: crates/rtps/src/parameter_list.rs (pid::PAD, ParameterList::from_bytes_with_consumed)

Tests: crates/rtps/src/parameter_list.rs::tests::pid_pad_is_skipped

Status: done

§9.6.3.2 Table 9.18/9.19 PID_SENTINEL

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_SENTINEL — 0x0001 — N/A”.

Repo: crates/qos/src/pid.rs (Pid::SENTINEL); crates/rtps/src/parameter_list.rs

Tests: crates/rtps/src/parameter_list.rs::tests::empty_parameter_list_is_just_sentinel

Status: done

§9.6.3.2 Table 9.18/9.19 PID_USER_DATA

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_USER_DATA — 0x002c — UserDataQosPolicy”; Table 9.19, p. 187 — ParticipantBuiltinTopicData, PublicationBuiltinTopicData, SubscriptionBuiltinTopicData user_data, default “See DDS Specification”.

Repo: crates/qos/src/pid.rs (Pid::USER_DATA); crates/rtps/src/participant_data.rs, crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs (user_data)

Tests: crates/rtps/tests/user_data_propagation.rs::participant_user_data_roundtrip, crates/rtps/tests/user_data_propagation.rs::subscription_user_data_roundtrip, crates/rtps/tests/user_data_propagation.rs::publication_empty_user_data_omits_pid

Status: done

§9.6.3.2 Table 9.18/9.19 PID_TOPIC_NAME

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_TOPIC_NAME — 0x0005 — string<256>”; Table 9.19, p. 187 — TopicBuiltinTopicData::name, Publication/Subscription topic_name, default N/A.

Repo: crates/rtps/src/parameter_list.rs (pid::TOPIC_NAME); crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs, crates/rtps/src/topic_data.rs

Tests: crates/rtps/src/publication_data.rs::tests::roundtrip_utf8_topic_name, crates/rtps/src/publication_data.rs::tests::decode_rejects_missing_topic_name, crates/rtps/src/publication_data.rs::tests::topic_and_type_names_are_bounded_by_string_256

Status: done

§9.6.3.2 Table 9.18/9.19 PID_TYPE_NAME

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_TYPE_NAME — 0x0007 — string<256>”; Table 9.19, p. 187 — TopicBuiltinTopicData, Publication/Subscription type_name, default N/A.

Repo: crates/rtps/src/parameter_list.rs (pid::TYPE_NAME); crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs, crates/rtps/src/topic_data.rs

Tests: crates/rtps/src/publication_data.rs::tests::decode_rejects_missing_type_name, crates/rtps/src/publication_data.rs::tests::roundtrip_le, crates/rtps/src/publication_data.rs::tests::topic_and_type_names_are_bounded_by_string_256

Status: done

§9.6.3.2 string<256> for names and domainTag

Spec: §9.6.3.2, p. 186, Table 9.18 — PID_TOPIC_NAME, PID_TYPE_NAME, PID_DOMAIN_TAG: “string<256>”.

Repo: crates/rtps/src/publication_data.rs (STRING_256_MAX, encode_bounded_cdr_string_le, decode_bounded_cdr_string); crates/dcps/src/participant.rs; crates/dcps/src/runtime.rs (start)

Tests: crates/rtps/src/publication_data.rs::tests::topic_and_type_names_are_bounded_by_string_256, crates/rtps/src/participant_data.rs::tests::a_domain_tag_longer_than_string_256_is_refused, crates/dcps/src/participant.rs::tests::create_topic_rejects_a_name_longer_than_string_256

Status: done — topic, type and domain-tag names are bounded to 256 octets: encoding and decoding refuse more (an announcement of a peer with a longer name is refused and counted), create_topic and DcpsRuntime::start refuse them.

§9.6.3.2 Table 9.18/9.19 PID_GROUP_DATA

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_GROUP_DATA — 0x002d — GroupDataQosPolicy”; Table 9.19, p. 187 — Publication/Subscription group_data.

Repo: crates/qos/src/pid.rs (Pid::GROUP_DATA); crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs

Tests: crates/rtps/src/publication_data.rs::tests::user_topic_and_group_data_survive_the_sedp_roundtrip, crates/rtps/tests/sedp_qos_roundtrip.rs::topic_data_and_group_data_survive_the_builtin_topic_untouched

Status: done

§9.6.3.2 Table 9.18/9.19 PID_TOPIC_DATA

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_TOPIC_DATA — 0x002e — TopicDataQosPolicy”; Table 9.19, p. 187 — TopicBuiltinTopicData, Publication/Subscription topic_data.

Repo: crates/qos/src/pid.rs (Pid::TOPIC_DATA); crates/rtps/src/topic_data.rs, crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs

Tests: crates/rtps/src/publication_data.rs::tests::user_topic_and_group_data_survive_the_sedp_roundtrip, crates/rtps/tests/sedp_qos_roundtrip.rs::topic_data_and_group_data_survive_the_builtin_topic_untouched

Status: done

§9.6.3.2 Table 9.18/9.19 PID_DURABILITY

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_DURABILITY — 0x001d — DurabilityQosPolicy”; Table 9.19, p. 187 — Topic, Publication, Subscription durability.

Repo: crates/qos/src/pid.rs (Pid::DURABILITY); crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs, crates/rtps/src/topic_data.rs

Tests: crates/rtps/src/publication_data.rs::tests::durability_try_from_u32_rejects_unknown, crates/rtps/tests/sedp_qos_roundtrip.rs::defaults_roundtrip_stays_default

Status: done

§9.6.3.2 Table 9.18/9.19 PID_DURABILITY_SERVICE

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_DURABILITY_SERVICE — 0x001e — DurabilityServiceQosPolicy”; Table 9.19, p. 187 — Topic, Publication durability_service.

Repo: crates/qos/src/pid.rs (Pid::DURABILITY_SERVICE); crates/rtps/src/publication_data.rs, crates/rtps/src/topic_data.rs

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies, crates/qos/src/policies/durability_service.rs::tests::default_matches_spec

Status: done

§9.6.3.2 Table 9.18/9.19 PID_DEADLINE

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_DEADLINE — 0x0023 — DeadlineQosPolicy”; Table 9.19, p. 188 — Topic, Publication, Subscription deadline.

Repo: crates/qos/src/pid.rs (Pid::DEADLINE)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies, crates/rtps/tests/sedp_qos_roundtrip.rs::subscription_data_roundtrip_preserves_reader_qos_policies

Status: done

§9.6.3.2 Table 9.18/9.19 PID_LATENCY_BUDGET

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_LATENCY_BUDGET — 0x0027 — LatencyBudgetQosPolicy”; Table 9.19, p. 188 — Topic, Publication, Subscription latency_budget.

Repo: crates/qos/src/pid.rs (Pid::LATENCY_BUDGET)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies, crates/rtps/tests/sedp_qos_roundtrip.rs::subscription_data_roundtrip_preserves_reader_qos_policies

Status: done

§9.6.3.2 Table 9.18/9.19 PID_LIVELINESS

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_LIVELINESS — 0x001b — LivelinessQosPolicy”; Table 9.19, p. 188 — Topic, Publication, Subscription liveliness.

Repo: crates/qos/src/pid.rs (Pid::LIVELINESS)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies, crates/discovery/tests/vendor_discovery_frames.rs::cyclone_announcements_read_and_write_back

Status: done

§9.6.3.2 Table 9.18/9.19 PID_RELIABILITY

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_RELIABILITY — 0x001a — ReliabilityQosPolicy” with footnote 3: “The encoding of DDS::ReliabilityQoSPolicy::kind is defined by RTPS::ReliabilityKind_t (9.3.2)”; Table 9.19, p. 188 — Topic, Publication, Subscription reliability.

Repo: crates/qos/src/pid.rs (Pid::RELIABILITY); crates/rtps/src/publication_data.rs (kind as 1/2)

Tests: crates/rtps/src/publication_data.rs::tests::an_absent_reliability_parameter_reads_as_reliable_on_a_publication, crates/rtps/src/publication_data.rs::tests::reliability_try_from_u32_rejects_unknown

Status: done

§9.6.3.2 Table 9.18/9.19 PID_LIFESPAN

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_LIFESPAN — 0x002b — LifespanQosPolicy”; Table 9.19, p. 188 — Topic, Publication lifespan.

Repo: crates/qos/src/pid.rs (Pid::LIFESPAN)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies

Status: done

§9.6.3.2 Table 9.18/9.19 PID_DESTINATION_ORDER

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_DESTINATION_ORDER — 0x0025 — DestinationOrderQosPolicy”; Table 9.19, p. 188 — Topic, Publication, Subscription destination_order.

Repo: crates/qos/src/pid.rs (Pid::DESTINATION_ORDER)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies, crates/qos/src/policies/destination_order.rs::tests::roundtrip

Status: done

§9.6.3.2 Table 9.18/9.19 PID_HISTORY

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_HISTORY — 0x0040 — HistoryQosPolicy”; Table 9.19, p. 188 — TopicBuiltinTopicData::history.

Repo: crates/qos/src/pid.rs (Pid::HISTORY); crates/rtps/src/topic_data.rs

Tests: crates/discovery/src/sedp/stack.rs::tests::two_stacks_exchange_a_topic_its_new_qos_and_its_dispose

Status: done

§9.6.3.2 Table 9.18/9.19 PID_RESOURCE_LIMITS

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_RESOURCE_LIMITS — 0x0041 — ResourceLimitsQosPolicy”; Table 9.19, p. 188 — TopicBuiltinTopicData::resource_limits.

Repo: crates/qos/src/pid.rs (Pid::RESOURCE_LIMITS); crates/rtps/src/topic_data.rs

Tests: crates/discovery/src/sedp/stack.rs::tests::two_stacks_exchange_a_topic_its_new_qos_and_its_dispose

Status: done

§9.6.3.2 Table 9.18/9.19 PID_OWNERSHIP

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_OWNERSHIP — 0x001f — OwnershipQosPolicy”; Table 9.19, p. 188 — Topic, Publication, Subscription ownership.

Repo: crates/qos/src/pid.rs (Pid::OWNERSHIP)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies, crates/rtps/tests/sedp_qos_roundtrip.rs::subscription_data_roundtrip_preserves_reader_qos_policies

Status: done

§9.6.3.2 Table 9.18/9.19 PID_OWNERSHIP_STRENGTH

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_OWNERSHIP_STRENGTH — 0x0006 — OwnershipStrengthQosPolicy”; Table 9.19, p. 188 — PublicationBuiltinTopicData::ownership_strength.

Repo: crates/qos/src/pid.rs (Pid::OWNERSHIP_STRENGTH)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies

Status: done

§9.6.3.2 Table 9.18/9.19 PID_PRESENTATION

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_PRESENTATION — 0x0021 — PresentationQosPolicy”; Table 9.19, p. 188 — Publication, Subscription presentation.

Repo: crates/qos/src/pid.rs (Pid::PRESENTATION)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies, crates/rtps/tests/sedp_qos_roundtrip.rs::subscription_data_roundtrip_preserves_reader_qos_policies

Status: done

§9.6.3.2 Table 9.18/9.19 PID_PARTITION

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_PARTITION — 0x0029 — PartitionQosPolicy”; Table 9.19, p. 188 — Publication, Subscription partition.

Repo: crates/qos/src/pid.rs (Pid::PARTITION)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies, crates/dcps/src/runtime.rs::tests::a_partition_change_unmatches_without_a_status_and_is_announced

Status: done

§9.6.3.2 Table 9.18/9.19 PID_TIME_BASED_FILTER

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_TIME_BASED_FILTER — 0x0004 — TimeBasedFilterQosPolicy”; Table 9.19, p. 188 — SubscriptionBuiltinTopicData::time_based_filter.

Repo: crates/qos/src/pid.rs (Pid::TIME_BASED_FILTER); crates/rtps/src/subscription_data.rs

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::subscription_data_roundtrip_preserves_reader_qos_policies

Status: done

§9.6.3.2 Table 9.18 PID_TRANSPORT_PRIORITY

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_TRANSPORT_PRIORITY — 0x0049 — TransportPriorityQoSPolicy”. Table 9.19 has no row for it.

Repo: crates/qos/src/pid.rs (Pid::TRANSPORT_PRIORITY); crates/rtps/src/topic_data.rs; crates/rtps/src/publication_data.rs (inline QoS)

Tests: crates/rtps/src/publication_data.rs::tests::a_transport_priority_goes_in_line_and_not_into_the_announcement

Status: done

§9.6.3.2 Table 9.18/9.19 PID_DOMAIN_ID

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID__DOMAIN_ID — 0x000f — DomainId_t”; Table 9.19, p. 188 — ParticipantProxy::domainId, default “The domainId of the local participant receiving the SPDPdiscoveredParticipantData”.

Repo: crates/rtps/src/parameter_list.rs (pid::DOMAIN_ID); crates/dcps/src/runtime.rs (spdp_announced: missing = own domain)

Tests: crates/dcps/src/runtime.rs::tests::a_participant_of_another_domain_id_is_not_discovered, crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§9.6.3.2 Table 9.18/9.19 PID_DOMAIN_TAG

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_DOMAIN_TAG — 0x4014 — string<256>”; Table 9.19, p. 188 — ParticipantProxy::domainTag, default ““” (empty, zero-length string)”.

Repo: crates/rtps/src/parameter_list.rs (pid::DOMAIN_TAG); crates/rtps/src/participant_data.rs (missing = empty)

Tests: crates/rtps/src/participant_data.rs::tests::domain_tag_goes_out_when_set_and_reads_back, crates/rtps/src/participant_data.rs::tests::domain_tag_is_a_standard_must_understand_pid, crates/rtps/src/participant_data.rs::tests::a_domain_tag_longer_than_string_256_is_refused

Status: done

§9.6.3.2 Table 9.18/9.19 PID_PROTOCOL_VERSION

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_PROTOCOL_VERSION — 0x0015 — ProtocolVersion_t”; Table 9.19, p. 188 — ParticipantProxy::protocolVersion.

Repo: crates/rtps/src/parameter_list.rs (pid::PROTOCOL_VERSION); crates/rtps/src/participant_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§9.6.3.2 Table 9.18/9.19 PID_VENDORID

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_VENDORID — 0x0016 — VendorId_t”; Table 9.19, p. 188 — ParticipantProxy::vendorId.

Repo: crates/rtps/src/parameter_list.rs (pid::VENDOR_ID); crates/rtps/src/participant_data.rs, crates/rtps/src/publication_data.rs

Tests: crates/rtps/src/publication_data.rs::tests::a_foreign_vendor_id_survives_read_and_write_back, crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§9.6.3.2 Table 9.18/9.19 PID_UNICAST_LOCATOR

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_UNICAST_LOCATOR — 0x002f — Locator_t”; Table 9.19, p. 188 — ReaderProxy/WriterProxy::unicastLocatorList.

Repo: crates/rtps/src/parameter_list.rs (pid::UNICAST_LOCATOR); crates/rtps/src/publication_data.rs (collect_locator_params)

Tests: crates/rtps/src/publication_data.rs::tests::locator_params_of_a_big_endian_list_are_read

Status: done

§9.6.3.2 Table 9.18/9.19 PID_MULTICAST_LOCATOR

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_MULTICAST_LOCATOR — 0x0030 — Locator_t”; Table 9.19, p. 188 — ReaderProxy/WriterProxy::multicastLocatorList.

Repo: crates/rtps/src/parameter_list.rs (pid::MULTICAST_LOCATOR); crates/rtps/src/publication_data.rs (collect_locator_params)

Tests: crates/rtps/src/publication_data.rs::tests::locator_params_of_a_big_endian_list_are_read

Status: done

§9.6.3.2 Endpoint locators in PL_CDR_BE

Spec: §9.6.3.2, Table 9.19, p. 188 — PID_UNICAST_LOCATOR and PID_MULTICAST_LOCATOR for ReaderProxy and WriterProxy; §9.6.3.2, p. 185: “Within each parameter, the parameter value is represented using CDR.”

Repo: —

Tests: crates/rtps/src/publication_data.rs::tests::locator_params_of_a_big_endian_list_are_read

Status: done

§9.6.3.2 Table 9.18/9.19 PID_DEFAULT_UNICAST_LOCATOR

Spec: §9.6.3.2, p. 186, Table 9.18 — “PID_DEFAULT_UNICAST_LOCATOR — 0x0031 — Locator_t”; Table 9.19, p. 188 — ParticipantProxy::defaultUnicastLocatorList.

Repo: crates/rtps/src/parameter_list.rs (pid::DEFAULT_UNICAST_LOCATOR); crates/rtps/src/participant_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::decode_retains_all_repeated_unicast_locators_in_order_le_and_be

Status: done

§9.6.3.2 Table 9.18/9.19 PID_DEFAULT_MULTICAST_LOCATOR

Spec: §9.6.3.2, p. 187, Table 9.18 — “PID_DEFAULT_MULTICAST_LOCATOR — 0x0048 — Locator_t”; Table 9.19, p. 189 — ParticipantProxy::defaultMulticastLocatorList.

Repo: crates/rtps/src/parameter_list.rs (pid::DEFAULT_MULTICAST_LOCATOR); crates/rtps/src/participant_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§9.6.3.2 Table 9.18/9.19 PID_METATRAFFIC_UNICAST_LOCATOR

Spec: §9.6.3.2, p. 187, Table 9.18 — “PID_METATRAFFIC_UNICAST_LOCATOR — 0x0032 — Locator_t”; Table 9.19, p. 189 — ParticipantProxy::metatrafficUnicastLocatorList.

Repo: crates/rtps/src/parameter_list.rs (pid::METATRAFFIC_UNICAST_LOCATOR); crates/rtps/src/participant_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::decode_retains_all_repeated_unicast_locators_in_order_le_and_be

Status: done

§9.6.3.2 Table 9.18/9.19 PID_METATRAFFIC_MULTICAST_LOCATOR

Spec: §9.6.3.2, p. 187, Table 9.18 — “PID_METATRAFFIC_MULTICAST_LOCATOR — 0x0033 — Locator_t”; Table 9.19, p. 189 — ParticipantProxy::metatrafficMulticastLocatorList.

Repo: crates/rtps/src/parameter_list.rs (pid::METATRAFFIC_MULTICAST_LOCATOR); crates/rtps/src/participant_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§9.6.3.2 Table 9.18/9.19 PID_EXPECTS_INLINE_QOS

Spec: §9.6.3.2, p. 187, Table 9.18 — “PID_EXPECTS_INLINE_QOS — 0x0043 — boolean”; Table 9.19, p. 189 — ParticipantProxy::expectsInlineQos, default FALSE.

Repo: crates/rtps/src/parameter_list.rs (pid::EXPECTS_INLINE_QOS); crates/rtps/src/participant_data.rs, crates/rtps/src/subscription_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::expects_inline_qos_goes_out_when_set_and_reads_back, crates/rtps/src/subscription_data.rs::tests::expects_inline_qos_goes_out_when_set_and_reads_back

Status: done

§9.6.3.2 Table 9.18/9.19 PID_PARTICIPANT_MANUAL_LIVELINESS_COUNT

Spec: §9.6.3.2, p. 187, Table 9.18 — “PID_PARTICIPANT_MANUAL_LIVELINESS_COUNT — 0x0034 — Count_t”; Table 9.19, p. 189 — ParticipantProxy::manualLivelinessCount.

Repo: crates/rtps/src/parameter_list.rs (pid::PARTICIPANT_MANUAL_LIVELINESS_COUNT); crates/rtps/src/participant_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::manual_liveliness_count_and_builtin_endpoint_qos_go_out_and_read_back, crates/discovery/tests/vendor_discovery_frames.rs::opendds_announcements_read_and_write_back

Status: done — read, written and in is_standard_pid; OpenDDS sends 0 and gets 0 back.

§9.6.3.2 Table 9.18/9.19 PID_PARTICIPANT_LEASE_DURATION

Spec: §9.6.3.2, p. 187, Table 9.18 — “PID_PARTICIPANT_LEASE_DURATION — 0x0002 — Duration_t”; Table 9.19, p. 189 — SPDPdiscoveredParticipantData::leaseDuration, default {100, 0}.

Repo: crates/rtps/src/parameter_list.rs (pid::PARTICIPANT_LEASE_DURATION); crates/rtps/src/participant_data.rs (missing = 100 s)

Tests: crates/rtps/src/participant_data.rs::tests::to_pl_cdr_be_is_big_endian_roundtrips_and_omits_credential_tokens

Status: done

§9.6.3.2 PID_PARTICIPANT_LEASE_DURATION in PL_CDR_BE

Spec: §9.6.3.2, p. 185 — “Within each parameter, the parameter value is represented using CDR.”; Table 9.18: Duration_t.

Repo: —

Tests: crates/rtps/src/participant_data.rs::tests::to_pl_cdr_be_is_big_endian_roundtrips_and_omits_credential_tokens

Status: done

§9.6.3.2 Table 9.18/9.19 PID_CONTENT_FILTER_PROPERTY

Spec: §9.6.3.2, p. 187, Table 9.18 — “PID_CONTENT_FILTER_PROPERTY — 0x0035 — ContentFilterProperty_t”; Table 9.19, p. 189 — DiscoveredReaderData::contentFilter.

Repo: crates/rtps/src/parameter_list.rs (pid::CONTENT_FILTER_PROPERTY); crates/rtps/src/subscription_data.rs

Tests: crates/rtps/src/subscription_data.rs::tests::subscription_with_content_filter_roundtrip_le

Status: done

§9.6.3.2 Table 9.18/9.19 PID_PARTICIPANT_GUID

Spec: §9.6.3.2, p. 187, Table 9.18 — “PID_PARTICIPANT_GUID — 0x0050 — GUID_t”; Table 9.19, p. 189 — ParticipantBuiltinTopicData::key, Publication/Subscription participant_key.

Repo: crates/rtps/src/parameter_list.rs (pid::PARTICIPANT_GUID); crates/rtps/src/participant_data.rs, crates/rtps/src/publication_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_decode_requires_guid_pid, crates/rtps/src/publication_data.rs::tests::participant_key_fallback_when_pid_missing

Status: done

§9.6.3.2 Table 9.18/9.19 PID_GROUP_GUID

Spec: §9.6.3.2, p. 187, Table 9.18 — “PID_GROUP_GUID — 0x0052 — GUID_t”; Table 9.19 — WriterProxy/ReaderProxy::remoteGroupGuid, default GUID_UNKNOWN.

Repo: —

Tests: crates/rtps/src/publication_data.rs::tests::the_writers_group_travels_as_pid_group_guid

Status: done

§9.6.3.2 Table 9.18/9.19 PID_GROUP_ENTITY_ID

Spec: §9.6.3.2, p. 187, Table 9.18 — “PID_GROUP_ENTITY_ID — 0x0053 — EntityId_t”; Table 9.19, p. 189 — WriterProxy/ReaderProxy::remoteGroupGuid.entityId, default ENTITYID_UNKNOWN.

Repo: —

Tests: crates/rtps/src/publication_data.rs::tests::the_writers_group_travels_as_pid_group_guid

Status: done — read; ZeroDDS sends the group as a full GUID in PID_GROUP_GUID.

§9.6.3.2 Table 9.18/9.19 PID_BUILTIN_ENDPOINT_SET

Spec: §9.6.3.2, p. 187, Table 9.18 — “PID_BUILTIN_ENDPOINT_SET — 0x0058 — BuiltinEndpointSet_t”; Table 9.19, p. 189 — ParticipantProxy::availableBuiltinEndpoints.

Repo: crates/rtps/src/parameter_list.rs (pid::BUILTIN_ENDPOINT_SET); crates/rtps/src/participant_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::endpoint_flag_roundtrip_through_pl_cdr

Status: done

§9.6.3.2 Table 9.18/9.19 PID_BUILTIN_ENDPOINT_QOS

Spec: §9.6.3.2, p. 187, Table 9.18 — “PID_BUILTIN_ENDPOINT_QOS — 0x0077 — BuiltinEndpointQos_t”; Table 9.19, p. 189 — ParticipantProxy::builtinEndpointQos.

Repo: crates/rtps/src/parameter_list.rs (pid::BUILTIN_ENDPOINT_QOS); crates/rtps/src/participant_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::manual_liveliness_count_and_builtin_endpoint_qos_go_out_and_read_back, crates/discovery/tests/vendor_discovery_frames.rs::opendds_announcements_read_and_write_back

Status: done — read, written and in is_standard_pid.

§9.6.3.2 Table 9.18 PID_PROPERTY_LIST

Spec: §9.6.3.2, p. 187, Table 9.18 — “PID_PROPERTY_LIST — 0x0059 — sequence”. Table 9.19 has no row for it.

Repo: crates/rtps/src/parameter_list.rs (pid::PROPERTY_LIST); crates/rtps/src/participant_data.rs (properties); crates/rtps/src/property_list.rs (WirePropertyList::decode)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_properties_roundtrip, crates/rtps/src/participant_data.rs::tests::participant_data_empty_properties_omits_pid, crates/rtps/src/property_list.rs::tests::decode_reads_the_rtps_form_without_binary_value

Status: done — sent in SPDP and, where an endpoint has properties, in SEDP, in the form of DDS-Security 1.2 §7.5.1.4 (with binary_value). Both forms are read; a list that ends after its properties (this row) has no binary entries.

§9.6.3.2 Table 9.18/9.19 PID_TYPE_MAX_SIZE_SERIALIZED

Spec: §9.6.3.2, p. 187, Table 9.18 — “PID_TYPE_MAX_SIZE_SERIALIZED — 0x0060 — long”; Table 9.19, p. 189 — “PID_DATA_MAX_SIZE_SERIALIZED — WriterProxy::dataMaxSizeSerialized”.

Repo: crates/rtps/src/publication_data.rs (data_max_size_serialized)

Tests: crates/rtps/src/publication_data.rs::tests::the_max_payload_size_and_the_name_of_a_writer_travel, crates/rtps/src/reliable_reader.rs::tests::a_payload_beyond_the_announced_maximum_is_refused_and_counted

Status: done — publications send and read the PID as a long (PublicationBuiltinTopicData::data_max_size_serialized); vendor_discovery_frames.rs no longer lists 0x0060 among the dropped PIDs. Measured in tools/wire-capture/rtps-sessions/rti: RTI 7.7.0 announces the value 8, and its writer’s DATA carries a SerializedPayload of 8 octets, the encapsulation header included; the value counts with the header, as the spec does. Fast DDS 2.6.10 announces 12, 32 and 52 (no user DATA in the capture); Cyclone and OpenDDS do not announce the PID. A reader refuses a payload that exceeds the value named. Not measured: a run against the vendors with this refusal.

§9.6.3.2 Table 9.18 PID_ENTITY_NAME

Spec: §9.6.3.2, p. 187, Table 9.18 — “PID_ENTITY_NAME — 0x0062 — EntityName_t”. Table 9.19 has no row for it.

Repo: crates/rtps/src/participant_data.rs, crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs (entity_name); crates/dcps/src/runtime.rs (built_entity_name, built_participant_name, RuntimeConfig::participant_name)

Tests: crates/rtps/src/participant_data.rs::tests::the_participant_name_goes_out_and_reads_back, crates/rtps/src/publication_data.rs::tests::the_max_payload_size_and_the_name_of_a_writer_travel

Status: done — participant, writer and reader send and read PID_ENTITY_NAME as EntityName_t (CDR string). The DCPS API has no EntityName QoS; the names are built: participant zerodds: and the GUID prefix in hex (overridable with discovery.participant_name), writer and reader DataWriter:<topic>:<entity id hex> and DataReader:…. UserWriterConfig::entity_name and UserReaderConfig::entity_name take a name that is set. A name that cannot be read (not a valid CDR string) refuses the announcement, as an unreadable domainTag does.

§9.6.3.2 Table 9.18/9.19 PID_ENDPOINT_GUID

Spec: §9.6.3.2, p. 187, Table 9.18 — “PID_ENDPOINT_GUID — 0x005a — GUID_t”; Table 9.19, p. 189 — Topic-, Subscription-, PublicationBuiltinTopicData::key.

Repo: crates/rtps/src/parameter_list.rs (pid::ENDPOINT_GUID); crates/rtps/src/publication_data.rs, crates/rtps/src/topic_data.rs

Tests: crates/rtps/src/publication_data.rs::tests::decode_rejects_missing_endpoint_guid, crates/discovery/src/sedp/stack.rs::tests::two_stacks_exchange_a_topic_its_new_qos_and_its_dispose

Status: done

§9.6.3.2 Defaults “See DDS Specification” for missing QoS PIDs

Spec: §9.6.3.2, Table 9.19, pp. 187–188 — the QoS rows name “See DDS Specification.” as the default; §9.6.3.2: “Unrecognized parameterIDs shall be treated as specified in Table 9.6.”

Repo: crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs, crates/rtps/src/topic_data.rs (unwrap_or_default per policy)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::defaults_roundtrip_stays_default, crates/rtps/src/publication_data.rs::tests::an_absent_reliability_parameter_reads_as_reliable_on_a_publication

Status: done

§9.6.4 Inline QoS ParameterIds

Spec: §9.6.4, p. 189 — “Sub clause 8.7.2.1 defines the complete set of parameters that can appear within the inlineQos SubmessageElement. The corresponding set of parameterIds is listed in Table 9.20. Unrecognized parameterIDs shall be treated as specified in Table 9.6.”

Repo: crates/rtps/src/inline_qos.rs; crates/rtps/src/parameter_list.rs

Tests: crates/rtps/src/inline_qos.rs::tests::roundtrip_in_data_submessage_inline_qos, crates/rtps/src/datagram.rs::tests::decode_accepts_data_with_known_must_understand_pid_in_inline_qos

Status: done — the treatment of unknown PIDs is listed under §9.4.2.11 Table 9.6.

§9.6.4 Table 9.20 PID_PAD

Spec: §9.6.4, p. 189, Table 9.20 — “PID_PAD — N/A”.

Repo: crates/rtps/src/parameter_list.rs (pid::PAD, ParameterList::from_bytes_with_consumed)

Tests: crates/rtps/src/parameter_list.rs::tests::pid_pad_is_skipped

Status: done

§9.6.4 Table 9.20 PID_SENTINEL

Spec: §9.6.4, p. 189, Table 9.20 — “PID_SENTINEL — N/A”.

Repo: crates/rtps/src/parameter_list.rs (pid::SENTINEL)

Tests: crates/rtps/src/parameter_list.rs::tests::empty_parameter_list_is_just_sentinel

Status: done

§9.6.4 Table 9.20 PID_TOPIC_NAME

Spec: §9.6.4, p. 189, Table 9.20 — “PID_TOPIC_NAME — See Table 9.18 — string<256>”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_DURABILITY

Spec: §9.6.4, p. 189, Table 9.20 — “PID_DURABILITY — See Table 9.18 — DurabilityQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_PRESENTATION

Spec: §9.6.4, p. 189, Table 9.20 — “PID_PRESENTATION — PresentationQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_DEADLINE

Spec: §9.6.4, p. 190, Table 9.20 — “PID_DEADLINE — DeadlineQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_LATENCY_BUDGET

Spec: §9.6.4, p. 190, Table 9.20 — “PID_LATENCY_BUDGET — LatencyBudgetQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_OWNERSHIP

Spec: §9.6.4, p. 190, Table 9.20 — “PID_OWNERSHIP — OwnershipQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_OWNERSHIP_STRENGTH

Spec: §9.6.4, p. 190, Table 9.20 — “PID_OWNERSHIP_STRENGTH — OwnershipStrengthQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_LIVELINESS

Spec: §9.6.4, p. 190, Table 9.20 — “PID_LIVELINESS — LivelinessQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_PARTITION

Spec: §9.6.4, p. 190, Table 9.20 — “PID_PARTITION — PartitionQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_RELIABILITY

Spec: §9.6.4, p. 190, Table 9.20 — “PID_RELIABILITY — ReliabilityQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_TRANSPORT_PRIORITY

Spec: §9.6.4, p. 190, Table 9.20 — “PID_TRANSPORT_PRIORITY — TransportPriorityQoSPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::a_transport_priority_goes_in_line_and_not_into_the_announcement

Status: done

§9.6.4 Table 9.20 PID_LIFESPAN

Spec: §9.6.4, p. 190, Table 9.20 — “PID_LIFESPAN — LifespanQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_DESTINATION_ORDER

Spec: §9.6.4, p. 190, Table 9.20 — “PID_DESTINATION_ORDER — DestinationOrderQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_CONTENT_FILTER_INFO (0x0055)

Spec: §9.6.4, p. 190, Table 9.20 — “PID_CONTENT_FILTER_INFO — 0x0055 — ContentFilterInfo_t”.

Repo: —

Tests: —

Status: open — ZeroDDS does not know the PID; a received parameter is skipped as an unknown PID without the must-understand bit. Part of the optional filtering on the writer side (§8.7.3), which ZeroDDS does not perform.

§9.6.4 Table 9.20 PID_COHERENT_SET (0x0056)

Spec: §9.6.4, p. 190, Table 9.20 — “PID_COHERENT_SET — 0x0056 — SequenceNumber_t”.

Repo: crates/rtps/src/parameter_list.rs (pid::COHERENT_SET); crates/rtps/src/inline_qos.rs (coherent_set_inline_qos, find_coherent_set)

Tests: crates/rtps/src/inline_qos.rs::tests::coherent_set_param_is_pid_0x0056_with_sequence_number_layout, crates/rtps/src/inline_qos.rs::tests::coherent_set_roundtrip_both_endiannesses

Status: done

§9.6.4 Table 9.20 PID_DIRECTED_WRITE (0x0057)

Spec: §9.6.4, p. 190, Table 9.20 — “PID_DIRECTED_WRITE — 0x0057 — GUID_t” with footnote 4: “RTPS protocol versions prior to 2.4 defined this as a sequence. … when interacting with protocol versions earlier than 2.4 this parameter should be ignored unless the receiver knows the format used by the vendor”.

Repo: crates/rtps/src/parameter_list.rs (pid::DIRECTED_WRITE); crates/rtps/src/inline_qos.rs (directed_write_param, find_directed_write); crates/rtps/src/datagram.rs (ignore_directed_write_before_2_4)

Tests: crates/rtps/src/inline_qos.rs::tests::table_9_20_directed_write_original_writer_info_and_secure_group_info, crates/rtps/src/inline_qos.rs::tests::directed_write_param_carries_target_guid, crates/rtps/src/inline_qos.rs::tests::find_directed_write_rejects_truncated_value, crates/rtps/src/datagram.rs::tests::pid_directed_write_of_a_peer_before_2_4_is_ignored

Status: done — 0x0057 with a GUID_t; note 4: for a protocol version before 2.4 (a sequence<GUID_t> there) the parameter is ignored. Sending and evaluating are done under §8.7.7.

§9.6.4 Table 9.20 PID_ORIGINAL_WRITER_INFO (0x0061)

Spec: §9.6.4, p. 190, Table 9.20 — “PID_ORIGINAL_WRITER_INFO — 0x0061 — OriginalWriterInfo_t”.

Repo: crates/rtps/src/parameter_list.rs (pid::ORIGINAL_WRITER_INFO); crates/rtps/src/inline_qos.rs (original_writer_info_param)

Tests: crates/rtps/src/inline_qos.rs::tests::table_9_20_directed_write_original_writer_info_and_secure_group_info, crates/rtps/src/parameter_list.rs::tests::the_group_and_name_parameter_ids_are_those_of_table_9_18, crates/rtps/src/inline_qos.rs::tests::original_writer_info_roundtrip_le

Status: done — 0x0061 with OriginalWriterInfo_t (24 octets, §9.6.4.7). Sending and evaluating are done under §8.7.9.

§9.6.4 Table 9.20 PID_GROUP_COHERENT_SET (0x0063)

Spec: §9.6.4, p. 190, Table 9.20 — “PID_GROUP_COHERENT_SET — 0x0063 — SequenceNumber_t”.

Repo: —

Tests: crates/rtps/src/reliable_writer.rs::tests::a_group_coherent_set_carries_the_parameters_of_table_9_23, crates/rtps/src/reliable_writer.rs::tests::a_participant_set_to_go_without_it_gets_no_group_coherent_set_pid, crates/rtps/src/reliable_writer.rs::tests::a_participant_set_to_coherent_sets_only_gets_no_group_information, crates/rtps/src/parameter_list.rs::tests::the_group_and_name_parameter_ids_are_those_of_table_9_18

Status: done

§9.6.4 Table 9.20 PID_GROUP_SEQ_NUM (0x0064)

Spec: §9.6.4, p. 190, Table 9.20 — “PID_GROUP_SEQ_NUM — 0x0064 — SequenceNumber_t”.

Repo: —

Tests: crates/rtps/src/inline_qos.rs::tests::group_seq_num_is_a_cdr_sequence_number_with_pid_0x0064, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_data_carries_its_group_sequence_number, crates/rtps/src/parameter_list.rs::tests::the_group_and_name_parameter_ids_are_those_of_table_9_18

Status: done

§9.6.4 Table 9.20 PID_WRITER_GROUP_INFO (0x0065)

Spec: §9.6.4, p. 190, Table 9.20 — “PID_WRITER_GROUP_INFO — 0x0065 — WriterGroupInfo_t”.

Repo: —

Tests: crates/rtps/src/inline_qos.rs::tests::writer_group_info_carries_the_four_digest_octets_with_pid_0x0065, crates/rtps/src/parameter_list.rs::tests::the_group_and_name_parameter_ids_are_those_of_table_9_18

Status: done

§9.6.4 Table 9.20 PID_SECURE_WRITER_GROUP_INFO (0x0066)

Spec: §9.6.4, p. 190, Table 9.20 — “PID_SECURE_WRITER_GROUP_INFO — 0x0066 — WriterGroupInfo_t”.

Repo: crates/rtps/src/parameter_list.rs (pid::SECURE_WRITER_GROUP_INFO); crates/rtps/src/inline_qos.rs (secure_writer_group_info_param, find_writer_group_info)

Tests: crates/rtps/src/inline_qos.rs::tests::table_9_20_directed_write_original_writer_info_and_secure_group_info, crates/rtps/src/reliable_writer.rs::tests::the_secure_writer_group_info_stands_where_the_plain_one_is_required, crates/rtps/src/parameter_list.rs::tests::the_group_and_name_parameter_ids_are_those_of_table_9_18

Status: done — 0x0066 with WriterGroupInfo_t (4 octets); a writer under DDS-Security sends it, a reader reads it in place of PID_WRITER_GROUP_INFO.

§9.6.4 Table 9.20 PID_KEY_HASH (0x0070)

Spec: §9.6.4, p. 190, Table 9.20 — “PID_KEY_HASH — 0x0070 — KeyHash_t”.

Repo: crates/rtps/src/parameter_list.rs (pid::KEY_HASH); crates/rtps/src/inline_qos.rs (find_key_hash)

Tests: crates/rtps/src/submessages.rs::tests::data_frag_key_hash_roundtrips_both_byte_orders, crates/dcps/src/runtime.rs::tests::alive_sample_without_key_hash_gets_the_types_computed_hash

Status: done

§9.6.4 Table 9.20 PID_STATUS_INFO (0x0071)

Spec: §9.6.4, p. 190, Table 9.20 — “PID_STATUS_INFO — 0x0071 — StatusInfo_t”.

Repo: crates/rtps/src/parameter_list.rs (pid::STATUS_INFO); crates/rtps/src/inline_qos.rs (status_info_param, find_status_info)

Tests: crates/dcps/tests/lifecycle_wire_decode.rs::reader_push_lifecycle_disposed_sets_instance_state, crates/dcps/tests/lifecycle_wire_e2e.rs::linux::dispose_propagates_over_wire_to_reader

Status: done

§9.6.4.1 PID_CONTENT_FILTER_INFO: wire form, bitmap, signature

Spec: §9.6.4.1, p. 191 — wire form numBitmaps, bitmaps, numSignatures, FilterSignature_t; “The content filter info in-line QoS is invalid unless numBitmaps == ([numSignatures/32] + (numSignatures%32 ? 1 : 0))”; “A filter’s signature is calculated as the 128-bit MD5 checksum of all strings in the filter’s ContentFilterProperty_t.”

Repo: —

Tests: —

Status: open — part of the optional filtering on the writer side (§8.7.3), which ZeroDDS does not perform.

§9.6.4.1 Table 9.21 filterResult

Spec: §9.6.4.1, p. 191, Table 9.21 — “0 — Sample was filtered by the corresponding filter and did not pass. 1 — Sample was filtered by the corresponding filter and passed.”

Repo: —

Tests: —

Status: open — part of the optional filtering on the writer side (§8.7.3), which ZeroDDS does not perform.

§9.6.4.2 PID_COHERENT_SET: encoding and value

Spec: §9.6.4.2, p. 191 — “The coherent set in-line QoS parameter uses the CDR encoding for SequenceNumber_t. … all Data and DataFrag Submessages that belong to the same coherent set must contain the coherent set in-line QoS parameter with value equal to the sequence number of the first sample in the set.”

Repo: —

Tests: crates/rtps/src/inline_qos.rs::tests::coherent_set_param_is_pid_0x0056_with_sequence_number_layout, crates/rtps/src/inline_qos.rs::tests::coherent_set_roundtrip_both_endiannesses, crates/rtps/src/reliable_writer.rs::tests::coherent_set_member_data_carries_pid_0x0056_with_set_first_sn_octets

Status: done

§9.6.4.2 Table 9.22 examples for the end of a coherent set

Spec: §9.6.4.2, p. 192, Table 9.22 — “Example Data Submessages to denote the end of a coherent set”.

Repo: crates/rtps/src/reliable_reader.rs (receive_data: coherent_set_end); crates/rtps/src/reliable_writer.rs (emit_coherent_set_end)

Tests: crates/rtps/src/reliable_reader.rs::tests::table_9_22_each_form_that_ends_a_coherent_set_ends_it, crates/rtps/src/reliable_reader.rs::tests::end_of_coherent_set_data_is_delivered_as_a_terminator, crates/rtps/src/reliable_writer.rs::tests::end_coherent_set_emits_ecs_data_with_d_and_k_clear

Status: done — the reader recognises all three forms of the table: Example 1 (DATA with data and PID_COHERENT_SET 7, a new set), Example 2 (no data, PID_COHERENT_SET SEQUENCENUMBER_UNKNOWN) and Example 3 (no data, no in-line QoS); the set 3 to 6 is ended and complete afterwards. The writer sends Example 3.

§9.6.4.3 PID_GROUP_COHERENT_SET

Spec: §9.6.4.3, p. 192 — “The group coherent set in-line QoS parameter uses the CDR encoding for SequenceNumber_t. … all Data submessages and the first DataFrag submessage belonging to a sample must contain the group coherent set in-line QoS parameter”.

Repo: —

Tests: crates/rtps/src/reliable_writer.rs::tests::a_group_coherent_set_carries_the_parameters_of_table_9_23, crates/rtps/src/reliable_writer.rs::tests::a_participant_set_to_go_without_it_gets_no_group_coherent_set_pid, crates/rtps/src/reliable_writer.rs::tests::a_participant_set_to_coherent_sets_only_gets_no_group_information, crates/rtps/src/parameter_list.rs::tests::the_group_and_name_parameter_ids_are_those_of_table_9_18

Status: done

§9.6.4.3 Table 9.23 example of a GROUP coherent set

Spec: §9.6.4.3, p. 192, Table 9.23 — “Example Data Submessages in a GROUP coherent set”.

Repo: crates/rtps/src/reliable_writer.rs (push_set_params); crates/rtps/src/inline_qos.rs (find_change_group_info); crates/rtps/src/reliable_reader.rs (DeliveredSample::group)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_group_coherent_set_carries_the_parameters_of_table_9_23, crates/rtps/src/reliable_reader.rs::tests::table_9_23_the_data_of_a_group_coherent_set_reach_the_consumer_with_their_group_numbers, crates/rtps/src/writer_group.rs::tests::the_numbers_of_table_9_23

Status: done — two writers of a GROUP publisher produce the values of the table (writerSN 4, 8, 5, 6, 9; GSN 11 to 14; PID_COHERENT_SET 4 and 8; PID_GROUP_COHERENT_SET 11); the reader passes on the group numbers with each sample.

§9.6.4.4 PID_GROUP_SEQ_NUM

Spec: §9.6.4.4, p. 193 — “all Data submessages and the first DataFrag submessage sent by DataWriters belonging to a Publisher with Presentation access scope GROUP must contain the group sequence number in-line QoS parameter with value equal to the group sequence number.”

Repo: —

Tests: crates/rtps/src/inline_qos.rs::tests::group_seq_num_is_a_cdr_sequence_number_with_pid_0x0064, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_data_carries_its_group_sequence_number, crates/rtps/src/parameter_list.rs::tests::the_group_and_name_parameter_ids_are_those_of_table_9_18

Status: done

§9.6.4.5 PID_WRITER_GROUP_INFO

Spec: §9.6.4.5, p. 193 — “for DataWriters belonging to a Publisher with Presentation access scope GROUP, the Data submessages and the first DataFrag submessage of each sample shall contain the publisher writer info in-line QoS parameter. The End Coherent Set Data submessage … shall also contain the publisher writer info in-line QoS parameter.”

Repo: —

Tests: crates/rtps/src/inline_qos.rs::tests::writer_group_info_carries_the_four_digest_octets_with_pid_0x0065, crates/rtps/src/parameter_list.rs::tests::the_group_and_name_parameter_ids_are_those_of_table_9_18

Status: done

§9.6.4.6 PID_SECURE_WRITER_GROUP_INFO

Spec: §9.6.4.6, p. 193 — “The secure publisher writer info in-line QoS is reserved for DDS Security. In the cases when it is used it shall be added anywhere that the PID_WRITER_GROUP_INFO in-line QoS is required.”

Repo: crates/rtps/src/parameter_list.rs (pid::SECURE_WRITER_GROUP_INFO); crates/rtps/src/reliable_writer.rs (set_secure_writer_group_info, push_set_params); crates/rtps/src/inline_qos.rs (secure_writer_group_info_param, find_writer_group_info); crates/dcps/src/runtime.rs (writer creation under security)

Tests: crates/rtps/src/reliable_writer.rs::tests::the_secure_writer_group_info_stands_where_the_plain_one_is_required, crates/rtps/src/inline_qos.rs::tests::table_9_20_directed_write_original_writer_info_and_secure_group_info

Status: done — under DDS-Security (RuntimeConfig::security) writers of a GROUP publisher send PID_SECURE_WRITER_GROUP_INFO wherever PID_WRITER_GROUP_INFO would stand; a reader takes both. The test with a security runtime is not in this run (only the writer setting is tested).

§9.6.4.7 PID_ORIGINAL_WRITER_INFO: wire form

Spec: §9.6.4.7, p. 193 — wire form GUID_t originalWriterGUID, SequenceNumber originalWriterSN. “The original writer info parameter may appear in the Data or in the DataFrag submessages.”

Repo: crates/rtps/src/inline_qos.rs (original_writer_info_param, find_original_writer_info)

Tests: crates/rtps/src/inline_qos.rs::tests::original_writer_info_param_24_byte_layout_le, crates/rtps/src/inline_qos.rs::tests::original_writer_info_roundtrip_be, crates/rtps/src/inline_qos.rs::tests::table_9_20_directed_write_original_writer_info_and_secure_group_info

Status: done — the wire form is right (GUID_t, SequenceNumber_t); the parameter is sent and evaluated in DATA and DATA_FRAG (items under §8.7.9).

§9.6.4.8 KeyHash: 16 octets

Spec: §9.6.4.8, p. 193 — “The KeyHash_t is defined as a 16-Byte octet array (see 9.3.2) therefore the key hash inline parameter just copies those 16 Bytes.”

Repo: crates/dcps/src/key_hash.rs (KEY_HASH_LEN); crates/rtps/src/inline_qos.rs (find_key_hash)

Tests: crates/dcps/src/key_hash.rs::tests::a_holder_of_exactly_sixteen_is_the_hash, crates/rtps/src/submessages.rs::tests::data_frag_key_hash_roundtrips_both_byte_orders

Status: done

§9.6.4.8 KeyHash step 1: FooKeyHolder

Spec: §9.6.4.8, pp. 193–194 — “FooKeyHolder shall have extensibility kind ‘FINAL’ … If there are any key members, then remove the non-key members … Reorder the members in ascending order of their memberId values.”

Repo: crates/dcps/src/key_hash.rs (keyhash_cdr2_be: sorting by member_id)

Tests: crates/dcps/src/key_hash.rs::tests::the_member_order_does_not_reach_the_hash

Status: done

§9.6.4.8 KeyHash steps 2 and 3: values and recursion

Spec: §9.6.4.8, p. 194 — “Step 2. … setting the members present in FooKeyHolderObject to the same values as the corresponding members in FooObject. Step 3. Apply steps 1 and 2 recursively to the members of FooKeyHolder if they are themselves Aggregated types”.

Repo: crates/dcps/src/key_hash.rs (PlainCdr2BeKeyHolder); crates/dcps/src/runtime.rs (reader_key_hash_context)

Tests: crates/dcps/src/runtime.rs::tests::alive_sample_without_key_hash_gets_the_types_computed_hash, crates/dcps/tests/lifecycle_wire_e2e.rs::linux::dispose_marker_carries_the_key_fields_of_a_string_keyed_type

Status: done

§9.6.4.8 KeyHash step 4: PLAIN_CDR2 big endian

Spec: §9.6.4.8, p. 194 — “Compute the PLAIN_CDR2 Big Endian Serialization … The serialization shall be performed on a buffer that is initially aligned to the maximum alignment in PLAIN_CDR2 (i.e., 4). Furthermore, any padding bytes added due to alignment rules shall be set to zero.”

Repo: crates/dcps/src/key_hash.rs (PlainCdr2BeKeyHolder)

Tests: crates/dcps/src/key_hash.rs::tests::a_u32_goes_out_big_endian, crates/dcps/src/key_hash.rs::tests::a_u64_is_aligned_to_four_and_not_to_eight, crates/dcps/src/key_hash.rs::tests::a_string_carries_its_terminator_in_its_length

Status: done

§9.6.4.8 KeyHash step 5: padding or MD5 by the maximum size

Spec: §9.6.4.8, p. 194 — “Step 5.1 If the FooKeyHolder has a maximum serialized size that is less than or equal to 16 bytes, then the KeyHash of FooObject shall be set to the result of Step 4, extended to 16 bytes. … Step 5.2 If the FooKeyHolder has a maximum serialized size that is greater than 16 bytes, then the KeyHash_t of FooObject shall be set to the MD5 Hash”.

Repo: crates/dcps/src/key_hash.rs (compute_key_hash: key_holder_max_size)

Tests: crates/dcps/src/key_hash.rs::tests::a_short_instance_of_a_bounded_type_still_pads, crates/dcps/src/key_hash.rs::tests::a_holder_over_sixteen_is_hashed

Status: done

§9.6.4.8 KeyHash examples 1 to 3

Spec: §9.6.4.8, pp. 194–196 — “Example 1 …”, “Example 2 …”, “Example 3 …” with the expected octets.

Repo: crates/dcps/src/key_hash.rs (PlainCdr2BeKeyHolder, compute_key_hash); crates/dcps/src/dds_type.rs (DdsType::compute_key_hash)

Tests: crates/dcps/src/dds_type.rs::tests::key_hash_example_1_of_the_spec_is_the_holder_padded_with_zeros, crates/dcps/src/dds_type.rs::tests::key_hash_example_2_of_the_spec_is_the_md5_of_the_holder, crates/dcps/src/dds_type.rs::tests::key_hash_example_3_of_the_spec_is_the_md5_of_the_reordered_holder

Status: done — the three examples give the octets of the spec: Example 1 the holder extended with zeros to 16 octets, Examples 2 and 3 the MD5 of the 20-octet and the 13-octet holder (f91a59e3…, 374b96e2…).

§9.6.4.9 StatusInfo_t: 4 octets

Spec: §9.6.4.9, p. 196 — “The StatusInfo_t is defined as a 4-Byte octet array (see 9.3.2) therefore the status info inline parameter just copies those 4 Bytes.”

Repo: crates/rtps/src/inline_qos.rs (status_info_param: network order; find_status_info)

Tests: crates/dcps/tests/lifecycle_wire_decode.rs::reader_push_lifecycle_unregistered_sets_instance_state, crates/dcps/tests/lifecycle_wire_e2e.rs::linux::unregister_with_autodispose_false_propagates_unregister_only

Status: done

§9.6.4.9 StatusInfo in Data or DataFrag

Spec: §9.6.4.9, p. 196 — “The status info parameter may appear in the Data or in the DataFrag submessages.”

Repo: crates/rtps/src/reliable_reader.rs (classify_change_kind for DATA, handle_data_frag_opening for DATA_FRAG)

Tests: crates/dcps/tests/lifecycle_wire_decode.rs::reader_push_lifecycle_disposed_sets_instance_state, crates/rtps/src/reliable_reader.rs::tests::a_reassembled_key_is_a_dispose_or_a_registration_as_a_data_is, crates/rtps/src/reliable_reader.rs::tests::a_reassembled_sample_with_the_filtered_flag_is_known_but_not_delivered

Status: done — evaluated in DATA and in DATA_FRAG (a key with D or U as dispose and unregister, F as a filtered sample).

§9.6.4.9 StatusInfo: X flags

Spec: §9.6.4.9, p. 197 — “The flags represented with the literal ‘X’ are unused by this version of the protocol and should be set to zero by the writer and not interpreted by the reader”.

Repo: crates/rtps/src/inline_qos.rs (status_info); crates/rtps/src/reliable_reader.rs (classify_change_kind: D and U only)

Tests: crates/dcps/tests/lifecycle_wire_decode.rs::reader_push_lifecycle_disposed_sets_instance_state

Status: done

§9.6.4.9 StatusInfo DisposedFlag

Spec: §9.6.4.9, p. 197 — “D=1 indicates that the DDS DataWriter has disposed the instance of the data-object whose Key appears in the submessage.”

Repo: crates/rtps/src/inline_qos.rs (status_info::DISPOSED = 0x1)

Tests: crates/dcps/tests/lifecycle_wire_e2e.rs::linux::dispose_propagates_over_wire_to_reader, crates/dcps/tests/lifecycle_wire_decode.rs::reader_push_lifecycle_disposed_sets_instance_state

Status: done

§9.6.4.9 StatusInfo UnregisteredFlag

Spec: §9.6.4.9, p. 197 — “U=1 indicates that the DDS DataWriter has unregistered the instance of the data-object whose Key appears in the submessage.”

Repo: crates/rtps/src/inline_qos.rs (status_info::UNREGISTERED = 0x2)

Tests: crates/dcps/tests/lifecycle_wire_decode.rs::reader_push_lifecycle_unregistered_sets_instance_state, crates/dcps/tests/lifecycle_wire_e2e.rs::linux::instance_goes_no_writers_when_its_last_writer_disappears

Status: done

§9.6.4.9 StatusInfo FilteredFlag

Spec: §9.6.4.9, p. 197 — “F=1 indicates that the DDS DataWriter has written as sample for the instance … but the sample did not pass the content filter specified by the DDS DataReader.” “If both DisposedFlag==0 and UnregisteredFlag=0 … FilteredFlag==1 indicates it did not pass the filter.”

Repo: crates/rtps/src/reliable_reader.rs (status_change_kind, classify_change_kind, ReliableReader::filtered_sample_count)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_sample_with_the_filtered_flag_is_known_but_not_delivered, crates/rtps/src/reliable_reader.rs::tests::a_reassembled_sample_with_the_filtered_flag_is_known_but_not_delivered, crates/rtps/src/reliable_reader.rs::tests::the_reader_keeps_the_status_of_each_change

Status: done — a DATA or DATA_FRAG with F = 1 and D = U = 0 (with or without payload and key flag) gives ChangeKind::AliveFiltered: the number is known and NA_FILTERED (the writer does not repeat it), the sample is not delivered and is counted in filtered_sample_count. With D or U set the lifecycle marker applies. ZeroDDS does not send F (the runtime does not filter on the writer side); whether another vendor sends F is not measured.

§9.6.4.9 Registration not propagated

Spec: §9.6.4.9, p. 197 — “Note that the protocol does not require that the DDS DataWriter propagates the”register” operation.”

Repo: —

Tests: —

Status: n/a (informative) — no requirement.

§9.6.5 Table 9.24 DDS-XTypes

Spec: §9.6.5, p. 197, Table 9.24 — “DDS-XTypes 1.1 … 1.3 — 0x0069, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076; Note that 0x0076 was deprecated in DDS-XTypes 1.2”.

Repo: crates/rtps/src/parameter_list.rs (pid::DATA_REPRESENTATION, TYPE_CONSISTENCY_ENFORCEMENT, TYPE_INFORMATION)

Tests: crates/rtps/src/publication_data.rs::tests::issue30_type_identifier_from_standard_type_information, crates/discovery/tests/vendor_discovery_frames.rs::cyclone_announcements_read_and_write_back

Status: done

§9.6.5 Table 9.24 DDS-Security

Spec: §9.6.5, p. 197, Table 9.24 — “DDS-Security 1.1 — Parameter IDs in the range 0x1000 to 0x1FFF; Parameter IDs in the range 0x5000 to 0x5FFF”.

Repo: crates/rtps/src/parameter_list.rs (security PIDs 0x1001 to 0x1013)

Tests: crates/rtps/src/parameter_list.rs::tests::is_standard_pid_recognises_dds_security_pids, crates/rtps/src/participant_data.rs::tests::participant_security_info_pid_roundtrip

Status: done

§9.6.5 Table 9.24 DDS-RPC

Spec: §9.6.5, p. 197, Table 9.24 — “DDS-RPC 1.0 — 0x0080, 0x0081, 0x0082, 0x0083”.

Repo: crates/rtps/src/parameter_list.rs (pid::SERVICE_INSTANCE_NAME, RELATED_ENTITY_GUID, TOPIC_ALIASES, RELATED_SAMPLE_IDENTITY)

Tests: crates/rtps/src/parameter_list.rs::tests::rpc_pid_constants_match_spec, crates/rtps/src/publication_data.rs::tests::rpc_pid_constants_in_emitted_bytes

Status: done

§9.6.6 Table 9.25 PID_PERSISTENCE (0x0003)

Spec: §9.6.6, pp. 197–198, Table 9.25 — “PID_PERSISTENCE — 0x0003 — 2.2”; “These parameters should not be used by versions of the protocol equal or newer than the deprecated version unless they are used with the same meaning as in versions prior to the deprecated version.”

Repo: —

Tests: —

Status: n/a (informative) — deprecated PID; ZeroDDS does not send it and passes over it on reception.

§9.6.6 Table 9.25 PID_TYPE_CHECKSUM (0x0008)

Spec: §9.6.6, p. 198, Table 9.25 — “PID_TYPE_CHECKSUM — 0x0008 — 2.2”.

Repo: —

Tests: —

Status: n/a (informative) — deprecated PID; ZeroDDS does not send it and passes over it on reception.

§9.6.6 Table 9.25 PID_TYPE2_NAME (0x0009)

Spec: §9.6.6, p. 198, Table 9.25 — “PID_TYPE2_NAME — 0x0009 — 2.2”.

Repo: —

Tests: —

Status: n/a (informative) — deprecated PID; ZeroDDS does not send it and passes over it on reception.

§9.6.6 Table 9.25 PID_TYPE2_CHECKSUM (0x000a)

Spec: §9.6.6, p. 198, Table 9.25 — “PID_TYPE2_CHECKSUM — 0x000a — 2.2”.

Repo: —

Tests: —

Status: n/a (informative) — deprecated PID; ZeroDDS does not send it and passes over it on reception.

§9.6.6 Table 9.25 PID_EXPECTS_ACK (0x0010)

Spec: §9.6.6, p. 198, Table 9.25 — “PID_EXPECTS_ACK — 0x0010 — 2.2”.

Repo: —

Tests: —

Status: n/a (informative) — deprecated PID; ZeroDDS does not send it and passes over it on reception.

§9.6.6 Table 9.25 PID_MANAGER_KEY (0x0012)

Spec: §9.6.6, p. 198, Table 9.25 — “PID_MANAGER_KEY — 0x0012 — 2.2”.

Repo: —

Tests: —

Status: n/a (informative) — deprecated PID; ZeroDDS does not send it and passes over it on reception.

§9.6.6 Table 9.25 PID_SEND_QUEUE_SIZE (0x0013)

Spec: §9.6.6, p. 198, Table 9.25 — “PID_SEND_QUEUE_SIZE — 0x0013 — 2.2”.

Repo: —

Tests: —

Status: n/a (informative) — deprecated PID; ZeroDDS does not send it and passes over it on reception (RTI sends it, vendor_discovery_frames.rs).

§9.6.6 Table 9.25 PID_RELIABILITY_ENABLED (0x0014)

Spec: §9.6.6, p. 198, Table 9.25 — “PID_RELIABILITY_ENABLED — 0x0014 — 2.2”.

Repo: —

Tests: —

Status: n/a (informative) — deprecated PID; ZeroDDS does not send it and passes over it on reception.

§9.6.6 Table 9.25 PID_VARGAPPS_SEQUENCE_NUMBER_LAST (0x0017)

Spec: §9.6.6, p. 198, Table 9.25 — “PID_VARGAPPS_SEQUENCE_NUMBER_LAST — 0x0017 — 2.2”.

Repo: —

Tests: —

Status: n/a (informative) — deprecated PID; ZeroDDS does not send it and passes over it on reception.

§9.6.6 Table 9.25 PID_RECV_QUEUE_SIZE (0x0018)

Spec: §9.6.6, p. 198, Table 9.25 — “PID_RECV_QUEUE_SIZE — 0x0018 — 2.2”.

Repo: —

Tests: —

Status: n/a (informative) — deprecated PID; ZeroDDS does not send it and passes over it on reception (RTI sends it, vendor_discovery_frames.rs).

§9.6.6 Table 9.25 PID_RELIABILITY_OFFERED (0x0019)

Spec: §9.6.6, p. 198, Table 9.25 — “PID_RELIABILITY_OFFERED — 0x0019 — 2.2”.

Repo: —

Tests: —

Status: n/a (informative) — deprecated PID; ZeroDDS does not send it and passes over it on reception.

§10 Serialized Payload Representation

§10.1 Introduction

Spec: §10.1, p. 199 — “The representation of the serialized application data is not part of the RTPS protocol. The RTPS protocol does not interpret the content of the SerializedPayload.”; “the content and format of the SerializedPayload is defined in sections 10.3 to 10.5.”

Repo: —

Tests: —

Status: n/a (informative) — overview; the requirements are in §10.2 to §10.5.

§10.2 SerializedPayloadHeader at the start of every SerializedPayload

Spec: §10.2, p. 199 — “All SerializedPayload shall start with the SerializedPayloadHeader defined below.”; “The SerializedPayloadHeader occupies the first four octets of the SerializedPayload”.

Repo: crates/dcps/src/runtime.rs (user_payload_encap, write_user_sample_pooled); crates/rtps/src/participant_data.rs (to_pl_cdr_le); crates/rtps/src/participant_message_data.rs (to_cdr); crates/security/src/generic_message.rs (encode_generic_message)

Tests: crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility, crates/rtps/src/participant_data.rs::tests::participant_data_first_4_bytes_are_pl_cdr_le_encapsulation, crates/rtps/src/participant_message_data.rs::tests::participant_message_data_roundtrip_le, crates/security-runtime/src/builtin_topics.rs::tests::encode_starts_with_cdr_le_encapsulation

Status: done

§10.2 SerializedPayloadHeader: structure

Spec: §10.2, p. 199 — “typedef octet RepresentationIdentifier[2]; typedef octet RepresentationOptions[2]; struct SerializedPayloadHeader { RepresentationIdentifier representation_identifier; RepresentationOptions representation_options; };”

Repo: crates/dcps/src/runtime.rs (user_encap_body, encap_representation, encap_big_endian)

Tests: crates/dcps/src/runtime.rs::tests::strip_user_encap_xcdr1_le, crates/dcps/src/runtime.rs::tests::strip_user_encap_xcdr2_le, crates/dcps/src/runtime.rs::tests::strip_user_encap_rejects_short

Status: done

§10.2 RepresentationOptions in the context of the RepresentationIdentifier

Spec: §10.2, p. 199 — “The RepresentationOptions shall be interpreted in the context of the RepresentationIdentifier, such that each RepresentationIdentifier may define the representation_options that it requires.”

Repo: crates/dcps/src/runtime.rs (user_encap_body: the low two bits as the count of appended padding octets per DDS-XTypes 1.3 §7.6.3.1.2)

Tests: crates/dcps/src/runtime.rs::tests::strip_user_encap_drops_the_padding_the_options_name, crates/dcps/src/runtime.rs::tests::strip_user_encap_refuses_padding_the_body_cannot_hold

Status: done

§10.2 CDR stream starts after representation_options

Spec: §10.2, p. 199 — “For alignment purposes, the CDR stream is logically reset at the position that follows the representation_options. Therefore, there should be no initial padding before the serialized data is added to the CDR stream.”

Repo: crates/dcps/src/runtime.rs (write_user_sample_pooled: header and a separately encoded body; user_encap_body: body from octet 4)

Tests: crates/dcps/src/interop.rs::tests::u64_type_xcdr1_and_xcdr2_alignment_differs, crates/dcps/src/runtime.rs::tests::strip_user_encap_xcdr1_le

Status: done

§10.2 Footnote 5: earlier versions

Spec: §10.2, p. 199, footnote 5 — “Versions of the RTPS specification previous to version 2.4 did not clearly state where the CDR stream was reset for alignment purposes. Therefore implementations may need to take into account the vendor and protocol version when interpreting the Serialized Data.”

Repo: —

Tests: —

Status: n/a (informative) — a note without an obligation.

§10.3 Discovery built-in endpoints use Table 10.1

Spec: §10.3, p. 200 — “The SerializedPayload for the data messages associated with built-in discovery endpoints shall use the RepresentationIdentifier values and formats defined in Table 10.1 below.”

Repo: crates/rtps/src/participant_data.rs, crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs, crates/rtps/src/topic_data.rs (encoding with PL_CDR_LE or PL_CDR_BE, other identifiers refused on reading)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_decode_rejects_unknown_encapsulation, crates/rtps/src/publication_data.rs::tests::decode_rejects_unknown_encapsulation

Status: done

§10.3 Table 10.1 PL_CDR_BE {0x00, 0x02}

Spec: §10.3, p. 200, Table 10.1 — “PL_CDR_BE — {0x00, 0x02} — ParameterList (9.4.2.11). Both the parameter list and its parameters are encapsulated using OMG CDR Big Endian.”

Repo: crates/rtps/src/participant_data.rs (to_pl_cdr_be, from_pl_cdr_le); crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs (reading on [0x00, 0x02])

Tests: crates/rtps/src/participant_data.rs::tests::to_pl_cdr_be_is_big_endian_roundtrips_and_omits_credential_tokens, crates/rtps/src/publication_data.rs::tests::locator_params_of_a_big_endian_list_are_read

Status: done

§10.3 Table 10.1 PL_CDR_LE {0x00, 0x03}

Spec: §10.3, p. 200, Table 10.1 — “PL_CDR_LE — {0x00, 0x03} — ParameterList (9.4.2.11). Both the parameter list and its parameters are encapsulated using OMG CDR Little Endian.”

Repo: crates/rtps/src/participant_data.rs (ENCAPSULATION_PL_CDR_LE, to_pl_cdr_le)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_first_4_bytes_are_pl_cdr_le_encapsulation, crates/discovery/tests/vendor_discovery_frames.rs::cyclone_announcements_read_and_write_back

Status: done

§10.3 representation_options: the sender sets zero

Spec: §10.3, p. 200 — “The current version of the protocol does not use the representation_options: The sender shall set the representation_options to zero.”

Repo: crates/rtps/src/participant_data.rs (to_pl_cdr_le, to_pl_cdr_be: options 0x0000)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_first_4_bytes_are_pl_cdr_le_encapsulation

Status: done

§10.3 representation_options: the receiver ignores them

Spec: §10.3, p. 200 — “The receiver shall ignore the value of the representation_options.”

Repo: crates/rtps/src/participant_data.rs, publication_data.rs, subscription_data.rs (from_pl_cdr_le)

Tests: crates/rtps/src/subscription_data.rs::tests::the_receiver_ignores_the_representation_options, crates/rtps/src/participant_data.rs::tests::the_receiver_ignores_the_representation_options_of_a_participant, crates/rtps/src/publication_data.rs::tests::the_receiver_ignores_the_representation_options_of_a_publication

Status: done — the decoders read an announcement with representation_options ≠ 0 like one with 0; the sender writes 0.

§10.4 Other built-in endpoints use Table 10.2

Spec: §10.4, p. 200 — “The SerializedPayload for the data messages associated with built-in endpoints other than discovery built-in endpoints shall use one of the RepresentationIdentifier values and formats defined in Table 10.2 below.”

Repo: crates/rtps/src/participant_message_data.rs (to_cdr: CDR_LE or CDR_BE); crates/security/src/generic_message.rs (CDR_LE)

Tests: crates/rtps/src/participant_message_data.rs::tests::participant_message_data_roundtrip_le, crates/security-runtime/src/builtin_topics.rs::tests::encode_starts_with_cdr_le_encapsulation

Status: done — ParticipantMessageData and the messages of the DDS-Security endpoints use CDR_LE. The TypeLookup endpoints use CDR2_LE, the representation their own definition names (DDS-XTypes 1.4 Beta 1 §7.6.3.3.3), and CDR_LE under the setting xcdr1 (item “TypeLookup endpoints with CDR2_LE”).

§10.4 TypeLookup endpoints with CDR2_LE

Spec: §10.4, p. 200 — “shall use one of the RepresentationIdentifier values and formats defined in Table 10.2 below.” Table 10.2 names CDR_BE, CDR_LE, PL_CDR_BE and PL_CDR_LE.

Repo: crates/types/src/type_lookup.rs (TypeLookupEncoding, TypeLookupEncapsulation, to_payload), crates/types/src/framing.rs (EncodingVersion, encode_optional, encode_mutable), crates/dcps/src/runtime.rs (send_type_lookup_request_datagram, send_type_lookup_reply, dispatch_type_lookup_datagram, RuntimeConfig::type_lookup_encoding), crates/java-omgdds/java/src/main/java/org/zerodds/typelookup/TypeLookupService.java (Encoding, Encapsulation), .../generated/ZdCodec.java (ZdCodec.Xcdr1)

Tests: crates/types/tests/type_lookup_xcdr1.rs (eight tests, among them a_get_types_request_is_cdr_le_with_its_parameters_as_a_parameter_list and a_get_types_reply_carries_its_object_in_the_encoding_version_1), crates/dcps/tests/type_lookup_e2e.rs::{server_handles_inbound_get_types_request_via_dispatch, a_get_types_request_in_cdr_le_is_answered, the_setting_xcdr1_answers_in_cdr_le, a_request_is_written_in_the_configured_encoding}, crates/dcps/tests/typelookup_resolution_e2e.rs::a_complete_object_crosses_between_an_xcdr1_and_an_xcdr2_participant, crates/java-omgdds/java/src/test/java/org/zerodds/typelookup/TypeLookupEncodingTest.java (five tests), crates/dcps/tests/java_typelookup_live.rs (Java asks the Rust runtime and the Rust runtime asks Java, over RTPS between two processes, both with the default XCDR2)

Status: done — request and reply of the TypeLookup service go out with 00 07 (CDR2_LE) and the XCDR2 encoding by default: the FINAL envelope without a DHEADER, the appendable unions with one, the MUTABLE _In/_Out parameters with a DHEADER and an EMHEADER per member. DDS-XTypes 1.4 Beta 1 (ptc/2026-02-06) §7.6.3.3.3: “The Data Representation used by these endpoints shall be Extended CDR Representation (encoding version 2)”, the resolution of OMG issue DDSXTY14-29. §10.4 leaves the format to “the definition of each of those builtin Endpoints”, and that definition now names XCDR2; CDR2_LE is not in Table 10.2, and DDSI-RTPS 2.5 is the current version. The form of Table 10.2 is the named setting wire.type_lookup_encoding = xcdr1 (env ZERODDS_WIRE_TYPE_LOOKUP_ENCODING, zerodds.yaml(5)): 00 01 (CDR_LE) with XCDR1, the outer type without a header, the MUTABLE parameters as PL_CDR1 lists with PID_EXTENDED (0x7F01, Table 34) for the @hashid ids above 0x3F00 and PID_LIST_END (0x7F02), the @optional members of the TypeObjects behind a parameter header instead of a presence octet (XTypes 1.3 §7.4.1.1.5.2, §7.4.1.2). It is the reading of XTypes 1.3, which names no representation for these endpoints: no DataRepresentation (default XCDR, §7.6.3.1.1), an unannotated outer type is APPENDABLE (§7.3.1.2.1.8), Table 60 gives CDR_LE. A received sample is read in the encoding its identifier names (CDR_BE/CDR_LE → XCDR1, CDR2_BE/CDR2_LE → XCDR2) under either setting; any other identifier is dropped and reported as typelookup.sample.rejected. The sample ends on a four-octet boundary and the options count the padding (XTypes 1.3 §7.6.3.1.2, 38d06cac567). The Java runtime (crates/java-omgdds) has the same default and the same setting (property zerodds.wire.type_lookup_encoding or the same environment variable, 21bbd369efa); its XCDR1 codec is generated from the same unmodified IDL and writes the octets the Rust runtime writes (TypeLookupEncodingTest::aGetTypesRequestIsWrittenInTheEncodingVersion1, theRustReplyReadsAndIsWrittenBackOctetForOctet). The expected XCDR1 octets of the tests are derived from the clauses, not a vendor capture: no measured vendor sends this form. Measured (Linux test host, internal/release/evidence/rc7-typelookup-encapsulation, e954fd7cfe8), in each direction with a type the peer does not know:

Vendor sends reads a CDR_LE request reads a CDR_LE reply
Cyclone DDS 11.0.1 CDR2_LE, options = padding no (deserialization failed) no (deserialization failed)
Fast DDS 3.6.1 CDR2_LE (replies) yes, answers not measured: Fast DDS asked in no cell
OpenDDS 3.34.0 CDR2_LE, options 0000 no (failed to deserialize type lookup request) no (failed to deserialize type lookup reply)
RTI Connext 7.7.0 CDR2_LE no (no deserialization program … CDR_LE) no (the same message)

InterCom DDS 4.3.1 sends CDR2_LE as well (earlier capture, an_intercom_get_types_request_padded_without_its_options_is_read). OpenDDS writes the options 0000 also on a sample that ends three octets short of a four-octet offset; XTypes 1.3 §7.6.3.1.2 asks for the padding count there. ZeroDDS reads it without a guess: the envelope’s structure says where it ends, and zero octets up to the next four-octet offset are the padding behind a submessage (DDSI-RTPS 2.5 §9.4.1), with and without them (runtime::tests::an_opendds_get_types_request_without_its_padding_count_is_read with the captured request, 6224b8ceab5). The runners set nothing for it; every pair runs the default. With CDR2_LE the Cyclone cell with the appended member delivers its samples (cyc-answers-x2: 38), with CDR_LE none (cyc-answers-x1).

§10.4 Table 10.2 CDR_BE {0x00, 0x00}

Spec: §10.4, p. 200, Table 10.2 — “CDR_BE — {0x00, 0x00} — Classic CDR representation with Big Endian encoding.”

Repo: crates/rtps/src/participant_message_data.rs (to_cdr(false), from_cdr)

Tests: crates/rtps/src/participant_message_data.rs::tests::participant_message_data_roundtrip_be

Status: done

§10.4 Table 10.2 CDR_LE {0x00, 0x01}

Spec: §10.4, p. 200, Table 10.2 — “CDR_LE — {0x00, 0x01} — Classic CDR representation with Little Endian encoding.”

Repo: crates/rtps/src/participant_message_data.rs (ENCAPSULATION_CDR_LE); crates/security/src/generic_message.rs (ENCAPSULATION_CDR_LE)

Tests: crates/rtps/src/participant_message_data.rs::tests::participant_message_data_roundtrip_le, crates/security-runtime/src/builtin_topics.rs::tests::encode_starts_with_cdr_le_encapsulation

Status: done

§10.4 Table 10.2 PL_CDR_BE {0x00, 0x02}

Spec: §10.4, p. 200, Table 10.2 — “PL_CDR_BE — {0x00, 0x02} — ParameterList (9.4.2.11) with Big Endian encoding.”

Repo: —

Tests: —

Status: n/a (informative) — one of the permitted identifiers; ZeroDDS uses CDR_LE and CDR_BE for these endpoints.

§10.4 Table 10.2 PL_CDR_LE {0x00, 0x03}

Spec: §10.4, p. 200, Table 10.2 — “PL_CDR_LE — {0x00, 0x03} — ParameterList (9.4.2.11) with Little Endian encoding.”

Repo: —

Tests: —

Status: n/a (informative) — one of the permitted identifiers; ZeroDDS uses CDR_LE and CDR_BE for these endpoints.

§10.4 Definition per built-in endpoint

Spec: §10.4, p. 200 — “The definition of each of those builtin Endpoints should indicate the serialized data format and RepresentationIdentifier used.”

Repo: —

Tests: —

Status: n/a (informative) — addressed to the specifications that define built-in endpoints.

§10.5 User topics use the representations of DDS-XTypes §7.4

Spec: §10.5, p. 200 — “The SerializedPayload for the data messages associated with the user-defined DDS Topics shall use the data representations defined in DDS-XTYPES clause 7.4 (Data Representation). Accordingly, the RepresentationIdentifier values and the corresponding formats shall be as defined in Table 10.3.”

Repo: crates/dcps/src/runtime.rs (user_payload_encap, encap_in_table, user_encap_body); wire.encapsulation_ids

Tests: crates/dcps/src/runtime.rs::tests::encap_in_table_maps_table_60_onto_table_39, crates/dcps/src/runtime.rs::tests::a_writer_stamps_the_identifiers_of_table_39_when_the_runtime_is_set_to_them, crates/dcps/src/runtime.rs::tests::the_encapsulation_identifiers_of_table_39_are_read, crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility, crates/dcps/tests/runtime_config_layering.rs::the_encapsulation_and_pl_cdr1_settings_default_to_the_vendors_and_are_set_by_file_and_environment

Status: done — XCDR1, XCDR2 and XML are implemented. Both sets of values are read. The default sent is DDS-XTypes 1.3 Table 60, to which the header of Table 10.3 refers and which Cyclone DDS 11.0.1, Fast DDS, OpenDDS 3.34.0 and RTI 7.7.0 send (measured in tools/wire-capture/frames/*/*.xcdr2.frames). With wire.encapsulation_ids: table-39 (environment ZERODDS_WIRE_ENCAPSULATION_IDS) ZeroDDS sends the identifiers of Table 39 (§7.4.3.4), whose XCDR2 values are those of Table 10.3 (XML: {0x01, 0x00}). Expected from the vendors: a peer that reads Table 60 only cannot read data with 0x0010 to 0x0015; the setting is for peers that send and expect Table 10.3. Not measured: a run against the vendors with the setting.

§10.5 Table 10.3 CDR_BE {0x00, 0x00}

Spec: §10.5, p. 201, Table 10.3 — “CDR_BE — {0x00, 0x00} — Classic CDR representation with Big Endian encoding.”

Repo: crates/dcps/src/runtime.rs (user_payload_encap with big_endian, encap_big_endian)

Tests: crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility, crates/dcps/src/subscriber.rs::tests::cache_materialize_honors_xcdr1_encapsulation_le_and_be

Status: done

§10.5 Table 10.3 CDR_LE {0x00, 0x01}

Spec: §10.5, p. 201, Table 10.3 — “CDR_LE — {0x00, 0x01} — Classic CDR representation with Little Endian encoding.”

Repo: crates/dcps/src/runtime.rs (USER_PAYLOAD_ENCAP, user_payload_encap)

Tests: crates/dcps/src/runtime.rs::tests::user_payload_encap_is_cdr_le, crates/dcps/src/runtime.rs::tests::strip_user_encap_xcdr1_le

Status: done

§10.5 Table 10.3 PL_CDR_BE {0x00, 0x02}

Spec: §10.5, p. 201, Table 10.3 — “PL_CDR_BE — {0x00, 0x02} — ParameterList (9.4.2.11) with Big Endian encoding.”

Repo: crates/dcps/src/runtime.rs (user_payload_encap: XCDR1 and MUTABLE)

Tests: crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility

Status: done

§10.5 Table 10.3 PL_CDR_LE {0x00, 0x03}

Spec: §10.5, p. 201, Table 10.3 — “PL_CDR_LE — {0x00, 0x03} — ParameterList (9.4.2.11) with Little Endian encoding.”

Repo: crates/dcps/src/runtime.rs (user_payload_encap: XCDR1 and MUTABLE)

Tests: crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility

Status: done

§10.5 Table 10.3 CDR2_BE {0x00, 0x10}

Spec: §10.5, p. 201, Table 10.3 — “CDR2_BE — {0x00, 0x10} — Plain CDR representation (version2) with Big Endian encoding.”

Repo: crates/dcps/src/runtime.rs (user_payload_encap, encap_in_table, user_encap_body); wire.encapsulation_ids

Tests: crates/dcps/src/runtime.rs::tests::encap_in_table_maps_table_60_onto_table_39, crates/dcps/src/runtime.rs::tests::a_writer_stamps_the_identifiers_of_table_39_when_the_runtime_is_set_to_them, crates/dcps/src/runtime.rs::tests::the_encapsulation_identifiers_of_table_39_are_read, crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility, crates/dcps/tests/runtime_config_layering.rs::the_encapsulation_and_pl_cdr1_settings_default_to_the_vendors_and_are_set_by_file_and_environment

Status: done — CDR2_BE: big endian, even identifier. Both sets of values are read. The default sent is DDS-XTypes 1.3 Table 60, to which the header of Table 10.3 refers and which Cyclone DDS 11.0.1, Fast DDS, OpenDDS 3.34.0 and RTI 7.7.0 send (measured in tools/wire-capture/frames/*/*.xcdr2.frames). With wire.encapsulation_ids: table-39 (environment ZERODDS_WIRE_ENCAPSULATION_IDS) ZeroDDS sends the identifiers of Table 39 (§7.4.3.4), whose XCDR2 values are those of Table 10.3 (XML: {0x01, 0x00}). Expected from the vendors: a peer that reads Table 60 only cannot read data with 0x0010 to 0x0015; the setting is for peers that send and expect Table 10.3. Not measured: a run against the vendors with the setting.

§10.5 Table 10.3 CDR2_LE {0x00, 0x11}

Spec: §10.5, p. 201, Table 10.3 — “CDR2_LE — {0x00, 0x11} — Plain CDR representation (version2) with Little Endian encoding.”

Repo: crates/dcps/src/runtime.rs (user_payload_encap, encap_in_table, user_encap_body); wire.encapsulation_ids

Tests: crates/dcps/src/runtime.rs::tests::encap_in_table_maps_table_60_onto_table_39, crates/dcps/src/runtime.rs::tests::a_writer_stamps_the_identifiers_of_table_39_when_the_runtime_is_set_to_them, crates/dcps/src/runtime.rs::tests::the_encapsulation_identifiers_of_table_39_are_read, crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility, crates/dcps/tests/runtime_config_layering.rs::the_encapsulation_and_pl_cdr1_settings_default_to_the_vendors_and_are_set_by_file_and_environment

Status: done — CDR2_LE. Both sets of values are read. The default sent is DDS-XTypes 1.3 Table 60, to which the header of Table 10.3 refers and which Cyclone DDS 11.0.1, Fast DDS, OpenDDS 3.34.0 and RTI 7.7.0 send (measured in tools/wire-capture/frames/*/*.xcdr2.frames). With wire.encapsulation_ids: table-39 (environment ZERODDS_WIRE_ENCAPSULATION_IDS) ZeroDDS sends the identifiers of Table 39 (§7.4.3.4), whose XCDR2 values are those of Table 10.3 (XML: {0x01, 0x00}). Expected from the vendors: a peer that reads Table 60 only cannot read data with 0x0010 to 0x0015; the setting is for peers that send and expect Table 10.3. Not measured: a run against the vendors with the setting.

§10.5 Table 10.3 PL_CDR2_BE {0x00, 0x12}

Spec: §10.5, p. 201, Table 10.3 — “PL_CDR2_BE — {0x00, 0x12} — Extended CDR representation (version2) for MUTABLE types with Big Endian encoding.”

Repo: crates/dcps/src/runtime.rs (user_payload_encap, encap_in_table, user_encap_body); wire.encapsulation_ids

Tests: crates/dcps/src/runtime.rs::tests::encap_in_table_maps_table_60_onto_table_39, crates/dcps/src/runtime.rs::tests::a_writer_stamps_the_identifiers_of_table_39_when_the_runtime_is_set_to_them, crates/dcps/src/runtime.rs::tests::the_encapsulation_identifiers_of_table_39_are_read, crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility, crates/dcps/tests/runtime_config_layering.rs::the_encapsulation_and_pl_cdr1_settings_default_to_the_vendors_and_are_set_by_file_and_environment

Status: done — PL_CDR2_BE. Both sets of values are read. The default sent is DDS-XTypes 1.3 Table 60, to which the header of Table 10.3 refers and which Cyclone DDS 11.0.1, Fast DDS, OpenDDS 3.34.0 and RTI 7.7.0 send (measured in tools/wire-capture/frames/*/*.xcdr2.frames). With wire.encapsulation_ids: table-39 (environment ZERODDS_WIRE_ENCAPSULATION_IDS) ZeroDDS sends the identifiers of Table 39 (§7.4.3.4), whose XCDR2 values are those of Table 10.3 (XML: {0x01, 0x00}). Expected from the vendors: a peer that reads Table 60 only cannot read data with 0x0010 to 0x0015; the setting is for peers that send and expect Table 10.3. Not measured: a run against the vendors with the setting.

§10.5 Table 10.3 PL_CDR2_LE {0x00, 0x13}

Spec: §10.5, p. 201, Table 10.3 — “PL_CDR2_LE — {0x00, 0x13} — Extended CDR representation (version2) for MUTABLE types with Little Endian encoding.”

Repo: crates/dcps/src/runtime.rs (user_payload_encap, encap_in_table, user_encap_body); wire.encapsulation_ids

Tests: crates/dcps/src/runtime.rs::tests::encap_in_table_maps_table_60_onto_table_39, crates/dcps/src/runtime.rs::tests::a_writer_stamps_the_identifiers_of_table_39_when_the_runtime_is_set_to_them, crates/dcps/src/runtime.rs::tests::the_encapsulation_identifiers_of_table_39_are_read, crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility, crates/dcps/tests/runtime_config_layering.rs::the_encapsulation_and_pl_cdr1_settings_default_to_the_vendors_and_are_set_by_file_and_environment

Status: done — PL_CDR2_LE. Both sets of values are read. The default sent is DDS-XTypes 1.3 Table 60, to which the header of Table 10.3 refers and which Cyclone DDS 11.0.1, Fast DDS, OpenDDS 3.34.0 and RTI 7.7.0 send (measured in tools/wire-capture/frames/*/*.xcdr2.frames). With wire.encapsulation_ids: table-39 (environment ZERODDS_WIRE_ENCAPSULATION_IDS) ZeroDDS sends the identifiers of Table 39 (§7.4.3.4), whose XCDR2 values are those of Table 10.3 (XML: {0x01, 0x00}). Expected from the vendors: a peer that reads Table 60 only cannot read data with 0x0010 to 0x0015; the setting is for peers that send and expect Table 10.3. Not measured: a run against the vendors with the setting.

§10.5 Table 10.3 D_CDR_BE {0x00, 0x14}

Spec: §10.5, p. 201, Table 10.3 — “D_CDR_BE — {0x00, 0x14} — Extended CDR representation (version2) for APPENDABLE types with Big Endian encoding.”

Repo: crates/dcps/src/runtime.rs (user_payload_encap, encap_in_table, user_encap_body); wire.encapsulation_ids

Tests: crates/dcps/src/runtime.rs::tests::encap_in_table_maps_table_60_onto_table_39, crates/dcps/src/runtime.rs::tests::a_writer_stamps_the_identifiers_of_table_39_when_the_runtime_is_set_to_them, crates/dcps/src/runtime.rs::tests::the_encapsulation_identifiers_of_table_39_are_read, crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility, crates/dcps/tests/runtime_config_layering.rs::the_encapsulation_and_pl_cdr1_settings_default_to_the_vendors_and_are_set_by_file_and_environment

Status: done — D_CDR_BE. Both sets of values are read. The default sent is DDS-XTypes 1.3 Table 60, to which the header of Table 10.3 refers and which Cyclone DDS 11.0.1, Fast DDS, OpenDDS 3.34.0 and RTI 7.7.0 send (measured in tools/wire-capture/frames/*/*.xcdr2.frames). With wire.encapsulation_ids: table-39 (environment ZERODDS_WIRE_ENCAPSULATION_IDS) ZeroDDS sends the identifiers of Table 39 (§7.4.3.4), whose XCDR2 values are those of Table 10.3 (XML: {0x01, 0x00}). Expected from the vendors: a peer that reads Table 60 only cannot read data with 0x0010 to 0x0015; the setting is for peers that send and expect Table 10.3. Not measured: a run against the vendors with the setting.

§10.5 Table 10.3 D_CDR_LE {0x00, 0x15}

Spec: §10.5, p. 201, Table 10.3 — “D_CDR_LE — {0x00, 0x15} — Extended CDR representation (version2) for APPENDABLE types with Little Endian encoding.”

Repo: crates/dcps/src/runtime.rs (user_payload_encap, encap_in_table, user_encap_body); wire.encapsulation_ids

Tests: crates/dcps/src/runtime.rs::tests::encap_in_table_maps_table_60_onto_table_39, crates/dcps/src/runtime.rs::tests::a_writer_stamps_the_identifiers_of_table_39_when_the_runtime_is_set_to_them, crates/dcps/src/runtime.rs::tests::the_encapsulation_identifiers_of_table_39_are_read, crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility, crates/dcps/tests/runtime_config_layering.rs::the_encapsulation_and_pl_cdr1_settings_default_to_the_vendors_and_are_set_by_file_and_environment

Status: done — D_CDR_LE. Both sets of values are read. The default sent is DDS-XTypes 1.3 Table 60, to which the header of Table 10.3 refers and which Cyclone DDS 11.0.1, Fast DDS, OpenDDS 3.34.0 and RTI 7.7.0 send (measured in tools/wire-capture/frames/*/*.xcdr2.frames). With wire.encapsulation_ids: table-39 (environment ZERODDS_WIRE_ENCAPSULATION_IDS) ZeroDDS sends the identifiers of Table 39 (§7.4.3.4), whose XCDR2 values are those of Table 10.3 (XML: {0x01, 0x00}). Expected from the vendors: a peer that reads Table 60 only cannot read data with 0x0010 to 0x0015; the setting is for peers that send and expect Table 10.3. Not measured: a run against the vendors with the setting.

§10.5 Table 10.3: identifiers 0x0010 to 0x0015

Spec: §10.5, p. 201, Table 10.3 — “CDR2_BE {0x00, 0x10}”, “CDR2_LE {0x00, 0x11}”, “PL_CDR2_BE {0x00, 0x12}”, “PL_CDR2_LE {0x00, 0x13}”, “D_CDR_BE {0x00, 0x14}”, “D_CDR_LE {0x00, 0x15}”.

Repo: crates/dcps/src/runtime.rs (user_payload_encap, encap_in_table, user_encap_body); wire.encapsulation_ids

Tests: crates/dcps/src/runtime.rs::tests::encap_in_table_maps_table_60_onto_table_39, crates/dcps/src/runtime.rs::tests::a_writer_stamps_the_identifiers_of_table_39_when_the_runtime_is_set_to_them, crates/dcps/src/runtime.rs::tests::the_encapsulation_identifiers_of_table_39_are_read, crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility, crates/dcps/tests/runtime_config_layering.rs::the_encapsulation_and_pl_cdr1_settings_default_to_the_vendors_and_are_set_by_file_and_environment

Status: done — The six identifiers 0x0010 to 0x0015 (even big endian, odd little endian). Both sets of values are read. The default sent is DDS-XTypes 1.3 Table 60, to which the header of Table 10.3 refers and which Cyclone DDS 11.0.1, Fast DDS, OpenDDS 3.34.0 and RTI 7.7.0 send (measured in tools/wire-capture/frames/*/*.xcdr2.frames). With wire.encapsulation_ids: table-39 (environment ZERODDS_WIRE_ENCAPSULATION_IDS) ZeroDDS sends the identifiers of Table 39 (§7.4.3.4), whose XCDR2 values are those of Table 10.3 (XML: {0x01, 0x00}). Expected from the vendors: a peer that reads Table 60 only cannot read data with 0x0010 to 0x0015; the setting is for peers that send and expect Table 10.3. Not measured: a run against the vendors with the setting.

§10.5 Table 10.3 XML {0x00, 0x04}

Spec: §10.5, p. 201, Table 10.3 — “XML — {0x00, 0x04} — See DDS-XTypes [3] clause 7.4.4.”

Repo: crates/dcps/src/runtime.rs (XML_ENCAP, user_payload_encap, xml_wire_body, xml_sample_as_cdr); crates/dcps/src/xml_data.rs; crates/dcps/src/publisher.rs

Tests: crates/dcps/src/runtime.rs::tests::an_xml_sample_reaches_the_reader_as_its_cdr_body, crates/dcps/src/runtime.rs::tests::an_xml_sample_that_is_no_document_of_the_type_is_refused, crates/dcps/src/runtime.rs::tests::an_xml_dispose_carries_the_instance_key, crates/dcps/src/runtime.rs::tests::an_xml_writer_sends_the_document_of_the_sample, crates/dcps/src/runtime.rs::tests::a_writer_registered_with_xml_first_is_accepted

Status: done — a writer whose first DataRepresentation is XML sends the document of the sample under {0x00, 0x04}; a reader reads the sample against its registered type and hands on the XCDR2 body. Not measured: a vendor that sends or reads XML.

§10.5 Legacy DDS implementations without DDS-XTypes

Spec: §10.5, p. 201 — “Legacy DDS implementations that are not compliant with DDS-XTYPES should minimally support the RepresentationIdentifier values CDR_BE and CDR_LE and the type system elements specified in clause F1”.

Repo: —

Tests: —

Status: n/a (informative) — addressed to implementations without DDS-XTypes; ZeroDDS supports CDR_BE and CDR_LE (§10.5 Table 10.3).

§10.6 Example for built-in endpoint data

Spec: §10.6, pp. 201–203 — “Following is the SerializedPayload element used by the SEDPbuiltinSubscriptionsWriter to declare a DataReader.” with layout and octets.

Repo: crates/rtps/src/subscription_data.rs (SubscriptionBuiltinTopicData::from_pl_cdr_le, to_pl_cdr_le)

Tests: crates/rtps/src/subscription_data.rs::tests::the_example_of_10_6_is_read, crates/rtps/src/subscription_data.rs::tests::the_parameters_of_the_example_of_10_6_are_written_as_the_spec_prints_them

Status: done — the 84 octets of the spec are read as the DataReader they describe; the encoder writes the five parameters of the example with the same octets (the spec leaves the default values out, ZeroDDS writes them in addition).

§10.7 Example for user-defined topic data

Spec: §10.7, pp. 203–204 — “Following is the SerializedPayload element used by an application DataWriter to send Data on the Topic “Square” with type “ShapeType”” with layout and octets.

Repo: crates/dcps/src/runtime.rs (user_payload_encap, strip_user_encap)

Tests: crates/dcps/src/runtime.rs::tests::the_example_of_10_7_has_the_header_and_body_of_the_spec

Status: done — the CDR_LE header ({0x00, 0x01}, options 0) and the 24-octet body of the example (“BLUE”, 34, 100, 24) are read as the spec prints them; the header for an XCDR1 final writer is the one of the spec.

Annex A References

Annex A References

Spec: Annex A, p. 205 — “[1] DDS-SECURITY: DDS Security version 1.1 https://www.omg.org/spec/DDS-SECURITY”.

Repo: —

Tests: —

Status: n/a (informative) — list of references.


Audit-Status

978 done / 3 partial / 15 open / 2 blocked / 127 n/a (informative).

Open items: ddsi-rtps-2.5.open.en.md.

DDSI-RTPS 2.5 — Spec-Coverage

Quelle: internal/standards/cache/omg/ddsi-rtps-2.5.pdf (206 Seiten, OMG formal/2022-04-01) — OMG DDSI-RTPS 2.5

Item-für-Item-Audit gegen die PDF nach internal/spec-coverage/PROCESS.md. Seitenangaben sind PDF-Seiten (PDF-Seite = gedruckte Seite + 6). Jede Zeile einer normativen Tabelle ist ein eigenes Item. done steht nur, wo Code und Test die Anforderung abdecken; ein Test-Zitat nennt die Testfunktion als datei::modul::name.

Kontext: Der DDSI-RTPS-2.5-Stack ist verteilt über:

  • crates/rtps/ · docs.rs — Header, Submessages, HeaderExtension, ParameterList, Inline-QoS, Receiver-Zustand, Writer- und Reader-Zustandsmaschinen mit ihren Proxies, HistoryCache, Fragmentierung, Discovery-Datentypen.
  • crates/discovery/ · docs.rs — SPDP, SEDP, TypeLookup, die sicheren Builtin-Endpoints.
  • crates/transport/ · docs.rs, crates/transport-udp/ — Transport-Schnittstelle und der UDP/IP-PSM (§9.5).
  • crates/dcps/ · docs.rs — die DDS-Seite (§8.2.10), Writer Liveliness Protocol, KeyHash, Encapsulation-Header (§10).
  • crates/qos/ · docs.rs — die QoS-Policies und ihr Wire-Format.

Offene Punkte: siehe ddsi-rtps-2.5.open.md.


§1 Scope

§1 Scope

Spec: §1, S. 7 — “This specification defines an interoperability wire protocol for DDS. Its purpose and scope are to ensure that applications based on different vendors’ implementations of DDS can interoperate.”

Repo: crates/rtps/src/lib.rs

Tests: —

Status: n/a (informative) — Zweckbestimmung der Spec; die Anforderungen stehen in §7.5–§10 und sind dort einzeln geführt.


§2 Conformance

§2 Conformance

Spec: §2, S. 7 — “Implementations of this specification must comply with the conformance statements listed in 8.4.2 of this specification.”

Repo: —

Tests: —

Status: n/a (informative) — Verweis ohne eigene Anforderung; die Konformitätsaussagen von §8.4.2 sind unter §8.4.2.1–§8.4.2.3 einzeln geführt.


§3 Normative References

§3 Normative References

Spec: §3, S. 7 — Liste der normativen Dokumente [1] DDS 1.4, [2] IDL 4.2, [3] DDS-XTypes 1.2, [4] NTP Version 3 (RFC 1305), [5] MD5 (RFC 1321), [6] SCTP-CRC32c (RFC 4960 Anhang B), [7] AUTOSAR-CRC-Routinen R20-11.

Repo: —

Tests: —

Status: n/a (informative) — Querverweisliste. Was aus den Referenzen folgt, ist an der verwendenden Stelle geführt: Time_t im NTP-Format unter §9.3.2.2, MD5 unter §9.4.2.15 und §9.6.4.8, CRC32c und CRC64 unter §9.4.2.15.


§4 Terms and Definitions

§4 Terms and Definitions

Spec: §4, S. 7 — “For the purposes of this specification, the terms and definitions given in the normative references apply.”

Repo: —

Tests: —

Status: n/a (informative) — Begriffsverweis ohne Anforderung.


§5 Symbols

§5 Symbols

Spec: §5, S. 7 — Abkürzungen CDR, DDS, EDP, GUID, PDP, PIM, PSM, RTPS, SEDP.

Repo: —

Tests: —

Status: n/a (informative) — Abkürzungsliste.


§6 Additional Information

§6.1 Changes to Adopted OMG Specifications

Spec: §6.1, S. 9 — “This specification does not change any adopted OMG specifications.”

Repo: —

Tests: —

Status: n/a (informative) — redaktionelle Angabe.

§6.2 How to Read this Specification

Spec: §6.2, S. 9 — Lesehinweise zu PIM, PSM und den Modulen.

Repo: —

Tests: —

Status: n/a (informative) — Lesehinweis.

§6.3 Acknowledgments

Spec: §6.3, S. 9–11 — Liste der beitragenden Firmen und Personen je Revision.

Repo: —

Tests: —

Status: n/a (informative) — Danksagung.

§6.4 Statement of Maturity

Spec: §6.4, S. 11 — Reifegrad und bekannte Implementierungen.

Repo: —

Tests: —

Status: n/a (informative) — Hintergrundangabe.


§7 Overview

§7.1 Introduction

Spec: §7.1, S. 13 — Motivation eines DDS-Wire-Protokolls.

Repo: —

Tests: —

Status: n/a (informative) — Einführung ohne Anforderung.

§7.2 Requirements for a DDS Wire-protocol

Spec: §7.2, S. 13–14 — Anforderungen an ein DDS-Wire-Protokoll als Entwurfsziele (kein zentraler Namensdienst, keine Single Points of Failure, Erweiterbarkeit).

Repo: —

Tests: —

Status: n/a (informative) — Entwurfsziele; die daraus folgenden Mechanismen (SPDP/SEDP ohne Server, Versionierung) sind unter §8.5 und §8.6 geführt.

§7.3 The RTPS Wire-protocol

Spec: §7.3, S. 14 — Herkunft und Eigenschaften von RTPS.

Repo: —

Tests: —

Status: n/a (informative) — Beschreibung.

§7.4 The RTPS Platform Independent Model (PIM)

Spec: §7.4–§7.4.4, S. 14–17 — Gliederung des PIM in die Module Structure, Messages, Behavior und Discovery.

Repo: —

Tests: —

Status: n/a (informative) — Übersicht; die Module sind unter §8.2–§8.5 geführt.

§7.5 UDP/IP-PSM ist Pflicht

Spec: §7.5, S. 17 — “Multiple PSMs may be supported, but all implementations of DDS must at least implement the PSM on top of UDP/IP, which is presented in Clause 9.”

Repo: crates/transport-udp/src/udp_transport.rs (UdpTransport); crates/dcps/src/runtime.rs (SPDP/SEDP und Nutzdaten über UDP).

Tests: crates/transport-udp/tests/e2e.rs::e2e_write_udp_read_single_datagram, crates/transport-udp/tests/e2e.rs::e2e_write_udp_read_multiple_in_order, crates/transport-udp/src/udp_transport.rs::tests::send_recv_v6_loopback

Status: done

§7.6 Transport: Unicast-Adresse in 16 Oktetten

Spec: §7.6, S. 18 — “The transport has a generalized notion of a unicast address (shall fit within 16 bytes).”

Repo: crates/rtps/src/wire_types.rs (Locator::address: [u8; 16])

Tests: crates/rtps/src/wire_types.rs::tests::locator_udp_v6_constructor_keeps_full_address, crates/rtps/src/wire_types.rs::tests::locator_udp_v4_layout

Status: done

§7.6 Transport: Port in 4 Oktetten

Spec: §7.6, S. 18 — “The transport has a generalized notion of a port (shall fit within 4 bytes)”.

Repo: crates/rtps/src/wire_types.rs (Locator::port: u32)

Tests: crates/rtps/src/wire_types.rs::tests::locator_roundtrip_le

Status: done

§7.6 Transport: Datagramm an Adresse/Port senden

Spec: §7.6, S. 18 — “The transport can send a datagram (uninterpreted sequence of octets) to a specific address/port.”

Repo: crates/transport/src/lib.rs (Transport::send); crates/transport-udp/src/udp_transport.rs (UdpTransport::send)

Tests: crates/transport-udp/src/udp_transport.rs::tests::loopback_send_and_recv_delivers_datagram, crates/transport-udp/tests/e2e.rs::e2e_write_udp_read_single_datagram

Status: done

§7.6 Transport: Datagramm an Adresse/Port empfangen

Spec: §7.6, S. 18 — “The transport can receive a datagram at a specific address/port.”

Repo: crates/transport/src/lib.rs (Transport::recv); crates/transport-udp/src/udp_transport.rs (UdpTransport::recv, UdpTransport::bind_v4)

Tests: crates/transport-udp/src/udp_transport.rs::tests::bind_v4_returns_local_locator_with_assigned_port, crates/transport-udp/src/udp_transport.rs::tests::loopback_multiple_datagrams_in_order

Status: done

§7.6 Transport verwirft unvollständige oder verfälschte Nachrichten

Spec: §7.6, S. 18 — “The transport will drop messages if incomplete or corrupted during transfer (i.e., RTPS assumes messages are complete and not corrupted).”

Repo: —

Tests: —

Status: n/a (informative) — Annahme über den Transport, keine Anforderung an die RTPS-Implementierung. Für UDP prüft die Prüfsumme des UDP-Kopfs im Betriebssystem; die optionale Nachrichtenprüfsumme der HeaderExtension ist unter §8.3.3.2 und §9.4.2.15 geführt.


§8.1 Introduction

§8.1 PIM als virtuelle Maschine

Spec: §8.1, S. 19 — “This description is not intended to constrain the internal implementation in any way. The only criteria for a compliant implementation is that the externally-observable behavior satisfies the requirements for interoperability.”

Repo: —

Tests: —

Status: n/a (informative) — legt den Maßstab für die PIM-Items fest: geprüft wird das von außen beobachtbare Verhalten, nicht die Klassenstruktur.


§8.2 Structure Module

§8.2.1 Overview

Spec: §8.2.1, S. 19 — jede RTPS-Entity entspricht einer DDS-Entity; der HistoryCache ist die Schnittstelle zwischen beiden.

Repo: —

Tests: —

Status: n/a (informative) — Übersicht; die Beziehung ist unter §8.2.10 je Übergang geführt.

§8.2.1.1 Table 8.1 Klassen der virtuellen Maschine

Spec: §8.2.1.1, S. 20–21, Table 8.1 — Zusammenfassung der Klassen Entity, Endpoint, Participant, Writer, Reader, HistoryCache, CacheChange, Data.

Repo: —

Tests: —

Status: n/a (informative) — Zusammenfassung; jede Klasse ist mit ihren Attributen unter §8.2.2–§8.2.9 geführt.

§8.2.1.2 Table 8.2 GUID_t

Spec: §8.2.1.2, S. 21, Table 8.2 — “GUID_t … Must be possible to represent using 16 octets. The following values are reserved by the protocol: GUID_UNKNOWN”.

Repo: crates/rtps/src/wire_types.rs (Guid, Guid::WIRE_SIZE, Guid::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::guid_layout_is_prefix_then_entity_id, crates/rtps/src/wire_types.rs::tests::guid_roundtrip, crates/rtps/src/wire_types.rs::tests::guid_prefix_unknown_is_zero, crates/rtps/src/wire_types.rs::tests::entity_id_unknown_is_four_zero_octets

Status: done — Guid::UNKNOWN ist aus den beiden geprüften UNKNOWN-Teilen zusammengesetzt.

§8.2.1.2 Table 8.2 GuidPrefix_t

Spec: §8.2.1.2, S. 21, Table 8.2 — “GuidPrefix_t … Must be possible to represent using 12 octets. The following values are reserved by the protocol: GUIDPREFIX_UNKNOWN”.

Repo: crates/rtps/src/wire_types.rs (GuidPrefix, GuidPrefix::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::guid_prefix_unknown_is_zero, crates/rtps/src/wire_types.rs::tests::guid_prefix_roundtrip

Status: done

§8.2.1.2 Table 8.2 EntityId_t

Spec: §8.2.1.2, S. 21, Table 8.2 — “EntityId_t … Must be possible to represent using 4 octets. The following values are reserved by the protocol: ENTITYID_UNKNOWN”.

Repo: crates/rtps/src/wire_types.rs (EntityId, EntityId::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::entity_id_unknown_is_four_zero_octets, crates/rtps/src/wire_types.rs::tests::entity_id_roundtrip

Status: done

§8.2.1.2 Table 8.2 SequenceNumber_t

Spec: §8.2.1.2, S. 21, Table 8.2 — “SequenceNumber_t … Must be possible to represent using 64 bits. The following values are reserved by the protocol: SEQUENCENUMBER_UNKNOWN”.

Repo: crates/rtps/src/wire_types.rs (SequenceNumber(i64), SequenceNumber::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::sequence_number_unknown_high_minus_one_low_zero, crates/rtps/src/wire_types.rs::tests::sequence_number_roundtrip_le, crates/rtps/src/wire_types.rs::tests::sequence_number_roundtrip_be

Status: done

§8.2.1.2 Table 8.2 Locator_t

Spec: §8.2.1.2, S. 22, Table 8.2 — “It must be possible to represent the discriminator and port number using 4 octets each, the address using 16 octets.” Reserviert: LOCATOR_INVALID, LOCATOR_KIND_INVALID, LOCATOR_KIND_RESERVED, LOCATOR_KIND_UDPv4, LOCATOR_KIND_UDPv6, LOCATOR_ADDRESS_INVALID, LOCATOR_PORT_INVALID.

Repo: crates/rtps/src/wire_types.rs (Locator, LocatorKind::{Invalid, Reserved, UdpV4, UdpV6}, Locator::INVALID, Locator::ADDRESS_INVALID, Locator::PORT_INVALID)

Tests: crates/rtps/src/wire_types.rs::tests::locator_invalid_constant_matches_spec, crates/rtps/src/wire_types.rs::tests::locator_reserved_constant_kind_is_zero, crates/rtps/src/wire_types.rs::tests::locator_udp_v4_any_kind_is_one, crates/rtps/src/wire_types.rs::tests::locator_udp_v6_any_kind_is_two, crates/rtps/src/wire_types.rs::tests::locator_roundtrip_le

Status: done — die Werte der Konstanten sind unter §9.3.2.4 geführt.

§8.2.1.2 Table 8.2 TopicKind_t

Spec: §8.2.1.2, S. 22, Table 8.2 — “Enumeration used to distinguish whether a Topic has defined some fields within to be used as the ‘key’ … NO_KEY, WITH_KEY”.

Repo: crates/rtps/src/wire_types.rs (TopicKind::{NoKey, WithKey}, EntityKind::topic_kind, TopicKind::writer_entity_kind, TopicKind::reader_entity_kind)

Tests: crates/rtps/src/wire_types.rs::tests::topic_kind_follows_entity_kind_octet_of_table_9_1, crates/rtps/src/wire_types.rs::tests::topic_kind_entity_kind_pairs_round_trip

Status: done

§8.2.1.2 Table 8.2 ChangeKind_t

Spec: §8.2.1.2, S. 22, Table 8.2 — “It can take the values: ALIVE, ALIVE_FILTERED, NOT_ALIVE_DISPOSED, NOT_ALIVE_UNREGISTERED”.

Repo: crates/rtps/src/history_cache.rs (ChangeKind::{Alive, AliveFiltered, NotAliveDisposed, NotAliveUnregistered, NotAliveDisposedUnregistered})

Tests: crates/rtps/src/history_cache.rs::tests::change_kind_distinct_variants, crates/rtps/src/history_cache.rs::tests::change_kind_alive_filtered_is_alive_but_not_relevant, crates/rtps/src/history_cache.rs::tests::change_kind_not_alive_kinds_are_not_alive

Status: done — NotAliveDisposedUnregistered ist eine zusätzliche Kombination für PID_STATUS_INFO mit beiden Bits.

§8.2.1.2 Table 8.2 ChangeCount_t

Spec: §8.2.1.2, S. 22, Table 8.2 — “Type used to hold a counter representing the number of HistoryCache changes that belong to a certain category.”

Repo: crates/rtps/src/submessages.rs (GapSubmessage::filtered_count, Option<u64>)

Tests: crates/rtps/src/submessages.rs::tests::gap_filtered_count_is_eight_octets_high_then_low, crates/rtps/src/submessages.rs::tests::gap_with_filtered_count_roundtrip_le

Status: done — der Zähler ist 64 Bit breit (high, low; acht Oktette, §9.3.2.11).

§8.2.1.2 Table 8.2 ReliabilityKind_t

Spec: §8.2.1.2, S. 22, Table 8.2 — “Enumeration used to indicate the level of the reliability used for communications. It can take the values: BEST_EFFORT, RELIABLE.”

Repo: crates/qos/src/policies/reliability.rs (ReliabilityKind::{BestEffort, Reliable})

Tests: crates/qos/src/policies/reliability.rs::tests::try_from_u32_is_strict, crates/qos/src/policies/reliability.rs::tests::best_effort_lt_reliable

Status: done

§8.2.1.2 Table 8.2 InstanceHandle_t

Spec: §8.2.1.2, S. 22, Table 8.2 — “Type used to represent the identity of a data-object whose changes in value are communicated by the RTPS protocol.”

Repo: crates/rtps/src/history_cache.rs (CacheChange::key_hash); crates/dcps/src/instance_handle.rs (InstanceHandle)

Tests: crates/dcps/src/instance_handle.rs::tests::from_guid_distinguishes_keys, crates/rtps/src/history_cache.rs::tests::keep_last_per_instance_keeps_the_newest_of_each_instance

Status: done — auf RTPS-Ebene trägt der KeyHash (§9.6.4.8) die Instanz-Identität.

§8.2.1.2 Table 8.2 ProtocolVersion_t

Spec: §8.2.1.2, S. 22, Table 8.2 — reserviert PROTOCOLVERSION, PROTOCOLVERSION_1_0, _1_1, _2_0, _2_1, _2_2, _2_4; “PROTOCOLVERSION is an alias for the most recent version, in this case PROTOCOLVERSION_2_4”.

Repo: crates/rtps/src/wire_types.rs (ProtocolVersion::{V1_0, V1_1, V2_0, V2_1, V2_2, V2_3, V2_4, V2_5, CURRENT})

Tests: crates/rtps/src/wire_types.rs::tests::protocol_version_aliases_match_spec, crates/rtps/src/wire_types.rs::tests::protocol_version_all_aliases_roundtrip, crates/rtps/src/wire_types.rs::tests::protocol_version_default_is_2_5

Status: done — CURRENT ist 2.5 nach §8.3.3.1 („protocol version 2.5“); die Angabe „in this case PROTOCOLVERSION_2_4“ in Table 8.2 widerspricht §8.3.3.1.

§8.2.1.2 Table 8.2 VendorId_t

Spec: §8.2.1.2, S. 22, Table 8.2 — “The possible values for the vendorId are assigned by the OMG. The following values are reserved by the protocol: VENDORID_UNKNOWN”.

Repo: crates/rtps/src/wire_types.rs (VendorId, VendorId::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::vendor_id_unknown_is_two_zero_octets, crates/rtps/src/wire_types.rs::tests::vendor_id_roundtrip

Status: done — der von ZeroDDS gesendete Wert ist unter §8.3.3.1 (vendorId) geführt.

§8.2.1.3 Configuration attributes of the RTPS Entities

Spec: §8.2.1.3, S. 23, Figure 8.2 — Konfigurationsattribute der Entities; Writer- und Reader-Attribute folgen in §8.4.

Repo: —

Tests: —

Status: n/a (informative) — Übersicht; die Attribute sind in Table 8.8, Table 8.9 und §8.4.7/§8.4.10 je einzeln geführt.

§8.2.2 HistoryCache: Rolle auf Writer- und Reader-Seite

Spec: §8.2.2, S. 23 — Writer-Seite: “the partial history of changes … needed to service existing and future matched RTPS Reader endpoints”; Reader-Seite: “the partial superposition of changes to data-objects made by all the matched RTPS Writer endpoints”.

Repo: crates/rtps/src/history_cache.rs (HistoryCache); crates/rtps/src/reliable_writer.rs (ReliableWriter, Feld cache); crates/rtps/src/reliable_reader.rs (ReliableReader)

Tests: crates/rtps/src/reliable_writer.rs::tests::keep_last_evicts_oldest_on_overflow, crates/rtps/src/reliable_reader.rs::tests::two_writers_with_overlapping_sn_spaces_both_delivered

Status: done

§8.2.2 Table 8.3 HistoryCache::changes

Spec: §8.2.2, S. 24, Table 8.3 — “changes: CacheChange[*] — The list of CacheChanges contained in the HistoryCache.”

Repo: crates/rtps/src/history_cache.rs (HistoryCache, get, iter_range, len)

Tests: crates/rtps/src/history_cache.rs::tests::insert_and_get, crates/rtps/src/history_cache.rs::tests::iter_range_is_ordered

Status: done

§8.2.2.1 HistoryCache new

Spec: §8.2.2.1, S. 25 — “This operation creates a new RTPS HistoryCache. The newly-created history cache is initialized with an empty list of changes.”

Repo: crates/rtps/src/history_cache.rs (HistoryCache::new, HistoryCache::new_with_kind)

Tests: crates/rtps/src/history_cache.rs::tests::new_cache_is_empty

Status: done

§8.2.2.2 HistoryCache add_change

Spec: §8.2.2.2, S. 25 — “This operation inserts the CacheChange a_change into the HistoryCache. This operation will only fail if there are not enough resources to add the change to the HistoryCache.”

Repo: crates/rtps/src/history_cache.rs (HistoryCache::insert, HistoryCache::insert_returning_evicted, CacheError)

Tests: crates/rtps/src/history_cache.rs::tests::insert_and_get, crates/rtps/src/history_cache.rs::tests::insert_at_capacity_is_err, crates/rtps/src/history_cache.rs::tests::insert_duplicate_is_err

Status: done — insert weist zusätzlich eine bereits belegte Sequenznummer ab; nach außen nicht sichtbar, da Writer jede Nummer nur einmal vergeben.

§8.2.2.2 RESOURCE_LIMITS und Fehlerweitergabe an den DDS-Nutzer

Spec: §8.2.2.2, S. 25 — “It is the responsibility of the DDS service implementation to configure the HistoryCache in a manner consistent with the DDS Entity RESOURCE_LIMITS QoS and to propagate any errors to the DDS-user in the manner specified by the DDS specification.”

Repo: crates/dcps/src/runtime.rs (await_writer_room); crates/rtps/src/history_cache.rs (HistoryKind, HistoryCache::set_per_instance_depth)

Tests: crates/dcps/tests/reader_history_resource_limits.rs::a_writer_refuses_an_instance_beyond_its_own_max_instances, crates/dcps/tests/reader_history_resource_limits.rs::keep_all_max_samples_total_rejects_when_reliable, crates/dcps/tests/reader_room_backpressure.rs::a_full_keep_all_reader_blocks_its_writer_and_loses_nothing

Status: done

§8.2.2.3 HistoryCache remove_change

Spec: §8.2.2.3, S. 25 — “This operation indicates that a previously-added CacheChange should be removed from the HistoryCache … The determination of which changes should be removed from the cache is made based on the QoS associated with the related DDS entity and on the acknowledgment status of the CacheChange.”

Repo: crates/rtps/src/history_cache.rs (HistoryCache::remove_up_to, remove_up_to_with, remove_highest); crates/rtps/src/reliable_writer.rs (ReliableWriter::remove_samples_up_to)

Tests: crates/rtps/src/history_cache.rs::tests::remove_up_to_inclusive, crates/rtps/src/history_cache.rs::tests::remove_up_to_with_no_matches_is_noop, crates/rtps/src/reliable_writer.rs::tests::the_unacked_window_fills_and_acknowledgements_free_it

Status: done

§8.2.2.4 HistoryCache get_seq_num_min

Spec: §8.2.2.4, S. 25 — “This operation retrieves the smallest value of the CacheChange::sequenceNumber attribute among the CacheChange stored in the HistoryCache.”

Repo: crates/rtps/src/history_cache.rs (HistoryCache::min_sn)

Tests: crates/rtps/src/history_cache.rs::tests::min_max_sn_reflect_content

Status: done

§8.2.2.5 HistoryCache get_seq_num_max

Spec: §8.2.2.5, S. 25 — “This operation retrieves the largest value of the CacheChange::sequenceNumber attribute among the CacheChange stored in the HistoryCache.”

Repo: crates/rtps/src/history_cache.rs (HistoryCache::max_sn)

Tests: crates/rtps/src/history_cache.rs::tests::min_max_sn_reflect_content

Status: done

§8.2.3 Table 8.5 CacheChange::kind

Spec: §8.2.3, S. 26, Table 8.5 — “kind: ChangeKind_t — Identifies the kind of change.”

Repo: crates/rtps/src/history_cache.rs (CacheChange::kind); crates/rtps/src/reliable_reader.rs (DeliveredSample::kind)

Tests: crates/rtps/src/history_cache.rs::tests::cache_change_alive_constructor, crates/rtps/src/reliable_reader.rs::tests::dispose_data_yields_not_alive_disposed, crates/rtps/src/reliable_reader.rs::tests::unregister_data_yields_not_alive_unregistered

Status: done

§8.2.3 Table 8.5 CacheChange::writerGuid

Spec: §8.2.3, S. 26, Table 8.5 — “writerGuid: GUID_t — The GUID_t that identifies the RTPS Writer that made the change”.

Repo: crates/rtps/src/reliable_reader.rs (DeliveredSample::writer_guid); Writer-Seite implizit, je Writer ein eigener HistoryCache.

Tests: crates/rtps/src/reliable_reader.rs::tests::two_writers_with_overlapping_sn_spaces_both_delivered, crates/rtps/src/reliable_reader.rs::tests::same_entity_id_different_prefix_not_confused

Status: done

§8.2.3 Table 8.5 CacheChange::instanceHandle

Spec: §8.2.3, S. 26, Table 8.5 — “instanceHandle: InstanceHandle_t — Identifies the instance of the data-object to which the change applies.”

Repo: crates/rtps/src/history_cache.rs (CacheChange::key_hash); crates/rtps/src/reliable_reader.rs (DeliveredSample::key_hash)

Tests: crates/rtps/src/history_cache.rs::tests::the_instance_index_follows_inserts_evictions_and_removals, crates/rtps/src/reliable_writer.rs::tests::keyed_alive_preserves_inline_hash_on_data_fragments_and_rebuilds

Status: done

§8.2.3 Table 8.5 CacheChange::sequenceNumber

Spec: §8.2.3, S. 26, Table 8.5 — “sequenceNumber: SequenceNumber_t — Sequence number assigned by the RTPS Writer to uniquely identify the change.”

Repo: crates/rtps/src/history_cache.rs (CacheChange::sequence_number)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_increments_sn_and_returns_data_datagram, crates/rtps/src/writer.rs::tests::writer_increments_sequence_number_per_write

Status: done

§8.2.3 Table 8.5 CacheChange::data_value

Spec: §8.2.3, S. 26, Table 8.5 — “data_value: Data — The data value associated with the change. Depending on the kind of CacheChange, there may be no associated data.”

Repo: crates/rtps/src/history_cache.rs (CacheChange::payload, CacheChange::lifecycle)

Tests: crates/rtps/src/history_cache.rs::tests::cache_change_alive_constructor, crates/rtps/src/reliable_writer.rs::tests::lifecycle_without_a_key_clears_k_and_sends_no_payload

Status: done

§8.2.3 Table 8.5 CacheChange::inlineQos

Spec: §8.2.3, S. 26, Table 8.5 — “inlineQos: ParameterList — Contains QoS that may affect the interpretation of the CacheChange::data_value.”

Repo: crates/rtps/src/history_cache.rs (CacheChange::inline_qos, CacheChange::with_inline_qos); Reader-Seite: crates/rtps/src/reliable_reader.rs (DeliveredSample mit den ausgewerteten Parametern key_hash, coherent_set_sn, related_sample_identity)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_reader_that_expects_inline_qos_gets_the_writers_qos_with_each_data, crates/rtps/src/reliable_reader.rs::tests::delivered_sample_carries_the_coherent_set_marker

Status: done

§8.2.4 Table 8.6 Entity::guid

Spec: §8.2.4, S. 26, Table 8.6 — “guid: GUID_t — Globally and uniquely identifies the RTPS Entity within the DDS domain. Maps to the value of the DDS BuiltinTopicKey_t”.

Repo: crates/rtps/src/wire_types.rs (Guid); crates/dcps/src/builtin_topics.rs (Schlüssel der Builtin-Topic-Daten)

Tests: crates/rtps/src/wire_types.rs::tests::guid_layout_is_prefix_then_entity_id, crates/dcps/src/instance_handle.rs::tests::from_guid_distinguishes_keys

Status: done

§8.2.4.1 Table 8.7 GUID = <prefix, entityId>

Spec: §8.2.4.1, S. 26–27, Table 8.7 — “The GUID is built as a tuple <prefix, entityId> combining a GuidPrefix_t prefix and an EntityId_t entityId.”

Repo: crates/rtps/src/wire_types.rs (Guid::new, Guid::to_bytes)

Tests: crates/rtps/src/wire_types.rs::tests::guid_layout_is_prefix_then_entity_id

Status: done

§8.2.4.2 Participant-GUID <prefix, ENTITYID_PARTICIPANT>

Spec: §8.2.4.2, S. 27 — “Every Participant has GUID <prefix, ENTITYID_PARTICIPANT>”.

Repo: crates/rtps/src/wire_types.rs (EntityId::PARTICIPANT); crates/dcps/src/participant.rs (random_guid_prefix)

Tests: crates/rtps/src/wire_types.rs::tests::entity_id_participant_constant, crates/dcps/src/participant.rs::tests::random_guid_prefixes_share_host_id_within_process

Status: done

§8.2.4.2 Prefix eindeutig in der Domain

Spec: §8.2.4.2, S. 27 — “The implementation is free to choose the prefix, as long as every Participant in the Domain has a unique GUID.”

Repo: crates/dcps/src/participant.rs (next_process_unique, namespaced_pid, process_unique); crates/dcps/src/runtime.rs (DcpsRuntime::prefix_collisions)

Tests: crates/dcps/src/participant.rs::tests::the_prefixes_of_one_process_are_pairwise_different, crates/dcps/src/participant.rs::tests::two_pid_namespaces_with_the_same_pid_give_different_prefixes, crates/dcps/src/runtime.rs::tests::a_beacon_with_the_own_prefix_from_another_participant_is_counted

Status: done — die Prefixe der Participants eines Prozesses sind paarweise verschieden (Zähler des Prozesses, 65536 je Prozess, auch für die C-API und die Brücken); über Prozesse und Hosts hinweg verhindert die Konstruktion die Kollision (Item „Eindeutigkeit des Prefix über Hosts und Prozesse“).

§8.2.4.2 Eindeutigkeit des Prefix über Hosts und Prozesse

Spec: §8.2.4.2, S. 27 — “every Participant in the Domain has a unique GUID”.

Repo: crates/dcps/src/participant.rs (namespaced_pid, pid_namespace_inode, next_process_unique, process_unique); crates/dcps/src/runtime.rs (DcpsRuntime::prefix_collisions, same_process)

Tests: crates/dcps/src/participant.rs::tests::two_pid_namespaces_with_the_same_pid_give_different_prefixes, crates/dcps/src/participant.rs::tests::the_prefixes_of_one_process_share_ten_octets_and_differ_in_the_tail, crates/dcps/src/participant.rs::tests::random_guid_prefixes_share_host_id_within_process, crates/dcps/src/runtime.rs::tests::a_beacon_with_the_own_prefix_from_another_participant_is_counted

Status: done — der Prefix besteht aus der VendorId, dem Host-Kennwert (4 Oktette), der Prozess-ID und einem Prozessanteil (Startwert aus der Zufallsquelle des Betriebssystems plus Zähler des Prozesses). Die Prozess-ID trägt die Marke des PID-Namensraums (namespaced_pid: XOR mit einer Maske aus dem Inode von /proc/self/ns/pid, im Ausgangs-Namensraum null, innerhalb eines Namensraums umkehrbar eindeutig). Container mit dem Netz des Hosts (gleicher Host-Kennwert) und eigenem PID-Namensraum, deren erster Prozess die Nummer 1 hat, tragen dadurch verschiedene Prefixe. same_process (erste zehn Oktette) und same_host (Host-Kennwert) lesen unverändert. Verbleibende Kollision: zwei verschiedene Hostnamen mit gleichem 32-Bit-Hash, gleicher markierter Prozess-ID und gleichem Prozessanteil; DcpsRuntime::prefix_collisions zählt einen SPDP-Beacon mit dem eigenen Prefix und fremden Locatoren.

§8.2.4.3 GUID einer Endpoint-Gruppe

Spec: §8.2.4.3, S. 27 — “The endpoint Groups contained by a Participant with GUID <participantPrefix, ENTITYID_PARTICIPANT> have the GUID <participantPrefix, entityId>. The entityId is the unique identification of the Group relative to the Participant.”

Repo: crates/dcps/src/publisher.rs (PublisherInner::entity_id), crates/dcps/src/subscriber.rs (SubscriberInner::entity_id), crates/dcps/src/runtime.rs (build_publication_data, build_subscription_data: group_guid)

Tests: crates/rtps/src/publication_data.rs::tests::the_writers_group_travels_as_pid_group_guid, crates/rtps/src/wire_types.rs::tests::every_kind_table_9_1_names_decodes_to_a_named_kind

Status: done

§8.2.4.4 GUID der Endpoints eines Participants

Spec: §8.2.4.4, S. 27 — “The Endpoints contained by a Participant with GUID <participantPrefix, ENTITYID_PARTICIPANT> have the GUID <participantPrefix, entityId>. The entityId is the unique identification of the Endpoint relative to the Participant.”

Repo: crates/dcps/src/runtime.rs (next_entity_key, entity_key_in_use, held_entity_keys, release_entity_key); crates/dcps/src/publisher.rs, crates/dcps/src/subscriber.rs (Drop der Inner-Typen)

Tests: crates/dcps/src/runtime.rs::tests::a_wrapped_entity_key_counter_skips_the_key_of_a_live_writer, crates/dcps/src/runtime.rs::tests::a_wrapped_entity_key_counter_skips_reserved_and_group_keys_until_they_are_given_back

Status: done — der 3-Oktett-Schlüssel kommt aus einem Zähler; nach dem Umlauf der 24 Bit wird ein Schlüssel übersprungen, den ein registrierter Writer, Reader, ein angekündigtes Topic, eine reservierte, noch nicht registrierte Id oder eine Gruppen-Id (Publisher, Subscriber) hält; ein zurückgegebener Schlüssel ist wieder frei.

§8.2.5 Table 8.8 Participant::defaultUnicastLocatorList

Spec: §8.2.5, S. 28, Table 8.8 — “Default list of unicast locators … These are the unicast locators that will be used in case the Endpoint does not specify its own set of Locators.”

Repo: crates/rtps/src/participant_data.rs (ParticipantBuiltinTopicData::default_unicast_locators)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done — der Rückgriff des Endpoints auf die Default-Locatoren ist unter §8.5.5.1 geführt.

§8.2.5 Table 8.8 Participant::defaultMulticastLocatorList

Spec: §8.2.5, S. 28, Table 8.8 — “Default list of multicast locators … used in case the Endpoint does not specify its own set of Locators.”

Repo: crates/rtps/src/participant_data.rs (ParticipantBuiltinTopicData::default_multicast_locators)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§8.2.5 Table 8.8 Participant::protocolVersion

Spec: §8.2.5, S. 28, Table 8.8 — “protocolVersion: ProtocolVersion_t — Identifies the version of the RTPS protocol that the Participant uses to communicate.”

Repo: crates/rtps/src/participant_data.rs (ParticipantBuiltinTopicData::protocol_version); crates/rtps/src/header.rs (RtpsHeader::new)

Tests: crates/rtps/src/header.rs::tests::header_protocol_version_at_bytes_4_5, crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§8.2.5 Table 8.8 Participant::vendorId

Spec: §8.2.5, S. 28, Table 8.8 — “vendorId: VendorId_t — Identifies the vendor of the RTPS middleware that contains the Participant.”

Repo: crates/rtps/src/participant_data.rs (ParticipantBuiltinTopicData::vendor_id); crates/rtps/src/header.rs

Tests: crates/rtps/src/header.rs::tests::header_vendor_id_at_bytes_6_7, crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§8.2.6 RTPS Group: Publisher enthält Writer, Subscriber enthält Reader

Spec: §8.2.6, S. 28–29 — “The RTPS Publisher contains RTPS Writer endpoints. The RTPS Publisher maps to a DDS Publisher. The RTPS Subscriber contains RTPS Reader endpoints. The RTPS Subscriber maps to a DDS Subscriber.”

Repo: crates/dcps/src/publisher.rs (Publisher::create_datawriter); crates/dcps/src/subscriber.rs (Subscriber::create_datareader)

Tests: crates/dcps/tests/entity_deletion.rs::a_writer_of_another_publisher_is_left_as_it_was, crates/dcps/tests/entity_deletion.rs::a_reader_of_another_subscriber_is_left_as_it_was, crates/dcps/tests/entity_deletion.rs::publisher_delete_contained_entities_deletes_every_writer

Status: done — die GUID der Gruppe ist unter §8.2.4.3 geführt.

§8.2.7 Table 8.9 Endpoint::unicastLocatorList

Spec: §8.2.7, S. 29, Table 8.9 — “List of unicast locators … that can be used to send messages to the Endpoint. The list may be empty.”

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::unicast_locators); crates/rtps/src/subscription_data.rs (SubscriptionBuiltinTopicData::unicast_locators)

Tests: crates/rtps/src/publication_data.rs::tests::endpoint_locators_roundtrip_le

Status: done — die Reader-Seite nutzt dieselben Hilfsfunktionen (encode_locator_params, collect_locator_params); ihr Test steht unter §8.5.4.4.

§8.2.7 Table 8.9 Endpoint::multicastLocatorList

Spec: §8.2.7, S. 29, Table 8.9 — “List of multicast locators … that can be used to send messages to the Endpoint. The list may be empty.”

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::multicast_locators); crates/rtps/src/subscription_data.rs (SubscriptionBuiltinTopicData::multicast_locators)

Tests: crates/rtps/src/publication_data.rs::tests::endpoint_locators_roundtrip_le

Status: done — die Reader-Seite nutzt dieselben Hilfsfunktionen; ihr Test steht unter §8.5.4.4.

§8.2.7 Table 8.9 Endpoint::reliabilityLevel

Spec: §8.2.7, S. 29, Table 8.9 — “reliabilityLevel: ReliabilityKind_t — The levels of reliability supported by the Endpoint. Maps to the RELIABILITY QoS ‘kind.’”

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::reliability); crates/rtps/src/writer.rs (BestEffortWriter); crates/rtps/src/reliable_writer.rs (ReliableWriter)

Tests: crates/rtps/src/publication_data.rs::tests::roundtrip_le, crates/rtps/src/reliable_reader.rs::tests::best_effort_reader_skips_leading_gap

Status: done

§8.2.7 Table 8.9 Endpoint::topicKind

Spec: §8.2.7, S. 29, Table 8.9 — “topicKind: TopicKind_t — Used to indicate whether the Endpoint supports instance lifecycle management operations (see 8.7.4).”

Repo: crates/rtps/src/wire_types.rs (EntityKind::topic_kind); crates/dcps/src/publisher.rs (Wahl der entityKind aus DdsType::HAS_KEY)

Tests: crates/dcps/src/publisher.rs::tests::live_datawriter_entity_kind_is_nokey_for_keyless_type, crates/rtps/src/wire_types.rs::tests::topic_kind_of_the_predefined_entity_ids

Status: done

§8.2.7 Table 8.9 Endpoint::endpointGroup

Spec: §8.2.7, S. 29, Table 8.9 — “endpointGroup: EntityId_t — Used to identify the RTPS Group (Publisher or Subscriber) to which the Endpoint belongs.”

Repo: crates/dcps/src/runtime.rs (UserWriterConfig::group_entity_id, UserReaderConfig::group_entity_id)

Tests: crates/rtps/src/publication_data.rs::tests::the_writers_group_travels_as_pid_group_guid

Status: done

§8.2.8 RTPS Writer gehört zu einem Publisher

Spec: §8.2.8, S. 29–30 — “Its role is to transfer all CacheChange changes in its HistoryCache to the HistoryCache of the matching remote RTPS Readers. An RTPS Writer belongs to an RTPS Group of type Publisher.”

Repo: crates/dcps/src/publisher.rs (Publisher::create_datawriter); crates/rtps/src/reliable_writer.rs (ReliableWriter)

Tests: crates/dcps/tests/entity_deletion.rs::delete_publisher_refuses_a_publisher_with_writers, crates/rtps/tests/reliable_e2e.rs::e2e_zero_loss_delivers_all_in_order

Status: done

§8.2.9 RTPS Reader gehört zu einem Subscriber

Spec: §8.2.9, S. 30 — “RTPS Reader specializes RTPS Endpoint and represents the actor that receives CacheChange messages from the matched RTPS Writer endpoints. An RTPS Reader belongs to an RTPS Group of type Subscriber.”

Repo: crates/dcps/src/subscriber.rs (Subscriber::create_datareader); crates/rtps/src/reliable_reader.rs (ReliableReader)

Tests: crates/dcps/tests/entity_deletion.rs::a_reader_of_another_subscriber_is_left_as_it_was, crates/rtps/tests/reliable_e2e.rs::e2e_10_percent_loss_delivers_all_in_order

Status: done

§8.2.10 Relation to DDS Entities

Spec: §8.2.10, S. 30 — “How exactly a DDS Entity interacts with the HistoryCache however, is implementation specific and not formally modeled by the RTPS protocol.”

Repo: —

Tests: —

Status: n/a (informative) — erläutert die Übergänge; diese sind unter §8.2.10.1 und §8.2.10.2 einzeln geführt.

§8.2.10.1 DataWriter: alle Changes für jeden Reader relevant

Spec: §8.2.10.1, S. 30–31 — “By default, all changes in the HistoryCache are considered relevant for each matching remote RTPS Reader. … The Reader itself will always filter.”

Repo: crates/rtps/src/reliable_writer.rs (ReliableWriter::write, Auslieferung an alle ReaderProxy)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_fans_out_to_all_reader_proxies

Status: done — der Reader-seitige Filter ist unter §8.7.3 geführt.

§8.2.10.1 Table 8.11 DataWriter T1 (new DDS DataWriter)

Spec: §8.2.10.1, S. 32, Table 8.11 T1 — “the_rtps_writer = new RTPS::Writer; the_dds_writer.related_rtps_writer := the_rtps_writer;”

Repo: crates/dcps/src/publisher.rs (Publisher::create_datawriter); crates/dcps/src/runtime.rs (register_user_writer_as)

Tests: crates/dcps/src/publisher.rs::tests::live_datawriter_entity_kind_is_nokey_for_keyless_type, crates/dcps/tests/entity_lifecycle.rs::datawriter_and_datareader_follow_their_factories_entity_factory_policy

Status: done

§8.2.10.1 Table 8.11 DataWriter T2 (write)

Spec: §8.2.10.1, S. 32, Table 8.11 T2 — “a_change := the_rtps_writer.new_change(ALIVE, data, inlineQos, handle); the_rtps_writer.writer_cache.add_change(a_change);” Nachbedingung “the_rtps_writer.writer_cache.get_seq_num_max() == a_change.sequenceNumber”.

Repo: crates/dcps/src/publisher.rs (DataWriter::write); crates/rtps/src/reliable_writer.rs (ReliableWriter::write)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_increments_sn_and_returns_data_datagram, crates/rtps/src/reliable_writer.rs::tests::heartbeat_carries_cache_range

Status: done

§8.2.10.1 Table 8.11 DataWriter T3 (dispose, WITH_KEY)

Spec: §8.2.10.1, S. 32 — “if (the_rtps_writer.topicKind == WITH_KEY) { a_change := the_rtps_writer.new_change(NOT_ALIVE_DISPOSED, , inlineQos, handle); the_rtps_writer.writer_cache.add_change(a_change); }”

Repo: crates/dcps/src/publisher.rs (DataWriter::dispose_w_timestamp); crates/dcps/src/runtime.rs (write_user_lifecycle); crates/rtps/src/reliable_writer.rs (ReliableWriter::write_lifecycle)

Tests: crates/dcps/tests/lifecycle_wire_e2e.rs::linux::dispose_propagates_over_wire_to_reader, crates/rtps/src/reliable_writer.rs::tests::lifecycle_with_a_key_sets_k_and_carries_it

Status: done

§8.2.10.1 Table 8.11 DataWriter T4 (unregister, WITH_KEY)

Spec: §8.2.10.1, S. 33 — “if (the_rtps_writer.topicKind == WITH_KEY) { a_change := the_rtps_writer.new_change(NOT_ALIVE_UNREGISTERED, , inlineQos, handle); the_rtps_writer.writer_cache.add_change(a_change); }”

Repo: crates/dcps/src/publisher.rs (DataWriter::unregister_instance_w_timestamp); crates/dcps/src/runtime.rs (write_user_lifecycle)

Tests: crates/dcps/tests/lifecycle_wire_e2e.rs::linux::unregister_with_autodispose_false_propagates_unregister_only, crates/rtps/src/reliable_reader.rs::tests::unregister_data_yields_not_alive_unregistered

Status: done

§8.2.10.1 T3/T4 ohne Wirkung bei NO_KEY

Spec: §8.2.10.1, S. 32–33 — dispose und unregister: “This operation has no effect if the topicKind==NO_KEY.”

Repo: crates/dcps/src/runtime.rs (write_user_lifecycle_with, keyless_lifecycle_not_sent); writer.keyless_lifecycle_on_wire

Tests: crates/dcps/src/runtime.rs::tests::dispose_and_unregister_of_a_no_key_writer_send_no_marker_unless_asked_for, crates/dcps/tests/runtime_config_layering.rs::the_heartbeat_digest_and_keyless_lifecycle_settings_are_read_from_yaml, crates/dcps/tests/keyless_instance.rs::the_writer_disposes_the_one_instance_of_a_keyless_topic

Status: done — dispose und unregister eines Writers ohne Schlüssel erzeugen keinen Change und senden keinen Marker (gezählt in DcpsRuntime::keyless_lifecycle_not_sent); der Instanzzustand des Writers selbst ändert sich (DDS 1.4 §2.2.1.2.2: eine Instanz). writer.keyless_lifecycle_on_wire (Umgebung ZERODDS_WRITER_KEYLESS_LIFECYCLE_ON_WIRE) sendet den Marker (nur Status-Bits) für einen Peer, der ihn erwartet. Erwartet bei den Herstellern: Reader von Topics ohne Schlüssel sehen kein NOT_ALIVE_DISPOSED der ZeroDDS-Writer mehr; ob Cyclone DDS, Fast DDS oder OpenDDS selbst einen Marker für NO_KEY senden, ist nicht gemessen.

§8.2.10.1 Table 8.11 DataWriter T5 (delete DDS DataWriter)

Spec: §8.2.10.1, S. 33 — “delete the_dds_writer.related_rtps_writer;”

Repo: crates/dcps/src/publisher.rs (Publisher::delete_datawriter)

Tests: crates/dcps/tests/entity_deletion.rs::delete_datawriter_deletes_the_writer_behind_every_handle, crates/dcps/tests/entity_deletion.rs::the_last_handle_deletes_the_writer

Status: done

§8.2.10.2 DataReader: read und take greifen auf den HistoryCache zu

Spec: §8.2.10.2, S. 33 — “The changes returned to the user are those in the HistoryCache that pass all Reader specific filters, if any.”

Repo: crates/dcps/src/subscriber.rs (DataReader::read, DataReader::take)

Tests: crates/dcps/tests/sample_info_lifecycle.rs::reader_take_filtered_with_state_mask_filters

Status: done

§8.2.10.2 Table 8.12 DataReader T1 (new DDS DataReader)

Spec: §8.2.10.2, S. 34, Table 8.12 T1 — “the_rtps_reader = new RTPS::Reader; the_dds_reader.related_rtps_reader := the_rtps_reader;”

Repo: crates/dcps/src/subscriber.rs (Subscriber::create_datareader); crates/dcps/src/runtime.rs (register_user_reader)

Tests: crates/dcps/tests/entity_lifecycle.rs::datawriter_and_datareader_follow_their_factories_entity_factory_policy

Status: done

§8.2.10.2 Table 8.12 DataReader T2 (read)

Spec: §8.2.10.2, S. 34 — “Changes returned to the application remain in the RTPS Reader’s HistoryCache such that subsequent read or take operations can find them again.”

Repo: crates/dcps/src/subscriber.rs (DataReader::read, DataReader::read_with_info)

Tests: crates/dcps/tests/sample_info_lifecycle.rs::reader_read_marks_sample_state_read, crates/dcps/tests/reader_history_resource_limits.rs::plain_read_keep_last_1_keeps_only_the_newest_per_instance_and_is_idempotent

Status: done

§8.2.10.2 Table 8.12 DataReader T3 (take)

Spec: §8.2.10.2, S. 34–35 — “Changes returned to the application are removed from the RTPS Reader’s HistoryCache such that subsequent read or take operations do not find the same change.”

Repo: crates/dcps/src/subscriber.rs (DataReader::take, DataReader::take_with_info)

Tests: crates/dcps/tests/sample_info_lifecycle.rs::reader_take_next_instance_consumes, crates/dcps/tests/sample_info_lifecycle.rs::reader_view_state_transitions_to_not_new_on_second_sample

Status: done

§8.2.10.2 Table 8.12 DataReader T4 (delete DDS DataReader)

Spec: §8.2.10.2, S. 35 — “delete the_dds_reader.related_rtps_reader;”

Repo: crates/dcps/src/subscriber.rs (Subscriber::delete_datareader)

Tests: crates/dcps/tests/entity_deletion.rs::delete_datareader_refuses_a_reader_that_holds_conditions, crates/dcps/tests/entity_deletion.rs::lookup_datareader_hands_out_a_handle_to_the_same_reader

Status: done


§8.3 Messages Module

§8.3.1 Overview

Spec: §8.3.1, S. 35 — Gliederung des Moduls; “The number of Submessages that can be sent in a single RTPS Message is only limited by the maximum message size the underlying transport can support.”

Repo: —

Tests: —

Status: n/a (informative) — Gliederung; die Anforderungen folgen in §8.3.2–§8.3.8.

§8.3.2 Table 8.13 ProtocolId_t (PROTOCOL_RTPS)

Spec: §8.3.2, S. 35, Table 8.13 — “ProtocolId_t: Enumeration used to identify the protocol. The following values are reserved by the protocol: PROTOCOL_RTPS”.

Repo: crates/rtps/src/header.rs (RTPS_MAGIC)

Tests: crates/rtps/src/header.rs::tests::header_layout_first_four_bytes_are_rtps_magic, crates/rtps/src/header.rs::tests::header_decode_rejects_invalid_magic

Status: done

§8.3.2 Table 8.13 SubmessageFlag

Spec: §8.3.2, S. 35, Table 8.13 — “A Submessage flag takes a boolean value and affects the parsing of the Submessage by the receiver.”

Repo: crates/rtps/src/submessage_header.rs (SubmessageHeader::flags, FLAG_E_LITTLE_ENDIAN); Flag-Konstanten in crates/rtps/src/submessages.rs

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_header_is_little_endian_flag, crates/rtps/src/datagram.rs::tests::decode_heartbeat_preserves_final_and_liveliness_flags

Status: done

§8.3.2 Table 8.13 SubmessageKind

Spec: §8.3.2, S. 36, Table 8.13 — reserviert “RTPS_HE, DATA, GAP, HEARTBEAT, ACKNACK, PAD, INFO_TS, INFO_REPLY, INFO_DST, INFO_SRC, DATA_FRAG, NACK_FRAG, HEARTBEAT_FRAG”.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId); crates/rtps/src/header_extension.rs (SUBMESSAGE_ID_HEADER_EXTENSION)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_octets_match_spec_table_8_13, crates/rtps/tests/cyclone_he_must_understand.rs::local_encoder_produces_must_understand_bit, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.2 Table 8.13 Time_t

Spec: §8.3.2, S. 36, Table 8.13 — “Type used to hold a timestamp. Should have at least nano-second resolution. The following values are reserved by the protocol: TIME_ZERO, TIME_INVALID, TIME_INFINITE”.

Repo: crates/rtps/src/header_extension.rs (HeTimestamp, TIME_INVALID, TIME_INFINITE); crates/dcps/src/time.rs

Tests: crates/rtps/src/submessages.rs::validity_tests::time_t_seconds_are_unsigned, crates/dcps/src/time.rs::tests::the_reserved_time_t_values_cross_the_wire_as_the_spec_gives_them

Status: done — seconds ist vorzeichenlos (u32, §9.3.2.1), die drei reservierten Werte TIME_ZERO, TIME_INVALID und TIME_INFINITE sind Konstanten und gehen mit den Werten der Spec auf die Leitung. Das DCPS-Time zählt Sekunden als long; die Oktette sind dieselben.

§8.3.2 Table 8.13 Count_t

Spec: §8.3.2, S. 36, Table 8.13 — “Type used to hold a count that is incremented monotonically, used to identify message duplicates.”

Repo: crates/rtps/src/submessages.rs (HeartbeatSubmessage::count, AckNackSubmessage::count, HeartbeatFragSubmessage::count, NackFragSubmessage::count, jeweils i32)

Tests: crates/rtps/src/reliable_writer.rs::tests::heartbeat_count_increments, crates/rtps/src/reliable_writer.rs::tests::heartbeat_count_wraps_around_at_i32_max_per_spec_8_4_15_7

Status: done — die Auswertung des Zählers beim Empfänger ist unter §8.3.8.1, §8.3.8.6 und §8.4.15.7 geführt.

§8.3.2 Table 8.13 Checksum_t

Spec: §8.3.2, S. 36, Table 8.13 — “Type used to hold a checksum. Used to detect RTPS message corruption by the underlying transport. The following values are reserved by the protocol: CHECKSUM_INVALID.”

Repo: crates/rtps/src/header_extension.rs (ChecksumValue::{None, Crc32c, Crc64, Md5})

Tests: crates/rtps/src/header_extension.rs::tests::checksum_value_kind_matches, crates/rtps/src/header_extension.rs::tests::checksum_kind_wire_size

Status: done — ChecksumValue::None steht für CHECKSUM_INVALID.

§8.3.2 Table 8.13 MessageLength_t

Spec: §8.3.2, S. 36, Table 8.13 — “Type used to hold the length of an RTPS Message. The following values are reserved by the protocol: MESSAGE_LENGTH_INVALID”.

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::message_length: Option<u32>); crates/rtps/src/receiver_state.rs (ReceiverState::message_length)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_message_length_only_le, crates/rtps/src/receiver_state.rs::tests::new_state_has_default_fields

Status: done — None steht für MESSAGE_LENGTH_INVALID.

§8.3.2 Table 8.13 ParameterId_t

Spec: §8.3.2, S. 36, Table 8.13 — “Type used to uniquely identify a parameter in a parameter list. … A range of values is reserved for protocol-defined parameters, while another range can be used for vendor-defined parameters”.

Repo: crates/rtps/src/parameter_list.rs (Parameter::id: u16, VENDOR_SPECIFIC_BIT, MUST_UNDERSTAND_BIT)

Tests: crates/rtps/src/parameter_list.rs::tests::a_vendor_specific_must_understand_pid_of_another_vendor_is_an_error, crates/rtps/src/parameter_list.rs::tests::must_understand_unknown_optional_pid_skips

Status: done — die Bereichsaufteilung ist unter §8.3.5.9 und §9.4.2.11 geführt.

§8.3.2 Table 8.13 FragmentNumber_t

Spec: §8.3.2, S. 36, Table 8.13 — “Type used to hold fragment numbers. Must be possible to represent using 32 bits.”

Repo: crates/rtps/src/wire_types.rs (FragmentNumber(u32))

Tests: crates/rtps/src/wire_types.rs::tests::fragment_number_wire_size_is_four, crates/rtps/src/wire_types.rs::tests::fragment_number_roundtrip_le_be

Status: done

§8.3.2 Table 8.13 GroupDigest_t

Spec: §8.3.2, S. 36, Table 8.13 — “Type used to hold a digest value that uniquely identifies a group of Entities belonging to the same Participant.”

Repo: crates/rtps/src/group_digest.rs (GroupDigest, GroupDigest::of_entities)

Tests: crates/rtps/src/group_digest.rs::tests::two_writers_digest_as_section_9_3_2_5_computes_it, crates/rtps/src/group_digest.rs::tests::the_digest_does_not_depend_on_the_order_given, crates/rtps/src/group_digest.rs::tests::the_empty_group_is_zero_and_not_the_hash_of_an_empty_sequence

Status: done

§8.3.2 Table 8.13 UExtension4_t

Spec: §8.3.2, S. 36, Table 8.13 — “Type used to hold an undefined 4-byte value. It is intended to be used in future revisions of the specification.”

Repo: crates/rtps/src/wire_types.rs (UExtension4)

Tests: crates/rtps/src/wire_types.rs::tests::uextension4_roundtrip

Status: done

§8.3.2 Table 8.13 WExtension8_t

Spec: §8.3.2, S. 36, Table 8.13 — “Type used to hold an undefined 8-byte value. It is intended to be used in future revisions of the specification.”

Repo: crates/rtps/src/wire_types.rs (WExtension8)

Tests: crates/rtps/src/wire_types.rs::tests::wextension8_roundtrip

Status: done

§8.3.3 Nachricht = Header + Submessages

Spec: §8.3.3, S. 36 — “The overall structure of an RTPS Message consists of a fixed-size leading RTPS Header followed by a variable number of RTPS Submessage parts. Each Submessage in turn consists of a SubmessageHeader and a variable number of SubmessageElements.”

Repo: crates/rtps/src/datagram.rs (decode_datagram, encode_datagram); crates/rtps/src/message_builder.rs (MessageBuilder)

Tests: crates/rtps/src/datagram.rs::tests::encode_decode_two_data_submessages, crates/rtps/tests/vendor_frames.rs::cyclone_datagrams_re_encode_byte_for_byte

Status: done

§8.3.3 Nachrichtenlänge über Transport oder HeaderExtension

Spec: §8.3.3, S. 37 — “The length may also be sent by the underlying transport that carries the RTPS message. In this case it may be omitted from the HeaderExtension. … a stream-oriented transport (like TCP) would need to include the length in the RTPS HeaderExtension”.

Repo: crates/rtps/src/datagram.rs (decode_datagram: Länge aus dem UDP-Datagramm)

Tests: crates/rtps/src/datagram.rs::tests::decode_handles_last_submessage_zero_length

Status: done — für UDP (§9) trägt der Transport die Länge; die TCP-Abbildung gehört nicht zum UDP/IP-PSM.

§8.3.3.1 Header am Anfang jeder Nachricht

Spec: §8.3.3.1, S. 37 — “The RTPS Header must appear at the beginning of every message.”

Repo: crates/rtps/src/header.rs (RtpsHeader::to_bytes, RtpsHeader::from_bytes); crates/rtps/src/datagram.rs (decode_datagram)

Tests: crates/rtps/src/datagram.rs::tests::decode_rejects_invalid_magic, crates/rtps/src/writer.rs::tests::writer_produces_decodable_datagram

Status: done

§8.3.3.1 Table 8.14 Header.protocol = PROTOCOL_RTPS

Spec: §8.3.3.1, S. 38 — “The protocol identifies the message as an RTPS message. This value is set to PROTOCOL_RTPS.”

Repo: crates/rtps/src/header.rs (RTPS_MAGIC, RtpsHeader::to_bytes)

Tests: crates/rtps/src/header.rs::tests::header_layout_first_four_bytes_are_rtps_magic

Status: done

§8.3.3.1 Table 8.14 Header.version = 2.5

Spec: §8.3.3.1, S. 38 — “Implementations following this version of the document implement protocol version 2.5 (major = 2, minor = 5) and have this field set to PROTOCOLVERSION.”

Repo: crates/rtps/src/header.rs (RtpsHeader::new setzt ProtocolVersion::V2_5)

Tests: crates/rtps/src/header.rs::tests::header_protocol_version_at_bytes_4_5

Status: done

§8.3.3.1 Table 8.14 Header.vendorId

Spec: §8.3.3.1, S. 38 — “The vendorId identifies the vendor of the middleware that implemented the RTPS protocol … The possible values for the vendorId are assigned by the OMG.”

Repo: crates/rtps/src/header.rs (RtpsHeader::vendor_id); crates/rtps/src/wire_types.rs (VendorId::ZERODDS = [0x01, 0xF0])

Tests: crates/rtps/src/header.rs::tests::header_vendor_id_at_bytes_6_7, crates/rtps/src/wire_types.rs::tests::vendor_id_zerodds_constant

Status: partial — das Feld wird gesendet und gelesen; ZeroDDS sendet 0x01F0, laut Kommentar an VendorId::ZERODDS ein Zwischenwert und kein von der OMG zugewiesener Wert (eigenes blocked-Item unter §8.3.5.2).

§8.3.3.1 Table 8.14 Header.guidPrefix

Spec: §8.3.3.1, S. 38 — “The guidPrefix defines a default prefix that can be used to reconstruct the Globally Unique Identifiers (GUIDs) that appear within the Submessages contained in the message.”

Repo: crates/rtps/src/header.rs (RtpsHeader::guid_prefix); crates/rtps/src/datagram.rs (ParsedDatagram::receiver_walk)

Tests: crates/rtps/src/header.rs::tests::header_guid_prefix_at_bytes_8_to_19, crates/rtps/src/datagram.rs::tests::receiver_walk_without_info_source_attributes_to_header_prefix

Status: done

§8.3.3.1 Header-Struktur in Version 2 unveränderlich

Spec: §8.3.3.1, S. 38 — “The structure of the RTPS Header cannot be changed in this major version (2) of the protocol.”

Repo: crates/rtps/src/header.rs (RtpsHeader::WIRE_SIZE = 20)

Tests: crates/rtps/src/header.rs::tests::header_total_size_is_20_bytes, crates/rtps/src/header.rs::tests::header_roundtrip

Status: done

§8.3.3.2 HeaderExtension direkt nach dem Header

Spec: §8.3.3.2, S. 38 — “The HeaderExtension may optionally appear immediately following the Header.”

Repo: crates/rtps/src/datagram.rs (decode_datagram: HE nur als erste Submessage)

Tests: crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension, crates/rtps/src/datagram.rs::tests::decode_rejects_header_extension_after_data_submessage

Status: done

§8.3.3.2 HeaderExtension für Versionen bis 2.4 überspringbar

Spec: §8.3.3.2, S. 39 — “versions of the protocol that do not understand the HeaderExtension will treat it as ‘unknown messge kind’, skip it, and continue processing the submessages that follow it”.

Repo: crates/rtps/src/datagram.rs (decode_datagram)

Tests: crates/rtps/src/datagram.rs::tests::rtps_2_1_treats_0x80_as_vendor_specific_not_header_extension

Status: n/a (informative) — beschreibt das Verhalten älterer Implementierungen; für ZeroDDS selbst gilt §8.3.4.1.

§8.3.3.2 Table 8.15 HE EndiannessFlag

Spec: §8.3.3.2, S. 39, Table 8.15 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_E, HeaderExtension::little_endian)

Tests: crates/rtps/src/header_extension.rs::tests::empty_he_be_roundtrip, crates/rtps/src/header_extension.rs::tests::wire_layout_be_message_length_correct, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.3.2 Table 8.15 HE LengthFlag

Spec: §8.3.3.2, S. 39, Table 8.15 — “LengthFlag … Indicates the messageLength field is present.”

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_L)

Tests: crates/rtps/src/header_extension.rs::tests::flag_byte_with_message_length, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.3.2 Table 8.15 HE TimestampFlag

Spec: §8.3.3.2, S. 39, Table 8.15 — “TimestampFlag … Indicates the rtpsSendTimestamp field is present.”

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_T, Bit 2)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_timestamp_le, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.3.2 Table 8.15 HE UExtensionFlag

Spec: §8.3.3.2, S. 39, Table 8.15 — “UExtensionFlag … Indicates the uExtension4 field is present.”

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_U)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_uextension4_be, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.3.2 Table 8.15 HE WExtensionFlag

Spec: §8.3.3.2, S. 39, Table 8.15 — “WExtensionFlag … Indicates the wExtension8 field is present.”

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_W, Bit 4)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_wextension8_le, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.3.2 Table 8.15 HE ChecksumFlags

Spec: §8.3.3.2, S. 39, Table 8.15 — “ChecksumFlags (2 flags) … Indicates the presence and format of the messageChecksum field.”

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_C0, HE_FLAG_C1, ChecksumKind::from_flags, ChecksumKind::to_flag_bits)

Tests: crates/rtps/src/header_extension.rs::tests::checksum_kind_roundtrip, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.3.2 Table 8.15 HE ParametersFlag

Spec: §8.3.3.2, S. 39, Table 8.15 — “ParametersFlag … Indicates the parameters field is present.”

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_P)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_parameter_list, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.3.2 Table 8.15 HE messageLength

Spec: §8.3.3.2, S. 39–40 — “The messageLength indicates the length of the complete RTPS Message, starting from the beginning of the RTPS Header.”

Repo: crates/rtps/src/datagram.rs (decode_datagram, HeaderExtension); crates/rtps/src/header_extension.rs (validate_message_length, restate_for_rebuilt_message); crates/dcps/src/runtime.rs (unprotect_volatile_datagram, unprotect_user_datagram)

Tests: crates/rtps/src/datagram.rs::tests::a_header_extension_message_length_too_small_for_header_and_extension_is_invalid, crates/rtps/src/datagram.rs::tests::a_header_extension_message_length_counts_from_the_start_of_the_rtps_header, crates/rtps/src/datagram.rs::tests::a_rebuilt_message_takes_the_header_extension_with_its_own_length

Status: done — der Decoder weist ein messageLength ab, das kleiner ist als Header und HeaderExtension, und eines, das von der Länge der empfangenen Nachricht ab dem RTPS-Header abweicht. Eine Nachricht, die der Empfänger nach dem Öffnen geschützter Submessages neu zusammensetzt, wird wie empfangen geprüft und bekommt dann die HeaderExtension mit ihrer eigenen Länge und ohne Prüfsumme (restate_for_rebuilt_message); unverändert wurde jede geöffnete Nachricht von CoreDX 6.14.1 abgewiesen, das ein messageLength sendet, ihre Krypto-Tokens eingeschlossen (OMG dds-security, Linux-Testhost).

§8.3.3.2 Table 8.15 HE rtpsSendTimestamp

Spec: §8.3.3.2, S. 40 — “The rtpsSendTimestamp indicates the time when the RTPS message was sent by the originating Participant. … shall collected as close as possible to the moment when the RTPS Message is sent … The time origin … shall be the same as the one used in the Timestamp Submessage Element”.

Repo: crates/rtps/src/header_extension.rs, crates/rtps/src/receiver_state.rs (apply_header_extension)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_header_extension_updates_fields, crates/rtps/src/datagram.rs::tests::a_header_extension_timestamp_is_no_source_timestamp, crates/rtps/src/datagram.rs::tests::the_walk_with_a_reception_clock_detects_a_skew_and_corrects_the_timestamp

Status: done — Feld kodiert und gelesen; beim Empfang setzt es Receiver.rtpsSendTimestamp (§8.3.7.4), nicht den Quellzeitstempel. ZeroDDS sendet keine HeaderExtension (sie ist optional, §8.3.3.2); die Vorgabe für den Erfassungszeitpunkt gilt für einen Sender, der sie schreibt.

§8.3.3.2 Table 8.15 HE uExtension4

Spec: §8.3.3.2, S. 40 — “The uExtension4 is undefined in this version of the protocol.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::uextension4)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_uextension4_be, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.3.2 Table 8.15 HE wExtension8

Spec: §8.3.3.2, S. 40 — “The wExtension8 is undefined in this version of the protocol.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::wextension8)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_wextension8_le, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.3.2 Table 8.15 HE messageChecksum

Spec: §8.3.3.2, S. 40 — “The messageChecksum provides a checksum computed over the complete of the RTPS Message, which includes the RTPS Header, the HeaderExtension, and all Submessages that may follow.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::message_checksum, seal_message, verify_message, encode_body, decode_body); crates/rtps/src/datagram.rs (decode_submessage)

Tests: crates/rtps/src/header_extension.rs::tests::a_sealed_message_verifies_and_a_changed_one_does_not, crates/rtps/src/header_extension.rs::tests::the_checksum_is_big_endian_in_a_little_endian_header_extension, crates/rtps/src/datagram.rs::tests::a_message_with_a_wrong_checksum_is_refused_and_counted

Status: done — die Prüfsumme der ganzen Nachricht mit genulltem Feld wird berechnet (seal_message) und beim Empfang geprüft; ein Fehler verwirft die Nachricht und wird gezählt (refused_messages). Einen Sendepfad, der eine HeaderExtension mit Prüfsumme schreibt, gibt es in der Runtime nicht.

§8.3.3.2 Table 8.15 HE parameters

Spec: §8.3.3.2, S. 40 — “The parameters provide an extensibility mechanism. It enables revisions of the protocol to add information to the HeaderExtension without breaking interoperability”.

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::parameters)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_parameter_list, crates/rtps/src/header_extension.rs::tests::decode_rejects_malformed_parameter_list_when_p_flag_set, crates/rtps/src/header_extension.rs::tests::decode_takes_a_parameter_list_without_sentinel

Status: done

§8.3.3.3 Table 8.16 SubmessageHeader.submessageId

Spec: §8.3.3.3, S. 41, Table 8.16 — “submessageId: SubmessageKind — Identifies the kind of Submessage.”

Repo: crates/rtps/src/submessage_header.rs (SubmessageHeader::submessage_id)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_header_layout_le, crates/rtps/src/submessage_header.rs::tests::submessage_id_roundtrip_for_known_ids

Status: done

§8.3.3.3 Table 8.16 SubmessageHeader.flags (Bit 0 = Endianness)

Spec: §8.3.3.3, S. 41–42 — “The first flag, the EndiannessFlag, is present and located in the same position in all Submessages … If the EndiannessFlag is set to FALSE, the Submessage is encoded in big-endian format, EndiannessFlag set to TRUE means little-endian.”

Repo: crates/rtps/src/submessage_header.rs (FLAG_E_LITTLE_ENDIAN, SubmessageHeader::is_little_endian); crates/rtps/src/datagram.rs (SubmessageFrame::little_endian)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_header_roundtrip_be, crates/rtps/src/submessage_header.rs::tests::submessage_header_roundtrip_le

Status: done

§8.3.3.3 Table 8.16 SubmessageHeader.submessageLength

Spec: §8.3.3.3, S. 42 — “In case submessageLength > 0, it is either: The length from the start of the contents of the Submessage until the start of the header of the next Submessage … Or else it is the remaining Message length”.

Repo: crates/rtps/src/datagram.rs (decode_datagram: body_end = body_start + octets)

Tests: crates/rtps/src/datagram.rs::tests::encode_decode_two_data_submessages, crates/rtps/src/datagram.rs::tests::pad_submessage_is_skipped_and_the_data_behind_it_still_decodes

Status: done

§8.3.3.3 submessageLength == 0: letzte Submessage

Spec: §8.3.3.3, S. 42 — “In case submessageLength==0, the Submessage is the last Submessage in the Message and extends up to the end of the Message.”

Repo: crates/rtps/src/datagram.rs (decode_datagram, SubmessageFrame::octets_elided, encode_datagram)

Tests: crates/rtps/src/datagram.rs::tests::decode_handles_last_submessage_zero_length, crates/rtps/src/datagram.rs::tests::an_info_ts_without_a_body_is_not_the_last_submessage, crates/rtps/tests/vendor_frames.rs::opendds_datagrams_re_encode_byte_for_byte

Status: done — die Ausnahme für PAD und INFO_TS steht in §9.4.5.1.3.

§8.3.3.3 Submessage-Struktur in Version 2 unveränderlich

Spec: §8.3.3.3, S. 41 — “The structure of the RTPS Submessage cannot be changed in this major version (2) of the protocol.”

Repo: crates/rtps/src/submessage_header.rs (SubmessageHeader::WIRE_SIZE = 4)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_header_layout_be

Status: done

§8.3.4 Receiver-Zustand je Nachricht zurückgesetzt

Spec: §8.3.4, S. 42 — “This state is modeled as the state of an RTPS Receiver that is reset each time a new message is processed and provides context for the interpretation of each Submessage.”

Repo: crates/rtps/src/datagram.rs (ParsedDatagram::receiver_walk legt je Datagramm einen neuen ReceiverState an)

Tests: crates/rtps/src/datagram.rs::tests::receiver_walk_attributes_submessages_after_info_source_to_the_new_prefix

Status: done

§8.3.4 Table 8.17 Anfangswert sourceVersion

Spec: §8.3.4, S. 43, Table 8.17 — “sourceVersion: PROTOCOLVERSION”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::new, source_version)

Tests: crates/rtps/src/receiver_state.rs::tests::the_initial_source_values_and_parameters_are_those_of_table_8_17

Status: done — Anfangswert PROTOCOLVERSION (2.5).

§8.3.4 Table 8.17 Anfangswert sourceVendorId

Spec: §8.3.4, S. 43, Table 8.17 — “sourceVendorId: VENDORID_UNKNOWN”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::new, source_vendor_id)

Tests: crates/rtps/src/receiver_state.rs::tests::the_initial_source_values_and_parameters_are_those_of_table_8_17

Status: done — Anfangswert VENDORID_UNKNOWN.

§8.3.4 Table 8.17 Anfangswert sourceGuidPrefix

Spec: §8.3.4, S. 43, Table 8.17 — “sourceGuidPrefix: GUIDPREFIX_UNKNOWN”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::new, source_guid_prefix)

Tests: crates/rtps/src/receiver_state.rs::tests::the_initial_source_values_and_parameters_are_those_of_table_8_17

Status: done — Anfangswert GUIDPREFIX_UNKNOWN.

§8.3.4 Table 8.17 Anfangswert destGuidPrefix

Spec: §8.3.4, S. 43, Table 8.17 — “destGuidPrefix: GUID prefix of the participant receiving the message”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::new); crates/rtps/src/datagram.rs (ParsedDatagram::receiver_walk)

Tests: crates/rtps/src/receiver_state.rs::tests::new_state_has_default_fields, crates/rtps/src/datagram.rs::tests::receiver_walk_without_info_source_attributes_to_header_prefix

Status: done

§8.3.4 Table 8.17 Anfangswert unicastReplyLocatorList

Spec: §8.3.4, S. 43, Table 8.17 — “The list is initialized to contain a single Locator_t with the LocatorKind, Address, and Port fields specified below: The LocatorKind is set to the kind that identifies the transport that received the message … The Address is set to the Address of the source of the message … The port is set to LOCATOR_PORT_INVALID.”

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::set_initial_reply_locators); crates/rtps/src/datagram.rs (ReceiveContext, ParsedDatagram::receiver_walk_in); crates/dcps/src/runtime.rs (receive_context, receiver_walk_of, reply_targets_of); crates/discovery/src/spdp.rs (samples_in), crates/discovery/src/sedp/stack.rs (handle_datagram_in); crates/dcps/src/wlp.rs, crates/dcps/src/type_lookup_transport.rs

Tests: crates/rtps/src/receiver_state.rs::tests::the_initial_state_is_the_one_of_table_8_17, crates/rtps/src/datagram.rs::tests::receiver_walk_from_starts_the_reply_lists_at_the_transport_values, crates/rtps/src/datagram.rs::tests::receiver_walk_in_applies_the_source_and_the_clock_of_the_context, crates/dcps/src/runtime.rs::tests::a_reader_proxy_without_locators_takes_the_info_reply_of_its_acknack

Status: done — Anfangswert nach Table 8.17 (Transportart, Quelladresse, LOCATOR_PORT_INVALID). Jeder Empfangspfad geht über receiver_walk_in mit der Quelle des Datagramms und der Empfangsuhr: Nutzer-Daten, SPDP, SEDP, WLP, TypeLookup und die Security-Builtins. Die Antwortseite benutzt die Liste: ein Reader-Proxy ohne eigenen Locator übernimmt die Einträge der Unicast-Liste mit Port (die ein InfoReply liefert; die Anfangswerte haben LOCATOR_PORT_INVALID) und behält sie für folgende Antworten.

§8.3.4 Table 8.17 Anfangswert multicastReplyLocatorList

Spec: §8.3.4, S. 43, Table 8.17 — “The list is initialized to contain a single Locator_t … The LocatorKind is set to the kind that identifies the transport that received the message … The address is set to LOCATOR_ADDRESS_INVALID. The port is set to LOCATOR_PORT_INVALID.”

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::set_initial_reply_locators); crates/rtps/src/datagram.rs (ReceiveContext, ParsedDatagram::receiver_walk_in); crates/dcps/src/runtime.rs (receive_context, receiver_walk_of, reply_targets_of); crates/discovery/src/spdp.rs (samples_in), crates/discovery/src/sedp/stack.rs (handle_datagram_in); crates/dcps/src/wlp.rs, crates/dcps/src/type_lookup_transport.rs

Tests: crates/rtps/src/receiver_state.rs::tests::the_initial_state_is_the_one_of_table_8_17, crates/rtps/src/datagram.rs::tests::receiver_walk_from_starts_the_reply_lists_at_the_transport_values, crates/rtps/src/datagram.rs::tests::receiver_walk_in_applies_the_source_and_the_clock_of_the_context, crates/dcps/src/runtime.rs::tests::a_reader_proxy_without_locators_takes_the_info_reply_of_its_acknack

Status: done — Anfangswert nach Table 8.17 (Transportart, LOCATOR_ADDRESS_INVALID, LOCATOR_PORT_INVALID). Jeder Empfangspfad geht über receiver_walk_in mit der Quelle des Datagramms und der Empfangsuhr: Nutzer-Daten, SPDP, SEDP, WLP, TypeLookup und die Security-Builtins. Die Antwortseite benutzt die Liste: ein Reader-Proxy ohne eigenen Locator übernimmt die Einträge der Unicast-Liste mit Port (die ein InfoReply liefert; die Anfangswerte haben LOCATOR_PORT_INVALID) und behält sie für folgende Antworten.

§8.3.4 Table 8.17 Anfangswert haveTimestamp

Spec: §8.3.4, S. 43, Table 8.17 — “haveTimestamp: FALSE”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::new)

Tests: crates/rtps/src/receiver_state.rs::tests::new_state_has_default_fields

Status: done

§8.3.4 Table 8.17 Anfangswert timestamp

Spec: §8.3.4, S. 43, Table 8.17 — “timestamp: TIME_INVALID”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::new); crates/rtps/src/header_extension.rs (HeTimestamp::TIME_INVALID)

Tests: crates/rtps/src/receiver_state.rs::tests::the_initial_state_is_the_one_of_table_8_17

Status: done — {0xffffffff, 0xffffffff}; auch nach InfoSource und InfoTimestamp mit I-Flag.

§8.3.4 Table 8.17 Anfangswert messageLength

Spec: §8.3.4, S. 43, Table 8.17 — “messageLength: MESSAGE_LENGTH_INVALID”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::new: message_length: None)

Tests: crates/rtps/src/receiver_state.rs::tests::new_state_has_default_fields

Status: done

§8.3.4 Table 8.17 Anfangswert messageChecksum

Spec: §8.3.4, S. 43, Table 8.17 — “messageChecksum: CHECKSUM_INVALID”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::new: ChecksumValue::None)

Tests: crates/rtps/src/receiver_state.rs::tests::new_state_has_default_fields

Status: done

§8.3.4 Table 8.17 Anfangswert rtpsSendTimestamp

Spec: §8.3.4, S. 43, Table 8.17 — “rtpsSendTimestamp: TIME_INVALID”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::rtps_send_timestamp)

Tests: crates/rtps/src/receiver_state.rs::tests::new_state_has_default_fields, crates/rtps/src/receiver_state.rs::tests::apply_header_extension_updates_fields

Status: done

§8.3.4 Table 8.17 Anfangswert rtpsReceptionTimestamp

Spec: §8.3.4, S. 43, Table 8.17 — “rtpsReceptionTimestamp: TIME_INVALID”.

Repo: crates/rtps/src/receiver_state.rs (rtps_reception_timestamp)

Tests: crates/rtps/src/receiver_state.rs::tests::the_initial_state_is_the_one_of_table_8_17

Status: done — das Feld beginnt als TIME_INVALID (None).

§8.3.4 Table 8.17 Anfangswert clockSkewDetected

Spec: §8.3.4, S. 43, Table 8.17 — “clockSkewDetected: FALSE”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::new)

Tests: crates/rtps/src/receiver_state.rs::tests::new_state_has_default_fields

Status: done

§8.3.4 Table 8.17 Anfangswert parameters

Spec: §8.3.4, S. 43, Table 8.17 — “parameters: The list is initialized as an empty list.”

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::new, parameters)

Tests: crates/rtps/src/receiver_state.rs::tests::the_initial_source_values_and_parameters_are_those_of_table_8_17

Status: done — Anfangswert eine leere Liste.

§8.3.4.1 Regel 1: unlesbarer Submessage-Header

Spec: §8.3.4.1, S. 43 — “If the full Submessage header cannot be read, the rest of the Message is considered invalid.”

Repo: crates/rtps/src/datagram.rs (decode_datagram: UnexpectedEof)

Tests: crates/rtps/src/datagram.rs::tests::a_truncated_submessage_header_invalidates_the_rest

Status: done — der Rest der Nachricht wird verworfen, der Fehler steht in ParsedDatagram::invalid_rest; die Submessages davor bleiben.

§8.3.4.1 Regel 2: ungültiges submessageLength

Spec: §8.3.4.1, S. 43 — “The submessageLength field defines where the next Submessage starts … If this field is invalid, the rest of the Message is invalid.”

Repo: crates/rtps/src/datagram.rs (decode_datagram: body_end > bytes.len() ergibt UnexpectedEof)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest, crates/rtps/tests/fuzz_smoke.rs::fuzz_decode_datagram_does_not_panic

Status: done — wie Regel 1: der Rest wird verworfen, die vorangehenden Submessages bleiben.

§8.3.4.1 Regel 3: unbekannte SubmessageId ignorieren

Spec: §8.3.4.1, S. 43 — “A Submessage with an unknown SubmessageId must be ignored and parsing must continue with the next Submessage. … SubmessageIds in the vendor-specific range coming from a vendorId that is unknown must also be ignored”.

Repo: crates/rtps/src/datagram.rs (decode_datagram, ParsedSubmessage::Unknown)

Tests: crates/rtps/src/datagram.rs::tests::decode_skips_unknown_submessage_without_must_understand, crates/rtps/src/datagram.rs::tests::decode_marks_unknown_submessage_id_without_failing, crates/rtps/src/datagram.rs::tests::decode_skips_an_unknown_submessage_whatever_its_flags

Status: done

§8.3.4.1 Regel 3: kein Must-Understand auf Submessage-Ebene

Spec: §8.3.4.1, S. 43–44 — Regeln 3 und 4: unbekannte Submessages und unbekannte Flags werden ignoriert; RTPS 2.5 kennt ein Must-Understand nur je ParameterId (Table 9.6, S. 165).

Repo: crates/rtps/src/datagram.rs (decode_datagram, ParsedSubmessage::Unknown)

Tests: crates/rtps/src/datagram.rs::tests::decode_skips_an_unknown_submessage_whatever_its_flags

Status: done — eine unbekannte Submessage wird übersprungen, gleich welche Flags sie trägt.

§8.3.4.1 Regel 4: unbekannte Flags ignorieren

Spec: §8.3.4.1, S. 44 — “The receiver of a Submessage should ignore unknown flags. An implementation of RTPS 2.5 should skip all flags that are marked as ‘X’ (unused) in the protocol.”

Repo: crates/rtps/src/datagram.rs (decode_datagram)

Tests: crates/rtps/src/datagram.rs::tests::unknown_flags_of_a_known_submessage_are_ignored, crates/rtps/src/datagram.rs::tests::decode_skips_an_unknown_submessage_whatever_its_flags

Status: done — bei bekannten Submessages ändern die oberen drei Flag-Bits, die keine Submessage definiert, nichts am Gelesenen; eine unbekannte Submessage wird übersprungen, gleich welche Flags sie trägt.

§8.3.4.1 Regel 5: submessageLength auch bei bekannten Kennungen

Spec: §8.3.4.1, S. 44 — “A valid submessageLength field must always be used to find the next Submessage, even for Submessages with known IDs.”

Repo: crates/rtps/src/datagram.rs (decode_datagram: pos = body_end für jede Submessage)

Tests: crates/rtps/src/datagram.rs::tests::pad_submessage_is_skipped_and_the_data_behind_it_still_decodes, crates/rtps/tests/vendor_frames.rs::rti_datagrams_re_encode_byte_for_byte

Status: done

§8.3.4.1 Regel 6: bekannte, ungültige Submessage

Spec: §8.3.4.1, S. 44 — “A known but invalid Submessage invalidates the rest of the Message.”

Repo: crates/rtps/src/datagram.rs (decode_datagram, ParsedDatagram::invalid_rest)

Tests: crates/rtps/src/datagram.rs::tests::the_submessages_before_an_invalid_one_stand, crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/submessages.rs::validity_tests::data_with_writer_sn_not_positive_or_with_d_and_k_is_invalid

Status: done — eine Submessage, die ihr Decoder nicht lesen kann oder deren „Validity“-Bedingung (§8.3.8) verletzt ist, macht den Rest der Nachricht ungültig; die Submessages davor bleiben (invalid_rest, gezählt). Die eine Bedingung, die der Definition von currentGSN widerspricht, steht unter §8.3.8.6 „Heartbeat ungültig: Group-Felder“.

§8.3.4.1 Gültige Submessages vor einer ungültigen

Spec: §8.3.4.1, S. 43–44 — Regeln 1, 2 und 6 erklären nur „the rest of the Message“ für ungültig.

Repo: crates/rtps/src/datagram.rs (decode_datagram, ParsedDatagram::invalid_rest)

Tests: crates/rtps/src/datagram.rs::tests::the_submessages_before_an_invalid_one_stand, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — decode_datagram liefert die gültig gelesenen Submessages vor einer ungültigen und vermerkt den Fehler in invalid_rest; die Empfangspfade verarbeiten sie.

§8.3.4.1 Regel 6 bei inhaltlich ungültigen Submessages

Spec: §8.3.4.1, S. 44 — “A known but invalid Submessage invalidates the rest of the Message.” Die Gültigkeitsbedingungen je Submessage stehen in §8.3.8 unter „Validity“.

Repo: crates/rtps/src/submessages.rs (Decoder je Submessage); crates/rtps/src/datagram.rs (ParsedDatagram::invalid_rest)

Tests: crates/rtps/src/submessages.rs::validity_tests::data_with_writer_sn_not_positive_or_with_d_and_k_is_invalid, crates/rtps/src/submessages.rs::validity_tests::data_frag_validity_rules, crates/rtps/src/submessages.rs::validity_tests::heartbeat_validity_rules, crates/rtps/src/submessages.rs::validity_tests::gap_and_sequence_number_set_validity_rules, crates/rtps/src/submessages.rs::validity_tests::fragment_submessages_validity_rules, crates/rtps/src/datagram.rs::tests::the_submessages_before_an_invalid_one_stand, crates/dcps/src/runtime.rs::tests::the_empty_acknack_setting_is_off_by_default

Status: done — die Bedingungen der „Validity“-Abschnitte von §8.3.8 prüfen die Decoder der Submessages; ein Verstoß ist ein Fehler des Decoders und macht den Rest der Nachricht ungültig, die Submessages davor bleiben. Gezählt, nicht still verworfen: zerodds_rtps::datagram::invalid_message_rests(), refused_messages() und skipped_must_understand_submessages() (prozessweit), am Runtime als DcpsRuntime::invalid_message_rests, refused_messages, skipped_must_understand_submessages.

§8.3.4.1 Zustandsändernde Submessages

Spec: §8.3.4.1, S. 44 — “In this version of the protocol, only the Header and the Submessages HeaderExtension, InfoSource, InfoReply, InfoDestination, and InfoTimestamp change the state of the Receiver.”

Repo: crates/rtps/src/datagram.rs (ReceiverWalk::next)

Tests: crates/rtps/src/datagram.rs::tests::receiver_walk_yields_every_submessage_including_info_ones, crates/rtps/src/datagram.rs::tests::receiver_walk_info_reply_ip4_sets_reply_locators

Status: done — zusätzlich ändert InfoReplyIp4 (PSM §9.4.5.15) den Zustand wie InfoReply.

§8.3.5 SubmessageElements

Spec: §8.3.5, S. 44 — “Each RTPS Submessage in turn is built from a set of predefined atomic building blocks called SubmessageElements.”

Repo: —

Tests: —

Status: n/a (informative) — Einleitung; die Elemente sind unter §8.3.5.1–§8.3.5.19 einzeln geführt.

§8.3.5.1 Table 8.18 GuidPrefix-Element

Spec: §8.3.5.1, S. 44, Table 8.18 — “value: GuidPrefix_t — Identifies the GuidPrefix_t part of the GUID_t of the Entity that is the source or target of the message.”

Repo: crates/rtps/src/submessages.rs (InfoSourceSubmessage::guid_prefix); crates/rtps/src/datagram.rs (ParsedSubmessage::InfoDestination)

Tests: crates/rtps/src/datagram.rs::tests::decode_info_source_via_datagram, crates/rtps/src/datagram.rs::tests::info_dst_body_of_exactly_twelve_decodes

Status: done

§8.3.5.1 Table 8.19 EntityId-Element

Spec: §8.3.5.1, S. 45, Table 8.19 — “value: EntityId_t — Identifies the EntityId_t part of the GUID_t of the Entity that is the source or target of the message.”

Repo: crates/rtps/src/submessages.rs (Felder reader_id, writer_id aller Entity-Submessages)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_roundtrip_le, crates/rtps/src/wire_types.rs::tests::entity_id_roundtrip

Status: done

§8.3.5.2 Table 8.20 VendorId-Element

Spec: §8.3.5.2, S. 45, Table 8.20 — “value: VendorId_t — Identifies the vendor of the middleware that implements the protocol.”

Repo: crates/rtps/src/submessages.rs (InfoSourceSubmessage::vendor_id); crates/rtps/src/header.rs (RtpsHeader::vendor_id)

Tests: crates/rtps/src/datagram.rs::tests::decode_info_source_via_datagram

Status: done

§8.3.5.2 VendorId von der OMG zugewiesen

Spec: §8.3.5.2, S. 45 — “The following values are reserved by the protocol: VENDORID_UNKNOWN. Other values must be assigned by the OMG.”

Repo: —

Tests: —

Status: blocked — Zuweisung einer VendorId durch die OMG (beantragt); hebt sich auf, sobald die OMG den Wert zuweist und VendorId::ZERODDS ihn trägt. Bis dahin sendet ZeroDDS 0x01F0 (crates/rtps/src/wire_types.rs, laut Kommentar ein Zwischenwert), einen Wert, den die OMG-Liste nicht führt (vergeben bis {0x01,0x1C}, {0x01,0x1D} und {0x01,0x1E} reserviert).

§8.3.5.3 Table 8.21 ProtocolVersion-Element

Spec: §8.3.5.3, S. 45, Table 8.21 — “value: ProtocolVersion_t — Identifies the major and minor version of the RTPS protocol.” Sonderwerte PROTOCOLVERSION_1_0 … PROTOCOLVERSION_2_4.

Repo: crates/rtps/src/wire_types.rs (ProtocolVersion); crates/rtps/src/submessages.rs (InfoSourceSubmessage::protocol_version)

Tests: crates/rtps/src/wire_types.rs::tests::protocol_version_all_aliases_roundtrip, crates/rtps/src/datagram.rs::tests::decode_info_source_via_datagram

Status: done

§8.3.5.4 Table 8.22 SequenceNumber: 64 Bit mit Vorzeichen

Spec: §8.3.5.4, S. 45 — “A sequence number is a 64-bit signed integer, that can take values in the range: -2^63 <= N <= 2^63-1.”

Repo: crates/rtps/src/wire_types.rs (SequenceNumber(i64), SequenceNumber::split, SequenceNumber::from_high_low)

Tests: crates/rtps/src/wire_types.rs::tests::sequence_number_split_high_low, crates/rtps/src/wire_types.rs::tests::sequence_number_roundtrip_be

Status: done

§8.3.5.4 Sequenznummern beginnen bei 1

Spec: §8.3.5.4, S. 45 — “Sequence numbers begin at 1.”

Repo: crates/rtps/src/writer.rs (BestEffortWriter); crates/rtps/src/reliable_writer.rs (ReliableWriter::write)

Tests: crates/rtps/src/writer.rs::tests::writer_starts_at_sequence_number_one, crates/rtps/src/reliable_stateless_writer.rs::tests::new_change_assigns_monotonic_sn

Status: done

§8.3.5.4 SEQUENCENUMBER_UNKNOWN

Spec: §8.3.5.4, S. 46 — “The protocol reserves the following value: SEQUENCENUMBER_UNKNOWN”.

Repo: crates/rtps/src/wire_types.rs (SequenceNumber::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::sequence_number_unknown_high_minus_one_low_zero

Status: done

§8.3.5.5 Table 8.23 SequenceNumberSet base/set

Spec: §8.3.5.5, S. 46, Table 8.23 — “base: SequenceNumber_t — Identifies the first sequence number in the set. set: SequenceNumber_t[*] — A set of sequence numbers, each verifying that: base <= element(set) <= base+255”.

Repo: crates/rtps/src/submessages.rs (SequenceNumberSet, from_missing, iter_set)

Tests: crates/rtps/tests/proptest_roundtrip.rs::seqnum_set_iter_matches_missing, crates/rtps/tests/proptest_roundtrip.rs::seqnum_set_roundtrip_le

Status: done

§8.3.5.5 Gültigkeit SequenceNumberSet

Spec: §8.3.5.5, S. 46 — “a valid SequenceNumberSet must verify that: maximum(SequenceNumberSet) - minimum(SequenceNumberSet) < 256, minimum(SequenceNumberSet) >= 1”.

Repo: crates/rtps/src/submessages.rs (SequenceNumberSet::read_from: numBits <= 256, bitmapBase >= 1; from_missing kappt das Fenster bei 256)

Tests: crates/rtps/tests/fuzz_smoke.rs::fuzz_sequence_number_set_read_from_does_not_panic, crates/rtps/tests/proptest_roundtrip.rs::seqnum_set_wire_size_matches_encoded, crates/rtps/src/submessages.rs::validity_tests::gap_and_sequence_number_set_validity_rules, crates/rtps/tests/vendor_frames.rs::the_empty_acknack_of_opendds_and_rti_is_invalid_by_default, crates/rtps/tests/vendor_frames.rs::opendds_session_re_encodes_byte_for_byte, crates/rtps/tests/vendor_frames.rs::rti_session_re_encodes_byte_for_byte, crates/rtps/src/submessages.rs::validity_tests::the_empty_set_with_base_zero_is_accepted_only_on_request

Status: done — die Spannweite ist auf 256 begrenzt, minimum >= 1 prüft der Decoder. Vendor-Form: OpenDDS 3.34.0 und RTI Connext 7.7.0 senden als ACKNACK eines Readers ohne Samples readerSNState 0/0: (bitmapBase 0, numBits 0; gemessen in tools/wire-capture/rtps-sessions: 40 und 8 ACKNACK). Standard: ungültig. Die Einstellung wire.accept_empty_acknack_base_zero (Env ZERODDS_WIRE_ACCEPT_EMPTY_ACKNACK_BASE_ZERO, Standard false) nimmt genau diese leere Menge in einem ACKNACK an, prozessweit.

§8.3.5.6 Table 8.24 FragmentNumber

Spec: §8.3.5.6, S. 46 — “A fragment number is a 32-bit unsigned integer … Fragment numbers start at 1.”

Repo: crates/rtps/src/wire_types.rs (FragmentNumber(u32)); crates/rtps/src/reliable_writer.rs (Fragmentierung ab Nummer 1)

Tests: crates/rtps/src/wire_types.rs::tests::fragment_number_roundtrip_le_be, crates/rtps/src/reliable_writer.rs::tests::write_above_fragment_size_packs_the_fragments_a_message_carries

Status: done

§8.3.5.7 Table 8.25 FragmentNumberSet

Spec: §8.3.5.7, S. 46, Table 8.25 — “base: FragmentNumber_t … set: FragmentNumber_t[*] — A set of fragment numbers, each verifying that: base <= element(set) <= base+255”. Gültig nur mit “maximum - minimum < 256, minimum >= 1”.

Repo: crates/rtps/src/submessages.rs (FragmentNumberSet, from_missing, read_from)

Tests: crates/rtps/tests/proptest_roundtrip.rs::frag_set_roundtrip_le, crates/rtps/tests/fuzz_smoke.rs::fuzz_fragment_number_set_read_from_does_not_panic, crates/rtps/src/submessages.rs::validity_tests::fragment_submessages_validity_rules

Status: done — Spannweite auf 256 begrenzt, bitmapBase >= 1 wird geprüft.

§8.3.5.8 Table 8.26 Timestamp

Spec: §8.3.5.8, S. 47 — “Timestamp is used to represent time. The representation should be capable of having a resolution of nano-seconds or better.” Sonderwerte TIME_ZERO, TIME_INVALID, TIME_INFINITE.

Repo: crates/rtps/src/header_extension.rs (HeTimestamp); crates/rtps/src/submessages.rs (InfoTimestampSubmessage); crates/dcps/src/time.rs

Tests: crates/rtps/src/submessages.rs::tests::info_timestamp_roundtrip_le, crates/rtps/src/submessages.rs::validity_tests::time_t_seconds_are_unsigned, crates/rtps/tests/reliable_e2e.rs::e2e_source_timestamp_round_trips

Status: done — Auflösung 2⁻³² s, vorzeichenlose Sekunden, TIME_INVALID und TIME_INFINITE als Konstanten.

§8.3.5.9 Table 8.27/8.28 ParameterList und Parameter

Spec: §8.3.5.9, S. 47, Table 8.27 und 8.28 — “parameter: Parameter[*]”; je Parameter “parameterId: ParameterId_t”, “length: short”, “value: octet[length]”.

Repo: crates/rtps/src/parameter_list.rs (ParameterList, Parameter, to_bytes, from_bytes_with_consumed)

Tests: crates/rtps/src/parameter_list.rs::tests::single_parameter_encodes_id_length_value, crates/rtps/src/parameter_list.rs::tests::roundtrip_multiple_parameters, crates/rtps/src/parameter_list.rs::tests::roundtrip_be_endianness

Status: done

§8.3.5.9 Höchstens 2^16 ParameterIds

Spec: §8.3.5.9, S. 47 — “There shall be no more than 2^16 possible values of the ParameterId_t parameterId.”

Repo: crates/rtps/src/parameter_list.rs (Parameter::id: u16)

Tests: crates/rtps/src/parameter_list.rs::tests::single_parameter_encodes_id_length_value

Status: done

§8.3.5.9 2^15 Werte für protokolldefinierte Parameter

Spec: §8.3.5.9, S. 47 — “A range of 2^15 values is reserved for protocol-defined parameters. All the parameter_id values defined by the 2.5 version of the protocol and all future revisions of the same major version must use values in this range.”

Repo: crates/rtps/src/parameter_list.rs (pid, is_standard_pid)

Tests: crates/rtps/src/parameter_list.rs::tests::is_standard_pid_recognises_dds_security_pids, crates/rtps/src/parameter_list.rs::tests::is_standard_pid_unknown_pid_returns_false

Status: done

§8.3.5.9 2^15 Werte für herstellerdefinierte Parameter

Spec: §8.3.5.9, S. 47 — “A range of 2^15 values is reserved for vendor-defined parameters.”

Repo: crates/rtps/src/parameter_list.rs (VENDOR_SPECIFIC_BIT, pid::SHM_LOCATOR, pid::ZERODDS_TYPE_ID)

Tests: crates/rtps/src/publication_data.rs::tests::a_foreign_vendors_0x8002_is_not_read_as_a_type_identifier, crates/rtps/src/publication_data.rs::tests::a_zerodds_0x8002_is_read_and_the_announcement_states_the_vendor

Status: done

§8.3.5.9 Parameterlänge höchstens 2^16 Oktette

Spec: §8.3.5.9, S. 47 — “The maximum length of any parameter is limited to 2^16 octets.”

Repo: crates/rtps/src/parameter_list.rs (length als u16)

Tests: crates/rtps/tests/user_data_propagation.rs::user_data_large_payload_32kib

Status: done

§8.3.5.10 Table 8.29 Count

Spec: §8.3.5.10, S. 47–48 — “Count is used by several Submessages and enables a receiver to detect duplicates of the same Submessage.”

Repo: crates/rtps/src/submessages.rs (count-Felder)

Tests: crates/rtps/src/reliable_writer.rs::tests::heartbeat_count_increments

Status: done — das Element ist vorhanden; die Auswertung beim Empfänger ist unter §8.3.8.1 und §8.3.8.6 geführt.

§8.3.5.11 Table 8.30 ChangeCount

Spec: §8.3.5.11, S. 48 — “ChangeCount is used in the Gap Submessage and enables the sender to indicate the number of changes within the Gap that belong to a certain category.”

Repo: crates/rtps/src/submessages.rs (GapSubmessage::filtered_count)

Tests: crates/rtps/src/submessages.rs::tests::gap_filtered_count_is_eight_octets_high_then_low, crates/rtps/src/submessages.rs::tests::gap_with_filtered_count_roundtrip_le

Status: done — in der GAP-Submessage 64 Bit (acht Oktette, high und low).

§8.3.5.12 Table 8.31 Checksum

Spec: §8.3.5.12, S. 48, Table 8.31 — “value: Checksum32_t, or Checksum64_t, or Checksum128_t — A checksum of the RTPS Message, including the RTPS Header.”

Repo: crates/rtps/src/header_extension.rs (ChecksumValue, ChecksumKind)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_crc32c_le, crates/rtps/src/header_extension.rs::tests::roundtrip_with_crc64_be, crates/rtps/src/header_extension.rs::tests::roundtrip_with_md5_le, crates/rtps/src/header_extension.rs::tests::the_checksum_is_big_endian_in_a_little_endian_header_extension

Status: done — die drei Formate, CRC in Big-Endian.

§8.3.5.12 Prüfsumme je Transport-PSM

Spec: §8.3.5.12, S. 48 — “the Checksum may be omitted from the HeaderExtension. The specific behavior shall be defined for each Transport PSM.”

Repo: —

Tests: —

Status: n/a (informative) — Auftrag an die PSMs; der UDP/IP-PSM regelt die Prüfsumme in §9.4.2.15.

§8.3.5.13 Table 8.32 MessageLength

Spec: §8.3.5.13, S. 48 — “MessageLength is used in the HeaderExtension Submessage and enables the sender to indicate the length of the RTPS message.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::message_length)

Tests: crates/rtps/src/header_extension.rs::tests::wire_layout_le_message_length_correct, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.5.14 Table 8.33 UExtension4

Spec: §8.3.5.14, S. 48–49 — “UExtension4 is used in the HeaderExtension Submessage and enables the sender to add 4 octets of information to the header.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::uextension4)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_uextension4_be, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.5.15 Table 8.34 WExtension8

Spec: §8.3.5.15, S. 49 — “WExtension8 is used in the HeaderExtension Submessage and enables the sender to add 8 octets of information to the header.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::wextension8)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_wextension8_le, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.5.16 Table 8.35 LocatorList

Spec: §8.3.5.16, S. 49 — “LocatorList is used to specify a list of locators.”

Repo: crates/rtps/src/submessages.rs (InfoReplySubmessage::unicast_locators, multicast_locators)

Tests: crates/rtps/src/datagram.rs::tests::decode_info_reply_with_multicast_via_datagram

Status: done

§8.3.5.17 Table 8.36 SerializedData

Spec: §8.3.5.17, S. 49 — “The RTPS protocol does not interpret the serialized data-stream. Therefore, it is represented as opaque data.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::serialized_payload); crates/rtps/src/payload.rs (Payload)

Tests: crates/rtps/src/datagram.rs::tests::the_shared_decode_gives_ranges_of_the_datagram, crates/rtps/tests/cyclone_compliance.rs::cyclone_data_cdr2_roundtrip_bit_identical

Status: done

§8.3.5.18 Table 8.37 SerializedDataFragment

Spec: §8.3.5.18, S. 49 — “SerializedDataFragment contains the serialized representation of a data-object that has been fragmented. … the RTPS protocol does not interpret the fragmented serialized data-stream.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::serialized_payload)

Tests: crates/rtps/src/datagram.rs::tests::decode_data_frag_preserves_flags_and_payload

Status: done

§8.3.5.19 Table 8.38 GroupDigest

Spec: §8.3.5.19, S. 49–50 — “GroupDigest is used to communicate a set of EntityId_t in a compact manner.”

Repo: crates/rtps/src/group_digest.rs (GroupDigest, GroupDigest::of_entities)

Tests: crates/rtps/src/group_digest.rs::tests::two_writers_digest_as_section_9_3_2_5_computes_it, crates/rtps/src/group_digest.rs::tests::the_digest_does_not_depend_on_the_order_given, crates/rtps/src/group_digest.rs::tests::the_empty_group_is_zero_and_not_the_hash_of_an_empty_sequence

Status: done

§8.3.6.1 Header: Purpose

Spec: §8.3.6.1, S. 50 — “The Header is used to identify the message as belonging to the RTPS protocol, to identify the version of the RTPS protocol used, and to provide context information”.

Repo: —

Tests: —

Status: n/a (informative) — Zweckangabe; die Felder sind unter §8.3.3.1 geführt.

§8.3.6.2 Header: Content

Spec: §8.3.6.2, S. 50 — “The structure of the Header can only be changed if the major version of the protocol is also changed.”

Repo: —

Tests: —

Status: n/a (informative) — wiederholt §8.3.3.1; dort als Item „Header-Struktur in Version 2 unveränderlich“ geführt.

§8.3.6.3 Header ungültig: zu wenige Oktette

Spec: §8.3.6.3, S. 50 — “The Message has less than the required number of octets to contain a full Header. The number required is defined by the PSM.”

Repo: crates/rtps/src/header.rs (RtpsHeader::from_bytes: UnexpectedEof unter 20 Oktetten)

Tests: crates/rtps/src/datagram.rs::tests::decode_rejects_datagram_shorter_than_the_header, crates/rtps/src/header.rs::tests::header_decode_rejects_truncated_input

Status: done

§8.3.6.3 Header ungültig: protocol ≠ PROTOCOL_RTPS

Spec: §8.3.6.3, S. 50 — “Its protocol value does not match the value of PROTOCOL_RTPS.”

Repo: crates/rtps/src/header.rs (RtpsHeader::from_bytes: InvalidMagic)

Tests: crates/rtps/src/header.rs::tests::header_decode_rejects_invalid_magic, crates/rtps/src/datagram.rs::tests::decode_rejects_invalid_magic

Status: done

§8.3.6.3 Header ungültig: Major-Version zu hoch

Spec: §8.3.6.3, S. 50 — “The major protocol version is larger than the major protocol version supported by the implementation.”

Repo: crates/rtps/src/datagram.rs (decode_datagram_into: Vergleich mit ProtocolVersion::CURRENT.major)

Tests: crates/rtps/src/datagram.rs::tests::decode_rejects_major_version_above_supported, crates/rtps/src/datagram.rs::tests::decode_accepts_minor_version_above_supported

Status: done

§8.3.6.4 Receiver.sourceGuidPrefix = Header.guidPrefix

Spec: §8.3.6.4, S. 50 — “Receiver.sourceGuidPrefix = Header.guidPrefix”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::init_from_header)

Tests: crates/rtps/src/receiver_state.rs::tests::init_from_header_overrides_source_fields, crates/rtps/src/datagram.rs::tests::receiver_walk_without_info_source_attributes_to_header_prefix

Status: done

§8.3.6.4 Receiver.sourceVersion = Header.version

Spec: §8.3.6.4, S. 50 — “Receiver.sourceVersion = Header.version”.

Repo: crates/rtps/src/receiver_state.rs (init_from_header)

Tests: crates/rtps/src/receiver_state.rs::tests::the_header_sets_the_source_and_clears_have_timestamp

Status: done — der Header setzt sourceVersion, sourceVendorId und sourceGuidPrefix.

§8.3.6.4 Receiver.sourceVendorId = Header.vendorId

Spec: §8.3.6.4, S. 50 — “Receiver.sourceVendorId = Header.vendorId”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::init_from_header)

Tests: crates/rtps/src/receiver_state.rs::tests::init_from_header_overrides_source_fields

Status: done

§8.3.6.4 Receiver.haveTimestamp = false

Spec: §8.3.6.4, S. 50 — “Receiver.haveTimestamp = false”.

Repo: crates/rtps/src/receiver_state.rs (init_from_header)

Tests: crates/rtps/src/receiver_state.rs::tests::the_header_sets_the_source_and_clears_have_timestamp

Status: done — der Header setzt haveTimestamp = false.

§8.3.6.5 Header: Logical Interpretation

Spec: §8.3.6.5, S. 50 — “None”.

Repo: —

Tests: —

Status: n/a (informative) — keine Anforderung.

§8.3.7.1 HeaderExtension unmittelbar nach dem Header

Spec: §8.3.7.1, S. 50 — “This submessage, if present, shall appear immediately after the RTPS Header.”

Repo: crates/rtps/src/datagram.rs (decode_datagram)

Tests: crates/rtps/src/datagram.rs::tests::decode_rejects_header_extension_after_data_submessage, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.7.2 HeaderExtension: Content

Spec: §8.3.7.2, S. 50 — “The elements that form the structure of the HeaderExtension were described in 8.3.3.2.”

Repo: —

Tests: —

Status: n/a (informative) — Verweis; Items unter §8.3.3.2.

§8.3.7.3 HE ungültig: nicht direkt nach dem Header

Spec: §8.3.7.3, S. 51 — “The submessage is present but does not immediately follow the RTPS Header.”

Repo: crates/rtps/src/datagram.rs (decode_datagram)

Tests: crates/rtps/src/datagram.rs::tests::decode_rejects_header_extension_after_data_submessage

Status: done — eine HeaderExtension hinter einer anderen Submessage ist ungültig und mit ihr der Rest der Nachricht; die Submessages davor bleiben.

§8.3.7.3 HE ungültig: submessageLength zu klein für die Felder

Spec: §8.3.7.3, S. 51 — “The submessageLength in the Submessage header is too small to fit the fields that are present as indicated by the submessage flags.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::decode_body)

Tests: crates/rtps/src/header_extension.rs::tests::decode_rejects_truncated_uextension4_body, crates/rtps/src/header_extension.rs::tests::decode_rejects_truncated_md5_checksum_body, crates/rtps/src/header_extension.rs::tests::decode_rejects_truncated_body_before_message_length, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.7.3 HE ungültig: messageLength zu klein

Spec: §8.3.7.3, S. 51 — “The messageLength is too small to fit the RTPS Header and the HeaderExtension.”

Repo: crates/rtps/src/datagram.rs (decode_datagram)

Tests: crates/rtps/src/datagram.rs::tests::a_header_extension_message_length_too_small_for_header_and_extension_is_invalid

Status: done — ein messageLength unter Header und HeaderExtension (28 Oktette) macht die Nachricht ungültig.

§8.3.7.3 HE ungültig: parameters fehlerhaft

Spec: §8.3.7.3, S. 51 — “The parameters are malformed.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::decode_body über ParameterList::from_bytes)

Tests: crates/rtps/src/header_extension.rs::tests::decode_rejects_malformed_parameter_list_when_p_flag_set, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.7.4 LengthFlag: Receiver.messageLength

Spec: §8.3.7.4, S. 51 — “IF ( LengthFlag ) { Receiver.messageLength = HeaderExtension.messageLength }”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_header_extension)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_header_extension_updates_fields, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.7.4 TimestampFlag: rtpsSendTimestamp, rtpsReceptionTimestamp, clockSkewDetected

Spec: §8.3.7.4, S. 51 — “IF ( TimestampFlag ) { Receiver.rtpsSendTimestamp = HeaderExtension.rtpsSendTimestamp; Receiver.rtpsReceptionTimestamp = GetCurrentTime(); RECEIVER.clockSkewDetected = CLOCK_SKEW_DETECTED(receptionTime, Receiver.rtpsSendTimestamp) }”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::note_reception, note_clock_skew, apply_info_timestamp); crates/rtps/src/datagram.rs (ReceptionClock, ReceiveContext); crates/dcps/src/runtime.rs (receive_context, RuntimeConfig::clock_skew_threshold_s)

Tests: crates/rtps/src/receiver_state.rs::tests::the_reception_time_is_kept_and_checked_against_the_send_time, crates/rtps/src/receiver_state.rs::tests::an_info_timestamp_is_corrected_by_the_clock_skew, crates/rtps/src/datagram.rs::tests::the_walk_with_a_reception_clock_detects_a_skew_and_corrects_the_timestamp, crates/dcps/tests/runtime_config_layering.rs::the_clock_skew_threshold_is_a_setting_and_off_by_default

Status: done — jeder Empfangspfad setzt bei einer HeaderExtension mit Zeitstempel rtpsReceptionTimestamp (Wanduhr). Die Spec nennt für CLOCK_SKEW_DETECTED keine Schwelle; sie ist die Einstellung wire.clock_skew_threshold_s (Sekunden). Vorgabe 0 = aus: dann bleibt clockSkewDetected FALSE. Es gibt keine Vorgabeschwelle.

§8.3.7.4 uExtensionFlag: Receiver.uExtension4

Spec: §8.3.7.4, S. 51 — “IF ( uExtensionFlag ) { Receiver.uExtension4 = HeaderExtension.uExtension4 }”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_header_extension)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_header_extension_updates_fields

Status: done

§8.3.7.4 wExtensionFlag: Receiver.wExtension8

Spec: §8.3.7.4, S. 51 — “IF ( wExtensionFlag ) { Receiver.wExtension8 = HeaderExtension.wExtension8 }”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_header_extension)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_header_extension_updates_fields

Status: done

§8.3.7.4 ChecksumFlags: Receiver.messageChecksum

Spec: §8.3.7.4, S. 51 — “IF ( ChecksumFlags != 00 ) { Receiver.messageChecksum = HeaderExtension.messageChecksum }”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_header_extension)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_header_extension_updates_fields, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.7.4 ParametersFlag: Receiver.parameters

Spec: §8.3.7.4, S. 51 — “IF ( ParamatersFlag) { Receiver.parameters = HeaderExtension.parameters }”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_header_extension)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_header_extension_with_parameters_sets_pl, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§8.3.7.5 messageLength ab Beginn des RTPS-Headers

Spec: §8.3.7.5, S. 51 — “The value of the messageLength shall indicate the length of the entire RTPS Message starting from the beginning of the RTPS Header.”

Repo: crates/rtps/src/datagram.rs, crates/rtps/src/header_extension.rs (validate_message_length)

Tests: crates/rtps/src/datagram.rs::tests::a_header_extension_message_length_counts_from_the_start_of_the_rtps_header

Status: done — die Länge wird ab dem ersten Oktett des RTPS-Headers gezählt und mit der empfangenen Nachricht verglichen.

§8.3.7.5 rtpsSendTimestamp und rtpsReceptionTimestamp

Spec: §8.3.7.5, S. 51 — “The rtpsSendTimestamp represents the time the RTPS message was sent. It is measured using the clock of the sending Participant. The rtpsReceptionTimestamp represents the time when the RTPS message was received.”

Repo: —

Tests: —

Status: n/a (informative) — Begriffsbestimmung; die Zuweisungen sind unter §8.3.7.4 TimestampFlag geführt.

§8.3.7.5 CLOCK_SKEW_DETECTED

Spec: §8.3.7.5, S. 51–52 — “The function CLOCK_SKEW_DETECTED() represents an implementation-specific function used to determine whether the sending and receiving participant clocks are not synchronized or have too large a skew.”

Repo: crates/rtps/src/receiver_state.rs (note_reception, note_clock_skew); crates/dcps/src/runtime.rs (receive_context, wire.clock_skew_threshold_s)

Tests: crates/rtps/src/receiver_state.rs::tests::the_reception_time_is_kept_and_checked_against_the_send_time, crates/rtps/src/datagram.rs::tests::the_walk_with_a_reception_clock_detects_a_skew_and_corrects_the_timestamp, crates/dcps/tests/runtime_config_layering.rs::the_clock_skew_threshold_is_a_setting_and_off_by_default

Status: done — die Spec nennt die Funktion implementierungsspezifisch; ZeroDDS vergleicht Empfangs- und Sendezeit gegen die Schwelle wire.clock_skew_threshold_s (Vorgabe 0 = aus, keine Vorgabeschwelle).

§8.3.7.5 messageChecksum mit genulltem Prüfsummenfeld

Spec: §8.3.7.5, S. 52 — “It shall be computed over the entire RTPS Message. For the purpose of computing the checksum, the value of the messageChecksum field in the RTPS HeaderExtension shall be set to zero.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::message_checksum, seal_message, verify_message, encode_body, decode_body); crates/rtps/src/datagram.rs (decode_submessage)

Tests: crates/rtps/src/header_extension.rs::tests::a_sealed_message_verifies_and_a_changed_one_does_not, crates/rtps/src/header_extension.rs::tests::the_checksum_is_big_endian_in_a_little_endian_header_extension, crates/rtps/src/datagram.rs::tests::a_message_with_a_wrong_checksum_is_refused_and_counted

Status: done — message_checksum rechnet über die ganze Nachricht mit genulltem Feld.

§8.3.7.5 uExtension4, wExtension8, parameters ohne Bedeutung

Spec: §8.3.7.5, S. 52 — “The uExtension4 and wExtension8 may be useful to communicate additional data on the header in a future version … This version of the specification does not define any parameters in the HeaderExtension.”

Repo: —

Tests: —

Status: n/a (informative) — keine Anforderung an diese Version.

§8.3.8 Entity- und Interpreter-Submessages

Spec: §8.3.8, S. 52–53, Table 8.39 — Einteilung in Entity-Submessages (Data, DataFrag, Heartbeat, HeartbeatFrag, Gap, AckNack, NackFrag) und Interpreter-Submessages (HeaderExtension, InfoSource, InfoDestination, InfoReply, InfoTimestamp, Pad); Gliederung jeder Beschreibung.

Repo: —

Tests: —

Status: n/a (informative) — Übersicht; die Submessages sind unter §8.3.8.1–§8.3.8.13 einzeln geführt.

§8.3.8.1 AckNack: Purpose

Spec: §8.3.8.1, S. 54 — “This Submessage is used to communicate the state of a Reader to a Writer. … This Submessage can be used to do both positive and negative acknowledgments.”

Repo: —

Tests: —

Status: n/a (informative) — Zweckangabe; die Inhalte folgen.

§8.3.8.1 Table 8.40 AckNack EndiannessFlag

Spec: §8.3.8.1, S. 54, Table 8.40 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/submessages.rs (AckNackSubmessage::write_body, AckNackSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::tests::acknack_submessage_roundtrip_le, crates/rtps/tests/vendor_frames.rs::fastdds_datagrams_re_encode_byte_for_byte

Status: done

§8.3.8.1 Table 8.40 AckNack FinalFlag

Spec: §8.3.8.1, S. 54, Table 8.40 — “FinalFlag … Indicates to the Writer whether a response is mandatory.”

Repo: crates/rtps/src/submessages.rs (AckNackSubmessage::final_flag, ACKNACK_FLAG_FINAL); crates/rtps/src/reliable_reader.rs (build_acknack_datagram)

Tests: crates/rtps/src/submessages.rs::tests::acknack_submessage_with_final_flag, crates/rtps/src/datagram.rs::tests::decode_acknack_preserves_final_flag

Status: done — die Antwortpflicht des Writers ist unter §9.4.5.3 geführt.

§8.3.8.1 Table 8.40 AckNack readerId

Spec: §8.3.8.1, S. 54, Table 8.40 — “readerId: EntityId — Identifies the Reader entity that acknowledges receipt of certain sequence numbers and/or requests to receive certain sequence numbers.”

Repo: crates/rtps/src/submessages.rs (AckNackSubmessage::reader_id)

Tests: crates/rtps/src/submessages.rs::tests::acknack_submessage_roundtrip_le

Status: done

§8.3.8.1 Table 8.40 AckNack writerId

Spec: §8.3.8.1, S. 54, Table 8.40 — “writerId: EntityId — Identifies the Writer entity that is the target of the AckNack message.”

Repo: crates/rtps/src/submessages.rs (AckNackSubmessage::writer_id); crates/dcps/src/runtime.rs (handle_user_datagram_from: rt.writer_slot(ack.writer_id))

Tests: crates/rtps/src/submessages.rs::tests::acknack_submessage_roundtrip_le, crates/rtps/src/reliable_writer.rs::tests::acknack_dispatches_to_matching_proxy_only

Status: done

§8.3.8.1 Table 8.40 AckNack readerSNState

Spec: §8.3.8.1, S. 54, Table 8.40 — “All sequence numbers up to the one prior to readerSNState.base are confirmed as received by the reader. The sequence numbers that appear in the set indicate missing sequence numbers on the reader side.”

Repo: crates/rtps/src/submessages.rs (AckNackSubmessage::reader_sn_state); crates/rtps/src/reliable_writer.rs (handle_acknack_set_at)

Tests: crates/rtps/src/reliable_writer.rs::tests::handle_acknack_updates_proxy_state, crates/rtps/src/reliable_writer.rs::tests::handle_acknack_with_lower_base_leaves_requested

Status: done

§8.3.8.1 Table 8.40 AckNack count

Spec: §8.3.8.1, S. 54, Table 8.40 — “count: Count — A counter that is incremented each time a new AckNack message is sent.”

Repo: crates/rtps/src/reliable_reader.rs (build_acknack_datagram)

Tests: crates/rtps/src/reliable_reader.rs::tests::the_counts_of_acknack_and_nack_frag_rise_with_each_message

Status: done — aufeinanderfolgende ACKNACKs tragen die Zähler 1, 2, 3.

§8.3.8.1 AckNack ungültig: submessageLength zu klein

Spec: §8.3.8.1, S. 54 — “submessageLength in the Submessage header is too small.”

Repo: crates/rtps/src/submessages.rs (AckNackSubmessage::read_body)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — die Kürzung wird erkannt; die Submessage ist ungültig und mit ihr der Rest der Nachricht, die Submessages davor bleiben (ParsedDatagram::invalid_rest, gezählt).

§8.3.8.1 AckNack ungültig: readerSNState ungültig

Spec: §8.3.8.1, S. 54 — “readerSNState is invalid (as defined in Section 8.3.5.5).”

Repo: crates/rtps/src/submessages.rs (SequenceNumberSet::read_from)

Tests: crates/rtps/src/submessages.rs::validity_tests::gap_and_sequence_number_set_validity_rules, crates/rtps/src/submessages.rs::tests::seqnumset_rejects_num_bits_above_256, crates/rtps/tests/vendor_frames.rs::the_empty_acknack_of_opendds_and_rti_is_invalid_by_default, crates/rtps/tests/vendor_frames.rs::opendds_session_re_encodes_byte_for_byte, crates/rtps/tests/vendor_frames.rs::rti_session_re_encodes_byte_for_byte, crates/rtps/src/submessages.rs::validity_tests::the_empty_set_with_base_zero_is_accepted_only_on_request

Status: done — numBits > 256 und bitmapBase < 1 werden abgewiesen, mit dem Rest der Nachricht. Vendor-Form: OpenDDS 3.34.0 und RTI Connext 7.7.0 senden als ACKNACK eines Readers ohne Samples readerSNState 0/0: (bitmapBase 0, numBits 0; gemessen in tools/wire-capture/rtps-sessions: 40 und 8 ACKNACK). Standard: ungültig. Die Einstellung wire.accept_empty_acknack_base_zero (Env ZERODDS_WIRE_ACCEPT_EMPTY_ACKNACK_BASE_ZERO, Standard false) nimmt genau diese leere Menge in einem ACKNACK an, prozessweit.

§8.3.8.1 AckNack: writerGUID = {destGuidPrefix, writerId}

Spec: §8.3.8.1, S. 54 — “writerGUID = { Receiver.destGuidPrefix, AckNack.writerId }”.

Repo: crates/dcps/src/runtime.rs (handle_user_datagram_from: Zuordnung über ack.writer_id)

Tests: crates/dcps/src/runtime.rs::tests::the_submessages_after_an_info_destination_for_another_participant_are_not_ours

Status: done

§8.3.8.1 AckNack: readerGUID = {sourceGuidPrefix, readerId}

Spec: §8.3.8.1, S. 55 — “readerGUID = { Receiver.sourceGuidPrefix, AckNack.readerId }”.

Repo: crates/dcps/src/runtime.rs (handle_user_datagram_from: Guid::new(src_prefix, ack.reader_id)); crates/rtps/src/reliable_writer.rs (handle_acknack_window)

Tests: crates/rtps/src/reliable_writer.rs::tests::handle_acknack_unknown_source_counts_but_noops, crates/rtps/src/reliable_writer.rs::tests::acknack_dispatches_to_matching_proxy_only

Status: done

§8.3.8.1 AckNack: positive Bestätigung bis base − 1

Spec: §8.3.8.1, S. 55 — “The Submessage acknowledges all sequence numbers up to and including the one just before the lowest sequence number in the SequenceNumberSet (that is readerSNState.base -1).”

Repo: crates/rtps/src/reliable_writer.rs (handle_acknack_window: acked_changes_set(base)); crates/rtps/src/reader_proxy.rs (ReaderProxy::acked_changes_set)

Tests: crates/rtps/src/reader_proxy.rs::tests::acked_changes_set_monotonic, crates/rtps/src/reliable_writer.rs::tests::is_acked_by_all_follows_the_slowest_reader_proxy

Status: done

§8.3.8.1 AckNack: negative Bestätigung der Menge

Spec: §8.3.8.1, S. 55 — “The Submessage negatively-acknowledges (requests) the sequence numbers that appear explicitly in the set.”

Repo: crates/rtps/src/reliable_writer.rs (handle_acknack_window: requested_changes_set)

Tests: crates/rtps/src/reliable_writer.rs::tests::tick_resends_requested_as_data_aggregated_with_hb, crates/rtps/src/reader_proxy.rs::tests::a_request_for_an_acknowledged_change_is_kept

Status: done

§8.3.8.2 Data: Purpose

Spec: §8.3.8.2, S. 55 — “The Submessage notifies the RTPS Reader of a change to a data-object belonging to the RTPS Writer.”

Repo: —

Tests: —

Status: n/a (informative) — Zweckangabe.

§8.3.8.2 Table 8.41 Data EndiannessFlag

Spec: §8.3.8.2, S. 55, Table 8.41 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::write_body, DataSubmessage::read_body_with_flags)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_roundtrip_be_with_empty_payload, crates/rtps/src/submessages.rs::tests::data_submessage_roundtrip_le

Status: done

§8.3.8.2 Table 8.41 Data InlineQosFlag

Spec: §8.3.8.2, S. 55, Table 8.41 — “InlineQosFlag … Indicates to the Reader the presence of a ParameterList containing QoS parameters that should be used to interpret the message.”

Repo: crates/rtps/src/submessages.rs (DATA_FLAG_INLINE_QOS, DataSubmessage::inline_qos)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_all_valid_flags_combined_roundtrip, crates/rtps/src/submessages.rs::tests::a_pid_ignore_in_the_inline_qos_does_not_move_the_payload

Status: done

§8.3.8.2 Table 8.41 Data DataFlag

Spec: §8.3.8.2, S. 55, Table 8.41 — “DataFlag … Indicates to the Reader that the dataPayload submessage element contains the serialized value of the data-object.”

Repo: crates/rtps/src/submessages.rs (DATA_FLAG_DATA, DataSubmessage::data_flag)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_roundtrip_le, crates/rtps/src/reliable_reader.rs::tests::alive_data_yields_alive_changekind

Status: done

§8.3.8.2 Table 8.41 Data KeyFlag

Spec: §8.3.8.2, S. 55, Table 8.41 — “KeyFlag … Indicates to the Reader that the dataPayload submessage element contains the serialized value of the key of the data-object.”

Repo: crates/rtps/src/submessages.rs (DATA_FLAG_KEY, DataSubmessage::key_flag)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_key_flag_roundtrip, crates/rtps/src/reliable_writer.rs::tests::lifecycle_with_a_key_sets_k_and_carries_it

Status: done

§8.3.8.2 Table 8.41 Data NonStandardPayloadFlag

Spec: §8.3.8.2, S. 55, Table 8.41 — “NonStandardPayloadFlag … Indicates to the Reader that the serializedPayload submessage element is not formatted according to Section 10.”

Repo: crates/rtps/src/submessages.rs (DATA_FLAG_NON_STANDARD, DataSubmessage::non_standard_flag)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_non_standard_flag_roundtrip

Status: done

§8.3.8.2 Table 8.41 Data readerId

Spec: §8.3.8.2, S. 55, Table 8.41 — “readerId: EntityId — Identifies the RTPS Reader entity that is being informed of the change to the data-object.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::reader_id)

Tests: crates/rtps/src/reader.rs::tests::reader_drops_data_addressed_to_other_reader, crates/rtps/src/reader.rs::tests::reader_delivers_data_addressed_to_us

Status: done

§8.3.8.2 Table 8.41 Data writerId

Spec: §8.3.8.2, S. 55, Table 8.41 — “writerId: EntityId — Identifies the RTPS Writer entity that made the change to the data-object.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::writer_id)

Tests: crates/rtps/src/reliable_reader.rs::tests::mismatched_writer_id_is_counted

Status: done

§8.3.8.2 Table 8.41 Data writerSN

Spec: §8.3.8.2, S. 56, Table 8.41 — “writerSN: SequenceNumber — Uniquely identifies the change and the relative order for all changes made by the RTPS Writer … Each change gets a consecutive sequence number.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::writer_sn); crates/rtps/src/reliable_writer.rs (ReliableWriter::write)

Tests: crates/rtps/src/writer.rs::tests::writer_three_writes_have_increasing_sn_in_decoded, crates/rtps/src/reliable_reader.rs::tests::out_of_order_data_buffered_until_gap_filled

Status: done

§8.3.8.2 Table 8.41 Data inlineQos

Spec: §8.3.8.2, S. 56, Table 8.41 — “inlineQos: ParameterList — Present only if the InlineQosFlag is set in the header.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::read_body_into: ParameterList nur bei Q)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_all_valid_flags_combined_roundtrip, crates/rtps/src/inline_qos.rs::tests::coherent_set_survives_data_submessage_roundtrip

Status: done

§8.3.8.2 Table 8.41 Data serializedPayload

Spec: §8.3.8.2, S. 56, Table 8.41 — “serializedPayload: SerializedPayload — Present only if either the DataFlag or the KeyFlag are set in the header.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::serialized_payload)

Tests: crates/rtps/src/reliable_writer.rs::tests::lifecycle_without_a_key_clears_k_and_sends_no_payload, crates/rtps/tests/cyclone_compliance.rs::cyclone_data_empty_payload_decodes

Status: done

§8.3.8.2 Data ungültig: submessageLength zu klein

Spec: §8.3.8.2, S. 56 — “submessageLength in the Submessage header is too small.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::read_body_into)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — die Kürzung wird erkannt; die Submessage ist ungültig und mit ihr der Rest der Nachricht, die Submessages davor bleiben (ParsedDatagram::invalid_rest, gezählt).

§8.3.8.2 Data ungültig: writerSN ≤ 0 oder SEQUENCENUMBER_UNKNOWN

Spec: §8.3.8.2, S. 56 — “writerSN.value is not strictly positive (1, 2, …) or is SEQUENCENUMBER_UNKNOWN.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::read_body_into)

Tests: crates/rtps/src/submessages.rs::validity_tests::data_with_writer_sn_not_positive_or_with_d_and_k_is_invalid

Status: done — writerSN unter 1 und SEQUENCENUMBER_UNKNOWN ({-1, 0}) werden abgewiesen; die Submessage ist ungültig und mit ihr der Rest der Nachricht.

§8.3.8.2 Data ungültig: inlineQos ungültig

Spec: §8.3.8.2, S. 56 — “inlineQos is invalid.”

Repo: crates/rtps/src/parameter_list.rs (ParameterList::from_bytes_with_consumed); crates/rtps/src/datagram.rs (validate_must_understand_in_data_pipeline)

Tests: crates/rtps/src/parameter_list.rs::tests::decode_rejects_truncated_value, crates/rtps/src/datagram.rs::tests::a_data_with_an_unknown_must_understand_pid_is_skipped, crates/rtps/src/datagram.rs::tests::the_submessages_before_an_invalid_one_stand

Status: done — eine fehlerhafte ParameterList macht die DATA ungültig und verwirft den Rest der Nachricht, die Submessages davor bleiben (§8.3.4.1 Regel 6); eine unbekannte Must-Understand-PID überspringt nur die DATA (Table 9.6).

§8.3.8.2 Data: DataFlag ohne KeyFlag ist der Wert

Spec: §8.3.8.2, S. 56 — “If the DataFlag is set and the KeyFlag is not set, the serializedPayload element is interpreted as the value of the data-object.”

Repo: crates/rtps/src/reliable_reader.rs (classify_change_kind, handle_data_into)

Tests: crates/rtps/src/reliable_reader.rs::tests::alive_data_yields_alive_changekind, crates/rtps/src/reliable_reader.rs::tests::in_order_data_delivered_immediately

Status: done

§8.3.8.2 Data: KeyFlag ohne DataFlag ist der Schlüssel

Spec: §8.3.8.2, S. 56 — “If the KeyFlag is set and the DataFlag is not set, the serializedPayload element is interpreted as the value of the key that identifies the registered instance of the data-object.”

Repo: crates/rtps/src/reliable_reader.rs (handle_data_into: schlüsselinhaltige DATA ohne Lebenszyklus als Registrierung)

Tests: crates/rtps/src/reliable_reader.rs::tests::key_only_alive_registration_is_acked_but_not_delivered, crates/rtps/src/reliable_reader.rs::tests::dispose_data_yields_not_alive_disposed

Status: done

§8.3.8.2 Data: Inline-QoS überschreibt die Writer-QoS

Spec: §8.3.8.2, S. 56 — “If the InlineQosFlag is set, the inlineQos element contains QoS values that override those of the RTPS Writer and should be used to process the update. For a complete list of possible in-line QoS parameters, see Table 8.85.”

Repo: crates/rtps/src/inline_qos.rs (InlineQosOverride); crates/rtps/src/reliable_reader.rs (DeliveredSample::inline_qos_override); crates/dcps/src/runtime.rs (sample_strength, sample_lifespan_nanos)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_data_hands_on_the_in_line_strength_and_lifespan, crates/dcps/src/runtime.rs::tests::the_in_line_strength_and_lifespan_of_a_sample_override_the_writers

Status: done — OWNERSHIP_STRENGTH und LIFESPAN, die ein DATA in-line trägt, gelten für diese Probe statt der angekündigten Werte des Writers. Die übrigen Policies von Table 8.85 wirken nicht auf eine einzelne Probe (sie gehen in den Abgleich beim Match ein: DURABILITY, RELIABILITY, PRESENTATION, PARTITION, DEADLINE, LATENCY_BUDGET, DESTINATION_ORDER, LIVELINESS), TRANSPORT_PRIORITY ist Sache des Senders.

§8.3.8.2 Data: NonStandardPayloadFlag nur informativ

Spec: §8.3.8.2, S. 56 — “This flag is informational. It indicates that the SerializedPayload has been transformed as described in another specification. For example, this flag should be set when the SerializedPayload is transformed as described in the DDS-Security specification.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::non_standard_flag wird gelesen, nicht interpretiert)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_non_standard_flag_roundtrip

Status: done — ob ZeroDDS das Flag bei DDS-Security-transformierten Nutzdaten setzt, ist nicht geprüft.

§8.3.8.2 Data: writerGUID = {sourceGuidPrefix, writerId}

Spec: §8.3.8.2, S. 56 — “writerGUID = { Receiver.sourceGuidPrefix, Data.writerId }”.

Repo: crates/rtps/src/reliable_reader.rs (proxy_index_by_writer); crates/dcps/src/runtime.rs (handle_user_datagram_from: src_prefix aus receiver_walk)

Tests: crates/rtps/src/reliable_reader.rs::tests::same_entity_id_different_prefix_not_confused, crates/discovery/tests/opensplice_infosrc_regression.rs::opensplice_bundled_infosrc_datagrams_attribute_to_the_real_source

Status: done

§8.3.8.2 Data: readerGUID = {destGuidPrefix, readerId}

Spec: §8.3.8.2, S. 56 — “readerGUID = { Receiver.destGuidPrefix, Data.readerId }”.

Repo: crates/dcps/src/runtime.rs (handle_user_datagram_from: rt.reader_slot(d.reader_id))

Tests: crates/dcps/src/runtime.rs::tests::the_submessages_after_an_info_destination_for_another_participant_are_not_ours

Status: done

§8.3.8.2 Data: readerId ENTITYID_UNKNOWN

Spec: §8.3.8.2, S. 56 — “The Data.readerId can be ENTITYID_UNKNOWN, in which case the Data applies to all Readers of that writerGUID within the Participant identified by the GuidPrefix_t Receiver.destGuidPrefix.”

Repo: crates/dcps/src/runtime.rs (handle_user_datagram_from: bei EntityId::UNKNOWN an alle Reader-Slots, Filter über den Writer-Proxy)

Tests: crates/rtps/src/reader.rs::tests::reader_accepts_unknown_wildcard_target

Status: done — die Einschränkung auf den Participant von destGuidPrefix hängt am Item unter §8.3.8.8.

§8.3.8.3 DataFrag: Purpose

Spec: §8.3.8.3, S. 57 — “The DataFrag Submessage extends the Data Submessage by enabling the serializedData to be fragmented and sent as multiple DataFrag Submessages.”

Repo: —

Tests: —

Status: n/a (informative) — Zweckangabe.

§8.3.8.3 Table 8.42 DataFrag EndiannessFlag

Spec: §8.3.8.3, S. 57, Table 8.42 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::write_body, DataFragSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::tests::data_frag_roundtrip_be, crates/rtps/src/submessages.rs::tests::data_frag_roundtrip_le

Status: done

§8.3.8.3 Table 8.42 DataFrag InlineQosFlag

Spec: §8.3.8.3, S. 57, Table 8.42 — “InlineQosFlag … Indicates to the Reader the presence of a ParameterList containing QoS parameters”.

Repo: crates/rtps/src/submessages.rs (DATA_FRAG_FLAG_INLINE_QOS)

Tests: crates/rtps/src/submessages.rs::tests::data_frag_flags_survive_roundtrip, crates/rtps/src/datagram.rs::tests::data_frag_spec_and_cyclone_flag_oracle

Status: done

§8.3.8.3 Table 8.42 DataFrag NonStandardPayloadFlag

Spec: §8.3.8.3, S. 57, Table 8.42 — “NonStandardPayloadFlag … Indicates to the Reader that the serializedPayload submessage element is not formatted according to Section 10.”

Repo: crates/rtps/src/submessages.rs (DATA_FRAG_FLAG_NON_STANDARD)

Tests: crates/rtps/src/submessages.rs::tests::data_frag_flags_survive_roundtrip

Status: done

§8.3.8.3 Table 8.42 DataFrag KeyFlag

Spec: §8.3.8.3, S. 57, Table 8.42 — “KeyFlag … Indicates to the Reader that the dataPayload submessage element contains the serialized value of the key of the data-object.”

Repo: crates/rtps/src/submessages.rs (DATA_FRAG_FLAG_KEY, DataFragSubmessage::key_flag)

Tests: crates/rtps/src/datagram.rs::tests::decode_data_frag_preserves_flags_and_payload

Status: done

§8.3.8.3 Table 8.42 DataFrag readerId

Spec: §8.3.8.3, S. 57, Table 8.42 — “readerId: EntityId — Identifies the RTPS Reader entity that is being informed of the change”.

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::reader_id)

Tests: crates/rtps/src/submessages.rs::tests::data_frag_roundtrip_le

Status: done

§8.3.8.3 Table 8.42 DataFrag writerId

Spec: §8.3.8.3, S. 57, Table 8.42 — “writerId: EntityId — Identifies the RTPS Writer entity that made the change”.

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::writer_id)

Tests: crates/rtps/src/submessages.rs::tests::data_frag_roundtrip_le

Status: done

§8.3.8.3 Table 8.42 DataFrag writerSN

Spec: §8.3.8.3, S. 57, Table 8.42 — “writerSN: SequenceNumber — Uniquely identifies the change and the relative order for all changes made by the RTPS Writer”.

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::writer_sn); crates/rtps/src/fragment_assembler.rs (Puffer je writer_sn)

Tests: crates/rtps/src/fragment_assembler.rs::tests::incomplete_sns_enumerates_in_order

Status: done

§8.3.8.3 Table 8.42 DataFrag fragmentStartingNum

Spec: §8.3.8.3, S. 57, Table 8.42 — “fragmentStartingNum: FragmentNumber — Indicates the starting fragment for the series of fragments in serializedData. Fragment numbering starts with number 1.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::fragment_starting_num)

Tests: crates/rtps/src/fragment_assembler.rs::tests::fragment_index_zero_dropped, crates/rtps/src/fragment_assembler.rs::tests::two_fragments_complete_in_order

Status: done

§8.3.8.3 Table 8.42 DataFrag fragmentsInSubmessage

Spec: §8.3.8.3, S. 58, Table 8.42 — “fragmentsInSubmessage: ushort — The number of consecutive fragments contained in this Submessage, starting at fragmentStartingNum.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::fragments_in_submessage)

Tests: crates/rtps/src/fragment_assembler.rs::tests::bundled_fragments_all_full, crates/rtps/src/fragment_assembler.rs::tests::bundled_fragments_including_last_with_tail

Status: done

§8.3.8.3 Table 8.42 DataFrag dataSize

Spec: §8.3.8.3, S. 58, Table 8.42 — “dataSize: ulong — The total size in bytes of the original data before fragmentation.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::sample_size)

Tests: crates/rtps/src/fragment_assembler.rs::tests::inconsistent_sample_size_drops_fragment

Status: done

§8.3.8.3 Table 8.42 DataFrag fragmentSize

Spec: §8.3.8.3, S. 58, Table 8.42 — “fragmentSize: ushort — The size of an individual fragment in bytes. The maximum fragment size equals 64K.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::fragment_size, Typ u16)

Tests: crates/rtps/src/fragment_assembler.rs::tests::fragment_size_zero_dropped, crates/rtps/src/submessages.rs::tests::data_frag_last_fragment_shorter_than_fragment_size

Status: done

§8.3.8.3 Table 8.42 DataFrag inlineQos

Spec: §8.3.8.3, S. 58, Table 8.42 — “inlineQos: ParameterList — Present only if the InlineQosFlag is set in the header.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::inline_qos)

Tests: crates/rtps/src/submessages.rs::tests::data_frag_key_hash_roundtrips_both_byte_orders, crates/rtps/src/submessages.rs::tests::data_frag_ignored_parameter_does_not_become_payload

Status: done

§8.3.8.3 Table 8.42 DataFrag serializedPayload

Spec: §8.3.8.3, S. 58, Table 8.42 — “A consecutive series of fragments, starting at fragmentStartingNum for a total of fragmentsInSubmessage. … If the KeyFlag is set, then it contains a consecutive set of fragments of the key”.

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::serialized_payload); crates/rtps/src/fragment_assembler.rs (FragmentAssembler::insert)

Tests: crates/rtps/src/fragment_assembler.rs::tests::fragments_complete_out_of_order, crates/rtps/src/fragment_assembler.rs::tests::last_fragment_shorter_than_fragment_size

Status: done

§8.3.8.3 DataFrag ungültig: submessageLength zu klein

Spec: §8.3.8.3, S. 58 — “submessageLength in the Submessage header is too small.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::read_body)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — die Kürzung wird erkannt; die Submessage ist ungültig und mit ihr der Rest der Nachricht, die Submessages davor bleiben (ParsedDatagram::invalid_rest, gezählt).

§8.3.8.3 DataFrag ungültig: writerSN ≤ 0 oder SEQUENCENUMBER_UNKNOWN

Spec: §8.3.8.3, S. 58 — “writerSN.value is not strictly positive (1, 2, …) or is SEQUENCENUMBER_UNKNOWN.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::validity_tests::data_frag_validity_rules

Status: done — wie bei DATA.

§8.3.8.3 DataFrag ungültig: fragmentStartingNum außerhalb

Spec: §8.3.8.3, S. 58 — “fragmentStartingNum.value is not strictly positive (1, 2, …) or exceeds the total number of fragments”.

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::read_body); crates/rtps/src/fragment_assembler.rs (FragmentAssembler::insert: FragmentIndexZero, FragmentIndexOutOfRange)

Tests: crates/rtps/src/submessages.rs::validity_tests::data_frag_validity_rules, crates/rtps/src/fragment_assembler.rs::tests::fragment_index_zero_dropped, crates/rtps/src/fragment_assembler.rs::tests::fragment_index_out_of_range_dropped

Status: done — fragmentStartingNum unter 1 oder über der Zahl der Fragmente (dataSize / fragmentSize, aufgerundet) macht die Submessage und den Rest der Nachricht ungültig.

§8.3.8.3 DataFrag ungültig: fragmentSize > dataSize

Spec: §8.3.8.3, S. 58 — “fragmentSize exceeds dataSize.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::validity_tests::data_frag_validity_rules

Status: done — fragmentSize über dataSize und fragmentSize 0 werden abgewiesen.

§8.3.8.3 DataFrag ungültig: serializedData zu groß

Spec: §8.3.8.3, S. 58 — “The size of serializedData exceeds fragmentsInSubmessage * fragmentSize.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::read_body); crates/rtps/src/fragment_assembler.rs (FragmentAssembler::insert: PayloadSizeMismatch)

Tests: crates/rtps/src/submessages.rs::validity_tests::data_frag_validity_rules, crates/rtps/src/fragment_assembler.rs::tests::payload_size_mismatch_dropped, crates/rtps/src/fragment_assembler.rs::tests::bundled_fragments_payload_size_mismatch_rejected

Status: done — mehr Oktette als fragmentsInSubmessage * fragmentSize machen die Submessage ungültig. Das letzte Fragment des Samples ist so lang, wie das Sample es lässt, auf 4 Oktette aufgerundet: Cyclone DDS und Fast DDS füllen es auf die Ausrichtung der Submessage auf (72 Oktette für 71, gemessen).

§8.3.8.3 DataFrag ungültig: inlineQos ungültig

Spec: §8.3.8.3, S. 58 — “inlineQos is invalid.”

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::validity_tests::data_frag_with_an_invalid_inline_qos_is_invalid

Status: done — eine Parameterliste, die über den Rumpf hinausläuft oder keinen Sentinel hat, macht die Submessage ungültig.

§8.3.8.3 DataFrag: Zusammensetzen, Offset und Fragmentanzahl

Spec: §8.3.8.3, S. 58–59 — Offset “(fragmentStartingNum - 1) * fragmentSize”; “The data is fully re-assembled when all fragments have been received. The total number of fragments to expect equals: (dataSize / fragmentSize) + ((dataSize % fragmentSize) ? 1 : 0)”.

Repo: crates/rtps/src/fragment_assembler.rs (FragmentAssembler::insert: byte_start, total_fragments = sample_size.div_ceil(fragment_size))

Tests: crates/rtps/src/fragment_assembler.rs::tests::fragments_complete_out_of_order, crates/rtps/src/fragment_assembler.rs::tests::missing_fragments_enumerates_gaps, crates/rtps/tests/reliable_e2e.rs::e2e_frag_large_sample_10_percent_loss

Status: done

§8.3.8.3 DataFrag: zusammengesetzt wie Data zu interpretieren

Spec: §8.3.8.3, S. 58 — “Once the serializedData is re-assembled by the RTPS Reader, the interpretation of the DataFrag Submessages is identical to that of the Data Submessage.”

Repo: —

Tests: crates/rtps/src/reliable_reader.rs::tests::a_fragmented_dispose_is_delivered_as_a_dispose, crates/rtps/src/fragment_assembler.rs::tests::the_first_fragments_inline_qos_reaches_the_completed_sample

Status: done

§8.3.8.3 DataFrag: Fragmentgröße nach kleinstem Transport

Spec: §8.3.8.3, S. 59 — “An RTPS Writer will select fragmentSize based on the smallest message size supported across all underlying transports. … the RTPS Writer can pack multiple fragments into a single DataFrag Submessage or may even send a regular Data Submessage if fragmentation is no longer required.”

Repo: crates/rtps/src/reliable_writer.rs (fragment_size_for_message_size, fragments_per_message, ReliableWriterConfig::fragment_size); crates/transport/src/lib.rs (Transport::max_message_size); crates/dcps/src/runtime.rs (Writer-Anlage)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_under_fragment_size_produces_single_data, crates/rtps/src/reliable_writer.rs::tests::write_above_fragment_size_packs_the_fragments_a_message_carries, crates/rtps/src/reliable_writer.rs::tests::fragment_size_is_fixed_and_a_larger_path_gets_one_data, crates/dcps/src/runtime.rs::tests::a_writers_fragment_size_follows_the_message_size_of_its_transport

Status: done — die Fragmentgröße eines Writers folgt der kleinsten Nachrichtengröße seiner Transporte (Transport::max_message_size, Item unter §8.4.14.1); mehrere Fragmente gehen in ein DATA_FRAG, wo die Nachricht sie trägt; ein Pfad, der ohne Fragmentierung auskommt, erhält ein DATA.

§8.3.8.3 DataFrag: Inline-QoS nur im ersten Fragment nötig

Spec: §8.3.8.3, S. 59 — “When sending inlineQos with DataFrag Submessages, it is only required to send the inlineQos with the first DataFrag Submessage for a given Writer sequence number.”

Repo: crates/rtps/src/reliable_writer.rs (Inline-QoS mit PID_KEY_HASH an den DATA_FRAG eines Samples)

Tests: crates/rtps/src/reliable_writer.rs::tests::keyed_alive_preserves_inline_hash_on_data_fragments_and_rebuilds

Status: done — die Inline-QoS eines Coherent-Set-Mitglieds auf dem ersten DATA_FRAG ist unter §8.7.6 geführt.

§8.3.8.4 Gap: Purpose und gefilterte Changes

Spec: §8.3.8.4, S. 59 — “indicates to the RTPS Reader that a set of changes in the RTPS Writer HistoryCache are not available to one or more RTPS Reader endpoints and will not be sent to them. … Filtered changes should not be treated as samples lost by the RTPS Reader.”

Repo: crates/rtps/src/reliable_reader.rs (handle_gap: irrelevant_change_set)

Tests: crates/rtps/src/writer_proxy.rs::tests::gap_marks_irrelevant, crates/rtps/src/writer_proxy.rs::tests::lost_changes_update_counts_what_was_neither_received_nor_irrelevant

Status: done

§8.3.8.4 Table 8.43 Gap EndiannessFlag

Spec: §8.3.8.4, S. 59, Table 8.43 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/submessages.rs (GapSubmessage::write_body, GapSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::tests::gap_submessage_roundtrip_le, crates/rtps/src/submessages.rs::tests::gap_with_group_info_roundtrip_be

Status: done

§8.3.8.4 Table 8.43 Gap GroupInfoFlag

Spec: §8.3.8.4, S. 59, Table 8.43 — “GroupInfoFlag … Indicates the presence of additional information about the group of writers (Writer Group) the sender belongs to.”

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::gap_with_group_info_roundtrip_be, crates/rtps/src/submessages.rs::tests::gap_decode_rejects_invalid_group_sequence_numbers, crates/rtps/src/submessages.rs::tests::a_gap_end_gsn_one_below_its_start_is_an_empty_range_and_valid, crates/rtps/src/submessages.rs::tests::the_gap_flags_are_those_of_9_4_5_6

Status: done

§8.3.8.4 Table 8.43 Gap FilteredCountFlag

Spec: §8.3.8.4, S. 59, Table 8.43 — “FilteredCountFlag … Indicates the presence of the filteredCount submessage element.”

Repo: crates/rtps/src/submessages.rs (GAP_FLAG_FILTERED_COUNT)

Tests: crates/rtps/src/submessages.rs::tests::the_gap_flags_are_those_of_9_4_5_6, crates/rtps/src/submessages.rs::tests::gap_with_filtered_count_roundtrip_le

Status: done

§8.3.8.4 Table 8.43 Gap readerId

Spec: §8.3.8.4, S. 59, Table 8.43 — “The readerId may be set to ENTITYID_UNKNOWN to indicate the Gap message applies to all Readers within the receiving Participant that are matched with the Writer specified by the writerId.”

Repo: crates/rtps/src/submessages.rs (GapSubmessage::reader_id); crates/dcps/src/runtime.rs (handle_user_datagram_from: Verteilung bei EntityId::UNKNOWN)

Tests: crates/rtps/src/submessages.rs::tests::gap_submessage_roundtrip_le

Status: done

§8.3.8.4 Table 8.43 Gap writerId

Spec: §8.3.8.4, S. 60, Table 8.43 — “writerId: EntityId — Identifies the Writer Entity to which the not-available changes apply.”

Repo: crates/rtps/src/submessages.rs (GapSubmessage::writer_id); crates/rtps/src/reliable_reader.rs (handle_gap)

Tests: crates/rtps/src/reliable_reader.rs::tests::gap_after_the_held_data_releases_it

Status: done

§8.3.8.4 Table 8.43 Gap gapStart

Spec: §8.3.8.4, S. 60, Table 8.43 — “gapStart: SequenceNumber — Identifies the first sequence number in the interval of sequence numbers corresponding to the set of not-available changes.”

Repo: crates/rtps/src/submessages.rs (GapSubmessage::gap_start)

Tests: crates/rtps/src/reliable_reader.rs::tests::gap_before_any_heartbeat_lets_the_next_data_through

Status: done

§8.3.8.4 Table 8.43 Gap gapList

Spec: §8.3.8.4, S. 60, Table 8.43 — “gapList: SequenceNumberSet — … (1) Identifies the last sequence number in the interval … (2) Identifies an additional list of sequence numbers corresponding to not-available changes.”

Repo: crates/rtps/src/submessages.rs (GapSubmessage::gap_list); crates/rtps/src/reliable_reader.rs (handle_gap)

Tests: crates/rtps/src/reliable_reader.rs::tests::gap_after_the_held_data_releases_it, crates/rtps/src/reliable_writer.rs::tests::tick_resends_evicted_request_as_gap

Status: done

§8.3.8.4 Table 8.43 Gap gapStartGSN

Spec: §8.3.8.4, S. 60, Table 8.43 — “gapStartGSN: SequenceNumber — Present only if the GroupInfoFlag is set in the header.”

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::gap_with_group_info_roundtrip_be, crates/rtps/src/submessages.rs::tests::gap_decode_rejects_invalid_group_sequence_numbers, crates/rtps/src/submessages.rs::tests::a_gap_end_gsn_one_below_its_start_is_an_empty_range_and_valid, crates/rtps/src/submessages.rs::tests::the_gap_flags_are_those_of_9_4_5_6

Status: done

§8.3.8.4 Table 8.43 Gap gapEndGSN

Spec: §8.3.8.4, S. 60, Table 8.43 — “gapEndGSN: SequenceNumber — Present only if the GroupInfoFlag is set in the header. … It shall be greater than or equal to the group sequence number corresponding to the sample identified by gapList.bitmapBase.”

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::gap_with_group_info_roundtrip_be, crates/rtps/src/submessages.rs::tests::gap_decode_rejects_invalid_group_sequence_numbers, crates/rtps/src/submessages.rs::tests::a_gap_end_gsn_one_below_its_start_is_an_empty_range_and_valid, crates/rtps/src/submessages.rs::tests::the_gap_flags_are_those_of_9_4_5_6

Status: done

§8.3.8.4 Table 8.43 Gap filteredCount

Spec: §8.3.8.4, S. 60, Table 8.43 — “filteredCount: ChangeCount — Present only if the FilteredCountFlag is set in the header. Indicates the number of changes corresponding to the set of sequence numbers in the Gap that are still present in the Writer cache but are being filtered for the RTPS Reader.”

Repo: crates/rtps/src/submessages.rs (GapSubmessage::filtered_count)

Tests: crates/rtps/src/submessages.rs::tests::gap_filtered_count_is_eight_octets_high_then_low, crates/rtps/src/submessages.rs::tests::gap_with_filtered_count_roundtrip_le

Status: done

§8.3.8.4 Gap ungültig: submessageLength zu klein

Spec: §8.3.8.4, S. 60 — “submessageLength in the Submessage header is too small.”

Repo: crates/rtps/src/submessages.rs (GapSubmessage::read_body)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — die Kürzung wird erkannt; die Submessage ist ungültig und mit ihr der Rest der Nachricht, die Submessages davor bleiben (ParsedDatagram::invalid_rest, gezählt).

§8.3.8.4 Gap ungültig: gapStart ≤ 0

Spec: §8.3.8.4, S. 60 — “gapStart is zero or negative.”

Repo: crates/rtps/src/submessages.rs (GapSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::validity_tests::gap_and_sequence_number_set_validity_rules

Status: done — gapStart unter 1 wird abgewiesen.

§8.3.8.4 Gap ungültig: gapList ungültig

Spec: §8.3.8.4, S. 60 — “gapList is invalid (as defined in 8.3.5.5).”

Repo: crates/rtps/src/submessages.rs (SequenceNumberSet::read_from)

Tests: crates/rtps/src/submessages.rs::validity_tests::gap_and_sequence_number_set_validity_rules, crates/rtps/src/submessages.rs::tests::seqnumset_rejects_num_bits_above_256

Status: done — numBits > 256 und bitmapBase < 1 werden abgewiesen.

§8.3.8.4 Gap ungültig: Group-Felder

Spec: §8.3.8.4, S. 60 — “If GroupInfoFlag is set and: gapStartGSN.value is zero or negative; gapEndGSN.value is zero or negative; gapEndGSN.value < gapStartGSN.value-1”.

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::gap_decode_rejects_invalid_group_sequence_numbers, crates/rtps/src/submessages.rs::tests::gap_decode_rejects_truncated_group_info

Status: done

§8.3.8.4 Gap::sequence_number_set

Spec: §8.3.8.4, S. 60–61 — “1. All sequence numbers in the range gapStart <= sequence_number <= gapList.base -1; 2. All the sequence numbers that appear explicitly listed in the gapList.”

Repo: crates/rtps/src/reliable_reader.rs (handle_gap)

Tests: crates/rtps/src/reliable_reader.rs::tests::gap_after_the_held_data_releases_it, crates/rtps/src/reliable_reader.rs::tests::a_best_effort_reader_counts_the_samples_a_gap_lost

Status: done

§8.3.8.4 Gap: writerGUID = {sourceGuidPrefix, writerId}

Spec: §8.3.8.4, S. 61 — “writerGUID = { Receiver.sourceGuidPrefix, Gap.writerId }”.

Repo: crates/rtps/src/reliable_reader.rs (handle_gap: proxy_index_by_writer(Guid::new(source_prefix, gap.writer_id)))

Tests: crates/rtps/src/reliable_reader.rs::tests::gap_after_the_held_data_releases_it

Status: done

§8.3.8.4 Gap: readerGUID = {destGuidPrefix, readerId}

Spec: §8.3.8.4, S. 61 — “readerGUID = { Receiver.destGuidPrefix, Gap.readerId }”.

Repo: crates/dcps/src/runtime.rs (handle_user_datagram_from)

Tests: crates/dcps/src/runtime.rs::tests::the_submessages_after_an_info_destination_for_another_participant_are_not_ours

Status: done

§8.3.8.4 Gap: GroupInfoFlag-Inhalt

Spec: §8.3.8.4, S. 61 — “The Writer sets the GroupInfoFlag to indicate the presence of the gapStartGSN and gapEndGSN elements. … The gapEndGSN can extend past the Group Sequence Number that corresponds to gapList.bitmapBase”.

Repo: crates/rtps/src/reliable_writer.rs (gap_group_info, note_gsn, GapGroupInfo); crates/rtps/src/submessages.rs; crates/dcps/src/runtime.rs (note_writer_group_progress)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_gap_of_a_group_writer_carries_the_group_sequence_numbers, crates/rtps/src/submessages.rs::tests::gap_with_group_info_roundtrip_be, crates/dcps/src/group_order.rs::tests::a_gap_rules_the_number_out_for_its_writer

Status: done — der Writer eines GROUP-Publishers sendet GAPs mit gesetztem GroupInfoFlag: gapStartGSN ist die Group Sequence Number der weggenommenen Änderung, gapEndGSN dieselbe (Bereich aus einer Nummer; gültig nach §8.3.8.4); die Nummer stammt aus dem Cache oder aus einer begrenzten Merkliste (4096) für Änderungen, die den Cache verlassen haben. Ein Writer ohne Gruppe sendet kein Flag. Der Reader rechnet beide Nummern in die Commit-Regel ein (DcpsRuntime::note_writer_group_progress).

§8.3.8.4 Gap: Inhalt von filteredCount

Spec: §8.3.8.4, S. 61 — “The filteredCount, if present, shall include: Changes filtered due to the writer-side application of a content-filtered-topic … a time filter … Changes that are written in ways that intend to exclude delivery to the Reader. … The filteredCount shall not include changes that are no longer in the RTPS Writer HistoryCache”.

Repo: —

Tests: —

Status: open — Teil der optionalen Filterung auf der Writer-Seite (§8.7.3), die ZeroDDS nicht ausführt. Der Gap-Codec kennt das Feld (GAP_FLAG_FILTERED_COUNT), append_gap setzt filtered_count: None.

§8.3.8.5 HeaderExtension

Spec: §8.3.8.5, S. 61 — “This submessage is logically part of the header and it is defined in 8.3.7.”

Repo: —

Tests: —

Status: n/a (informative) — Verweis; Items unter §8.3.7.

§8.3.8.6 Heartbeat: Purpose

Spec: §8.3.8.6, S. 61 — “This message is sent from an RTPS Writer to an RTPS Reader to communicate the sequence numbers of changes that the Writer has available.”

Repo: —

Tests: —

Status: n/a (informative) — Zweckangabe.

§8.3.8.6 Table 8.44 Heartbeat EndiannessFlag

Spec: §8.3.8.6, S. 62, Table 8.44 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/submessages.rs (HeartbeatSubmessage::write_body, HeartbeatSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_submessage_roundtrip_le, crates/rtps/tests/cyclone_compliance.rs::cyclone_heartbeat_decodes

Status: done

§8.3.8.6 Table 8.44 Heartbeat FinalFlag

Spec: §8.3.8.6, S. 62, Table 8.44 — “FinalFlag … Indicates whether the Reader is required to respond to the Heartbeat or if it is just an advisory heartbeat.”

Repo: crates/rtps/src/submessages.rs (HEARTBEAT_FLAG_FINAL, HeartbeatSubmessage::final_flag)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_submessage_no_final_flag_when_disabled, crates/rtps/src/reliable_writer.rs::tests::periodic_heartbeat_has_final_flag_unset

Status: done

§8.3.8.6 Table 8.44 Heartbeat LivelinessFlag

Spec: §8.3.8.6, S. 62, Table 8.44 — “LivelinessFlag … Indicates that the DDS DataWriter associated with the RTPS Writer of the message has manually asserted its LIVELINESS.”

Repo: crates/rtps/src/submessages.rs (HEARTBEAT_FLAG_LIVELINESS); crates/rtps/src/reliable_writer.rs (ReliableWriter::liveliness_heartbeat)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_submessage_liveliness_flag_roundtrip, crates/rtps/src/reliable_writer.rs::tests::liveliness_heartbeat_is_a_final_heartbeat_with_the_liveliness_flag

Status: done

§8.3.8.6 Table 8.44 Heartbeat GroupInfoFlag

Spec: §8.3.8.6, S. 62, Table 8.44 — “GroupInfoFlag … Indicates the presence of additional information about the group of writers (Writer Group) the sender belongs to.”

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::the_group_info_is_the_three_sequence_numbers_of_9_4_5_7, crates/rtps/src/submessages.rs::tests::heartbeat_with_group_info_roundtrip_le, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_heartbeat_carries_the_groups_numbers

Status: done

§8.3.8.6 Table 8.44 Heartbeat readerId

Spec: §8.3.8.6, S. 62, Table 8.44 — “readerId … Can be set to ENTITYID_UNKNOWN to indicate all readers for the writer that sent the message.”

Repo: crates/rtps/src/submessages.rs (HeartbeatSubmessage::reader_id); crates/dcps/src/runtime.rs (handle_user_datagram_from: Verteilung bei EntityId::UNKNOWN)

Tests: crates/rtps/src/reliable_reader.rs::tests::final_heartbeat_from_unknown_to_data_writer_requests_the_missing_sn

Status: done

§8.3.8.6 Table 8.44 Heartbeat writerId

Spec: §8.3.8.6, S. 62, Table 8.44 — “writerId: EntityId — Identifies the Writer Entity to which the range of sequence numbers applies.”

Repo: crates/rtps/src/submessages.rs (HeartbeatSubmessage::writer_id)

Tests: crates/rtps/src/reliable_reader.rs::tests::unknown_writer_id_in_heartbeat_counts_not_crashes

Status: done

§8.3.8.6 Table 8.44 Heartbeat firstSN

Spec: §8.3.8.6, S. 62, Table 8.44 — “If samples are available in the Writer, identifies the first (lowest) sequence number that is available in the Writer. If no samples are available in the Writer, identifies the lowest sequence number that is yet to be written by the Writer.”

Repo: crates/rtps/src/reliable_writer.rs (append_heartbeat)

Tests: crates/rtps/src/reliable_writer.rs::tests::heartbeat_carries_cache_range, crates/rtps/src/reliable_writer.rs::tests::a_heartbeat_after_the_cache_emptied_announces_the_last_sn_written

Status: done

§8.3.8.6 Table 8.44 Heartbeat lastSN

Spec: §8.3.8.6, S. 62, Table 8.44 — “lastSN: SequenceNumber — Identifies the last (highest) sequence number that the Writer has ever written.”

Repo: crates/rtps/src/reliable_writer.rs (append_heartbeat: last_written_sn)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_heartbeat_after_the_cache_emptied_announces_the_last_sn_written

Status: done

§8.3.8.6 Table 8.44 Heartbeat count

Spec: §8.3.8.6, S. 62, Table 8.44 — “count: Count — A counter that is incremented each time a new Heartbeat message is sent.”

Repo: crates/rtps/src/reliable_writer.rs (append_heartbeat: heartbeat_count.wrapping_add(1))

Tests: crates/rtps/src/reliable_writer.rs::tests::heartbeat_count_increments

Status: done

§8.3.8.6 Table 8.44 Heartbeat currentGSN

Spec: §8.3.8.6, S. 62, Table 8.44 — “currentGSN … Identifies the last (highest) group sequence number written by any DataWriter in the Writer’s Group at the time that the HeartBeat was sent.”

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::the_group_info_is_the_three_sequence_numbers_of_9_4_5_7, crates/rtps/src/submessages.rs::tests::heartbeat_with_group_info_roundtrip_le, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_heartbeat_carries_the_groups_numbers

Status: done

§8.3.8.6 Table 8.44 Heartbeat firstGSN

Spec: §8.3.8.6, S. 62, Table 8.44 — “firstGSN … Identifies the group sequence number corresponding to the sample identified by sequence number firstSN.”

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::the_group_info_is_the_three_sequence_numbers_of_9_4_5_7, crates/rtps/src/submessages.rs::tests::heartbeat_with_group_info_roundtrip_le, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_heartbeat_carries_the_groups_numbers

Status: done

§8.3.8.6 Table 8.44 Heartbeat lastGSN

Spec: §8.3.8.6, S. 62, Table 8.44 — “lastGSN … Identifies the group sequence number corresponding to the sample identified by sequence number lastSN.”

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::the_group_info_is_the_three_sequence_numbers_of_9_4_5_7, crates/rtps/src/submessages.rs::tests::heartbeat_with_group_info_roundtrip_le, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_heartbeat_carries_the_groups_numbers

Status: done

§8.3.8.6 Table 8.44 Heartbeat writerSet

Spec: §8.3.8.6, S. 62, Table 8.44 — “writerSet: GroupDigest … Identifies the subset of Writers that belong to the Writer’s Group at the time the sample with currentGSN was written.”

Repo: crates/rtps/src/submessages.rs (HeartbeatGroupInfo, HeartbeatSubmessage::write_body, read_body); crates/rtps/src/dialect.rs (HeartbeatGroupDigests); crates/rtps/src/reliable_writer.rs (heartbeat_group_info); crates/dcps/src/group_order.rs; wire.omit_heartbeat_group_digests

Tests: crates/rtps/src/submessages.rs::tests::the_group_digests_follow_last_gsn_and_are_optional_on_read, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_heartbeat_carries_the_writer_sets_unless_the_peer_omits_them, crates/dcps/src/group_order.rs::tests::a_heartbeat_whose_writer_sets_are_not_the_discovered_ones_keeps_the_number_open, crates/dcps/tests/runtime_config_layering.rs::the_heartbeat_digest_and_keyless_lifecycle_settings_are_read_from_yaml

Status: done — mit G=1 sendet der Writer nach lastGSN writerSet als GroupDigest (vier Oktette, §9.4.2.19; die ersten vier Oktette des MD5 über das EntityIdSet_t, sortiert, §9.3.2.5; leere Gruppe: Null). Der Reader liest beide, wenn die submessageLength Platz lässt, und nimmt ihr Fehlen an (Bild §9.4.5.7); die Commit-Regel §8.7.5 vergleicht sie mit den entdeckten Writern. wire.omit_heartbeat_group_digests lässt sie beim Senden weg. Widerspruch PIM/PSM: siehe „Widersprüche innerhalb der Spec“.

§8.3.8.6 Table 8.44 Heartbeat secureWriterSet

Spec: §8.3.8.6, S. 62, Table 8.44 — “secureWriterSet: GroupDigest … Reserved for use by the DDS-Security Specification.”

Repo: crates/rtps/src/submessages.rs (HeartbeatGroupInfo, HeartbeatSubmessage::write_body, read_body); crates/rtps/src/dialect.rs (HeartbeatGroupDigests); crates/rtps/src/reliable_writer.rs (heartbeat_group_info); crates/dcps/src/group_order.rs; wire.omit_heartbeat_group_digests

Tests: crates/rtps/src/submessages.rs::tests::the_group_digests_follow_last_gsn_and_are_optional_on_read, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_heartbeat_carries_the_writer_sets_unless_the_peer_omits_them, crates/dcps/src/group_order.rs::tests::a_heartbeat_whose_writer_sets_are_not_the_discovered_ones_keeps_the_number_open, crates/dcps/tests/runtime_config_layering.rs::the_heartbeat_digest_and_keyless_lifecycle_settings_are_read_from_yaml

Status: done — mit G=1 sendet der Writer nach lastGSN secureWriterSet als GroupDigest (vier Oktette, §9.4.2.19; die ersten vier Oktette des MD5 über das EntityIdSet_t, sortiert, §9.3.2.5; leere Gruppe: Null; secureWriterSet ist für DDS-Security reserviert und wird als Null gesendet). Der Reader liest beide, wenn die submessageLength Platz lässt, und nimmt ihr Fehlen an (Bild §9.4.5.7); die Commit-Regel §8.7.5 vergleicht sie mit den entdeckten Writern. wire.omit_heartbeat_group_digests lässt sie beim Senden weg. Widerspruch PIM/PSM: siehe „Widersprüche innerhalb der Spec“.

§8.3.8.6 Heartbeat Beispiel 1: nie geschrieben

Spec: §8.3.8.6, S. 63 — “A Writer that has never written any samples before sending a Heartbeat will send a Heartbeat with firstSN.value = 1, lastSN.value = 0.”

Repo: crates/rtps/src/reliable_writer.rs (append_heartbeat)

Tests: crates/rtps/src/reliable_writer.rs::tests::an_empty_writer_heartbeats_a_reader_until_it_answers

Status: done

§8.3.8.6 Heartbeat Beispiel 2: ein Sample im Cache

Spec: §8.3.8.6, S. 63 — “A Writer that has only one sample in its cache with sequence number SN will send a Heartbeat with firstSN.value = lastSN.value = SN.”

Repo: crates/rtps/src/reliable_writer.rs (append_heartbeat)

Tests: crates/rtps/src/reliable_writer.rs::tests::heartbeat_carries_cache_range

Status: done

§8.3.8.6 Heartbeat Beispiel 3: Teil der Historie im Cache

Spec: §8.3.8.6, S. 63 — “A Writer that has written 10 samples and still has the last 5 samples in its cache will send a Heartbeat with firstSN.value = 6, lastSN.value = 10.”

Repo: crates/rtps/src/reliable_writer.rs (append_heartbeat)

Tests: crates/rtps/src/reliable_writer.rs::tests::keep_last_evicts_oldest_on_overflow

Status: done

§8.3.8.6 Heartbeat Beispiel 4: Cache leer nach Schreiben

Spec: §8.3.8.6, S. 63 — “A Writer that has written 10 samples before sending a Heartbeat but does not have any samples available at the time of the Heartbeat will send a Heartbeat with firstSN.value = 11, lastSN.value = 10.”

Repo: crates/rtps/src/reliable_writer.rs (append_heartbeat: first_sn.min(last + 1))

Tests: crates/rtps/src/reliable_writer.rs::tests::a_heartbeat_after_the_cache_emptied_announces_the_last_sn_written

Status: done

§8.3.8.6 Heartbeat ungültig: submessageLength zu klein

Spec: §8.3.8.6, S. 63 — “submessageLength in the Submessage header is too small”.

Repo: crates/rtps/src/submessages.rs (HeartbeatSubmessage::read_body)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — die Kürzung wird erkannt; die Submessage ist ungültig und mit ihr der Rest der Nachricht, die Submessages davor bleiben (ParsedDatagram::invalid_rest, gezählt).

§8.3.8.6 Heartbeat ungültig: firstSN ≤ 0

Spec: §8.3.8.6, S. 63 — “firstSN.value is zero or negative”.

Repo: crates/rtps/src/submessages.rs (HeartbeatSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::validity_tests::heartbeat_validity_rules

Status: done — firstSN unter 1 wird abgewiesen.

§8.3.8.6 Heartbeat ungültig: lastSN < 0

Spec: §8.3.8.6, S. 63 — “lastSN.value is negative”.

Repo: crates/rtps/src/submessages.rs (HeartbeatSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::validity_tests::heartbeat_validity_rules

Status: done — ein negatives lastSN wird abgewiesen.

§8.3.8.6 Heartbeat ungültig: lastSN < firstSN − 1

Spec: §8.3.8.6, S. 63 — “lastSN.value < firstSN.value - 1”.

Repo: crates/rtps/src/submessages.rs (HeartbeatSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::validity_tests::heartbeat_validity_rules

Status: done — lastSN < firstSN - 1 wird abgewiesen; lastSN = firstSN - 1 (leere Historie) ist gültig.

§8.3.8.6 Heartbeat ungültig: Group-Felder

Spec: §8.3.8.6, S. 63 — sechs Bedingungen für currentGSN, firstGSN und lastGSN bei gesetztem GroupInfoFlag.

Repo: crates/rtps/src/submessages.rs (HeartbeatSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_decode_rejects_invalid_group_sequence_numbers, crates/rtps/src/submessages.rs::tests::a_current_gsn_past_the_writers_last_is_accepted, crates/rtps/src/submessages.rs::tests::heartbeat_decode_rejects_truncated_group_info

Status: done — fünf der sechs Bedingungen werden geprüft. Die sechste, currentGSN > lastGSN, widerspricht der Definition von currentGSN (S. 62–63: die Nummer des zuletzt geschriebenen Samples, das bei lastGSN noch nicht eingerechnet sein kann) und wird nicht angewandt; der Test a_current_gsn_past_the_writers_last_is_accepted hält das fest. Die gewählte Lesart steht unter „Widersprüche innerhalb der Spec“. Cyclone DDS, Fast DDS und OpenDDS senden keine Group-HEARTBEATs; erwartet: keine Wirkung.

§8.3.8.6 Heartbeat: Verfügbarkeit melden

Spec: §8.3.8.6, S. 63 — “It informs the Reader of the sequence numbers that are available in the writer’s HistoryCache so that the Reader may request (using an AckNack) any that it has missed.”

Repo: crates/rtps/src/reliable_reader.rs (handle_heartbeat: update_from_heartbeat); crates/rtps/src/writer_proxy.rs

Tests: crates/rtps/src/writer_proxy.rs::tests::heartbeat_sets_available_range, crates/rtps/src/reliable_reader.rs::tests::heartbeat_with_missing_triggers_acknack_after_delay

Status: done

§8.3.8.6 Heartbeat ohne FinalFlag verlangt AckNack

Spec: §8.3.8.6, S. 63 — “if the FinalFlag is not set, then the Reader must send an AckNack message indicating which CacheChange changes it has received, even if the AckNack indicates it has received all CacheChange changes in the writer’s HistoryCache.”

Repo: crates/rtps/src/reliable_reader.rs (handle_heartbeat, tick_outbound)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_heartbeat_without_the_final_flag_is_answered_when_everything_is_received

Status: done — ein HEARTBEAT ohne FinalFlag löst einen ACKNACK aus, auch wenn alles empfangen ist (bitmapBase hinter der letzten Nummer, nichts fehlt), mit und ohne LivelinessFlag.

§8.3.8.6 Heartbeat LivelinessFlag erneuert die manuelle Lease

Spec: §8.3.8.6, S. 63 — “The RTPS Reader should therefore renew the manual liveliness lease of the corresponding remote DDS DataWriter.”

Repo: crates/dcps/src/runtime.rs (handle_user_datagram_from: liveliness.writer_asserted bei h.liveliness_flag)

Tests: crates/dcps/tests/liveliness_qos.rs::linux::assert_liveliness_keeps_a_manual_writer_alive_at_a_remote_reader

Status: done

§8.3.8.6 Heartbeat: GroupInfoFlag-Inhalt

Spec: §8.3.8.6, S. 64 — “The Writer sets the GroupInfoFlag to indicate the presence of the currentGSN, firstGSN, lastGSN, writerSet, and secureWriterSet elements.”

Repo: crates/rtps/src/submessages.rs; crates/rtps/src/reliable_writer.rs (heartbeat_group_info)

Tests: crates/rtps/src/submessages.rs::tests::the_group_digests_follow_last_gsn_and_are_optional_on_read, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_heartbeat_carries_the_writer_sets_unless_the_peer_omits_them, crates/dcps/src/group_order.rs::tests::a_heartbeat_whose_writer_sets_are_not_the_discovered_ones_keeps_the_number_open, crates/dcps/tests/runtime_config_layering.rs::the_heartbeat_digest_and_keyless_lifecycle_settings_are_read_from_yaml, crates/rtps/src/submessages.rs::tests::heartbeat_with_group_info_roundtrip_le, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_heartbeat_carries_the_groups_numbers

Status: done — currentGSN, firstGSN, lastGSN, writerSet und secureWriterSet werden gesendet und gelesen (siehe die Items writerSet und secureWriterSet).

§8.3.8.6 Heartbeat: writerGUID = {sourceGuidPrefix, writerId}

Spec: §8.3.8.6, S. 64 — “writerGUID = { Receiver.sourceGuidPrefix, Heartbeat.writerId }”.

Repo: crates/rtps/src/reliable_reader.rs (handle_heartbeat)

Tests: crates/rtps/src/reliable_reader.rs::tests::same_entity_id_different_prefix_not_confused

Status: done

§8.3.8.6 Heartbeat: readerGUID = {destGuidPrefix, readerId}

Spec: §8.3.8.6, S. 64 — “readerGUID = { Receiver.destGuidPrefix, Heartbeat.readerId }. The Heartbeat.readerId can be ENTITYID_UNKNOWN, in which case the Heartbeat applies to all Readers of that writerGUID within the Participant.”

Repo: crates/dcps/src/runtime.rs (handle_user_datagram_from)

Tests: crates/dcps/src/runtime.rs::tests::the_submessages_after_an_info_destination_for_another_participant_are_not_ours

Status: done

§8.3.8.7 HeartbeatFrag: Purpose

Spec: §8.3.8.7, S. 64 — “When fragmenting data and until all fragments are available, the HeartbeatFrag Submessage is sent from an RTPS Writer to an RTPS Reader to communicate which fragments the Writer has available.”

Repo: —

Tests: —

Status: n/a (informative) — Zweckangabe; ZeroDDS sendet ein Sample erst, wenn alle Fragmente vorliegen.

§8.3.8.7 Table 8.45 HeartbeatFrag EndiannessFlag

Spec: §8.3.8.7, S. 64, Table 8.45 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/submessages.rs (HeartbeatFragSubmessage::write_body, HeartbeatFragSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_frag_roundtrip_be

Status: done

§8.3.8.7 Table 8.45 HeartbeatFrag readerId

Spec: §8.3.8.7, S. 64, Table 8.45 — “readerId … Can be set to ENTITYID_UNKNOWN to indicate all readers for the writer that sent the message.”

Repo: crates/rtps/src/submessages.rs (HeartbeatFragSubmessage::reader_id)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_frag_roundtrip_le

Status: done

§8.3.8.7 Table 8.45 HeartbeatFrag writerId

Spec: §8.3.8.7, S. 64, Table 8.45 — “writerId: EntityId — Identifies the Writer Entity that sent the Submessage.”

Repo: crates/rtps/src/submessages.rs (HeartbeatFragSubmessage::writer_id)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_frag_roundtrip_le

Status: done

§8.3.8.7 Table 8.45 HeartbeatFrag writerSN

Spec: §8.3.8.7, S. 64, Table 8.45 — “writerSN: SequenceNumber — Identifies the sequence number of the data change for which fragments are available.”

Repo: crates/rtps/src/submessages.rs (HeartbeatFragSubmessage::writer_sn)

Tests: crates/rtps/src/datagram.rs::tests::decode_heartbeat_frag_roundtrip

Status: done

§8.3.8.7 Table 8.45 HeartbeatFrag lastFragmentNum

Spec: §8.3.8.7, S. 64, Table 8.45 — “lastFragmentNum: FragmentNumber — All fragments up to and including this last (highest) fragment are available on the Writer for the change identified by writerSN.”

Repo: crates/rtps/src/submessages.rs (HeartbeatFragSubmessage::last_fragment_num)

Tests: crates/rtps/src/datagram.rs::tests::decode_heartbeat_frag_roundtrip

Status: done

§8.3.8.7 Table 8.45 HeartbeatFrag count

Spec: §8.3.8.7, S. 64, Table 8.45 — “count: Count — A counter that is incremented each time a new HeartbeatFrag message is sent.”

Repo: crates/rtps/src/submessages.rs (HeartbeatFragSubmessage::count)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_frag_roundtrip_le

Status: done — ZeroDDS sendet keine HEARTBEAT_FRAG; das Feld wird kodiert und gelesen.

§8.3.8.7 HeartbeatFrag ungültig: submessageLength zu klein

Spec: §8.3.8.7, S. 64 — “submessageLength in the Submessage header is too small”.

Repo: crates/rtps/src/submessages.rs (HeartbeatFragSubmessage::read_body)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — die Kürzung wird erkannt; die Submessage ist ungültig und mit ihr der Rest der Nachricht, die Submessages davor bleiben (ParsedDatagram::invalid_rest, gezählt).

§8.3.8.7 HeartbeatFrag ungültig: writerSN ≤ 0

Spec: §8.3.8.7, S. 64 — “writerSN.value is zero or negative”.

Repo: crates/rtps/src/submessages.rs (HeartbeatFragSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::validity_tests::fragment_submessages_validity_rules, crates/rtps/src/reliable_reader.rs::tests::a_heartbeat_frag_is_answered_when_an_available_fragment_is_missing

Status: done — writerSN unter 1 wird abgewiesen.

§8.3.8.7 HeartbeatFrag ungültig: lastFragmentNum ≤ 0

Spec: §8.3.8.7, S. 64 — “lastFragmentNum.value is zero or negative”.

Repo: crates/rtps/src/submessages.rs (HeartbeatFragSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::validity_tests::fragment_submessages_validity_rules, crates/rtps/src/reliable_reader.rs::tests::a_heartbeat_frag_is_answered_when_an_available_fragment_is_missing

Status: done — lastFragmentNum unter 1 wird abgewiesen.

§8.3.8.7 HeartbeatFrag: Reader antwortet mit NackFrag

Spec: §8.3.8.7, S. 65 — “The RTPS Reader will respond by sending a NackFrag message, but only if it is missing any of the available fragments.”

Repo: crates/rtps/src/reliable_reader.rs (ReliableReader::handle_heartbeat_frag), crates/dcps/src/runtime.rs (handle_user_datagram_from)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_heartbeat_frag_is_answered_when_an_available_fragment_is_missing

Status: done

§8.3.8.7 HeartbeatFrag: writerGUID/readerGUID

Spec: §8.3.8.7, S. 65 — “writerGUID = { Receiver.sourceGuidPrefix, HeartbeatFrag.writerId } … readerGUID = { Receiver.destGuidPrefix, HeartbeatFrag.readerId } … can be ENTITYID_UNKNOWN”.

Repo: crates/dcps/src/runtime.rs (handle_user_datagram_from: readerId oder ENTITYID_UNKNOWN), crates/rtps/src/reliable_reader.rs (proxy_index_by_writer)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_heartbeat_frag_is_answered_when_an_available_fragment_is_missing

Status: done

§8.3.8.8 InfoDestination: Purpose

Spec: §8.3.8.8, S. 65 — “This message is sent from an RTPS Writer to an RTPS Reader to modify the GuidPrefix used to interpret the Reader entityIds appearing in the Submessages that follow it.”

Repo: —

Tests: —

Status: n/a (informative) — Zweckangabe.

§8.3.8.8 Table 8.46 InfoDestination EndiannessFlag

Spec: §8.3.8.8, S. 65, Table 8.46 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/datagram.rs (decode_datagram, encode_datagram für InfoDestination)

Tests: crates/rtps/src/datagram.rs::tests::info_dst_decodes_to_typed_destination_prefix

Status: done

§8.3.8.8 Table 8.46 InfoDestination guidPrefix

Spec: §8.3.8.8, S. 65, Table 8.46 — “guidPrefix: GuidPrefix — Provides the GuidPrefix that should be used to reconstruct the GUIDs of all the RTPS Reader entities whose EntityIds appears in the Submessages that follow.”

Repo: crates/rtps/src/datagram.rs (ParsedSubmessage::InfoDestination); crates/rtps/src/reliable_reader.rs (wrap_to_writer sendet INFO_DST vor ACKNACK/NACK_FRAG)

Tests: crates/rtps/src/datagram.rs::tests::info_dst_body_of_exactly_twelve_decodes, crates/rtps/src/reliable_reader.rs::tests::pre_emptive_acknack_carries_info_dst, crates/rtps/src/reliable_writer.rs::tests::every_proxy_directed_datagram_carries_info_dst_not_just_the_heartbeat_path

Status: done

§8.3.8.8 InfoDestination ungültig: submessageLength zu klein

Spec: §8.3.8.8, S. 65 — “submessageLength in the Submessage header is too small.”

Repo: crates/rtps/src/datagram.rs (decode_datagram, InfoDestination)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — die Kürzung wird erkannt; die Submessage ist ungültig und mit ihr der Rest der Nachricht, die Submessages davor bleiben (ParsedDatagram::invalid_rest, gezählt).

§8.3.8.8 InfoDestination: destGuidPrefix = guidPrefix

Spec: §8.3.8.8, S. 65 — “if (InfoDestination.guidPrefix != GUIDPREFIX_UNKNOWN) { Receiver.destGuidPrefix = InfoDestination.guidPrefix }”.

Repo: crates/rtps/src/datagram.rs (ReceiverWalk::next)

Tests: crates/rtps/src/datagram.rs::tests::receiver_walk_info_source_does_not_reset_dest_guid_prefix

Status: done

§8.3.8.8 InfoDestination: GUIDPREFIX_UNKNOWN setzt den eigenen Prefix

Spec: §8.3.8.8, S. 65 — “else { Receiver.destGuidPrefix = }”.

Repo: crates/rtps/src/datagram.rs (ReceiverWalk::next, InfoDestination)

Tests: crates/dcps/src/runtime.rs::tests::the_submessages_after_an_info_destination_for_another_participant_are_not_ours

Status: done

§8.3.8.8 destGuidPrefix im Nutzdatenpfad

Spec: §8.3.8.2, S. 56 — “readerGUID = { Receiver.destGuidPrefix, Data.readerId }”; ebenso §8.3.8.4, S. 61 (Gap), §8.3.8.6, S. 64 (Heartbeat), §8.3.8.7, S. 65 (HeartbeatFrag); §8.3.8.3, S. 58 — “the interpretation of the DataFrag Submessages is identical to that of the Data Submessage”; §8.3.8.1, S. 54 — “writerGUID = { Receiver.destGuidPrefix, AckNack.writerId }”; ebenso §8.3.8.12, S. 69 (NackFrag).

Repo: —

Tests: crates/dcps/src/runtime.rs::tests::the_submessages_after_an_info_destination_for_another_participant_are_not_ours

Status: done

§8.3.8.9 InfoReply: Purpose

Spec: §8.3.8.9, S. 66 — “It contains explicit information on where to send a reply to the Submessages that follow it within the same message.”

Repo: —

Tests: —

Status: n/a (informative) — Zweckangabe.

§8.3.8.9 Table 8.47 InfoReply EndiannessFlag

Spec: §8.3.8.9, S. 66, Table 8.47 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/submessages.rs (InfoReplySubmessage::write_body, InfoReplySubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::tests::info_reply_with_multicast_roundtrip_be

Status: done

§8.3.8.9 Table 8.47 InfoReply MulticastFlag

Spec: §8.3.8.9, S. 66, Table 8.47 — “MulticastFlag … Indicates whether the Submessage also contains a multicast address.”

Repo: crates/rtps/src/submessages.rs (INFO_REPLY_FLAG_MULTICAST)

Tests: crates/rtps/src/submessages.rs::tests::info_reply_with_multicast_roundtrip_le, crates/rtps/src/submessages.rs::tests::info_reply_unicast_only_roundtrip_le

Status: done

§8.3.8.9 Table 8.47 InfoReply unicastLocatorList

Spec: §8.3.8.9, S. 66, Table 8.47 — “unicastLocatorList: LocatorList — Indicates an alternative set of unicast addresses that the Writer should use to reach the Readers when replying to the Submessages that follow.”

Repo: crates/rtps/src/submessages.rs (InfoReplySubmessage::unicast_locators)

Tests: crates/rtps/src/submessages.rs::tests::info_reply_empty_unicast_list_is_valid, crates/rtps/src/submessages.rs::tests::info_reply_unicast_only_roundtrip_le

Status: done — ob ein Writer die Liste beim Antworten benutzt, ist unter §8.4 geführt.

§8.3.8.9 Table 8.47 InfoReply multicastLocatorList

Spec: §8.3.8.9, S. 66, Table 8.47 — “multicastLocatorList … Only present when the MulticastFlag is set.”

Repo: crates/rtps/src/submessages.rs (InfoReplySubmessage::multicast_locators)

Tests: crates/rtps/src/submessages.rs::tests::info_reply_with_multicast_roundtrip_le

Status: done

§8.3.8.9 InfoReply ungültig: submessageLength zu klein

Spec: §8.3.8.9, S. 66 — “submessageLength in the Submessage header is too small.”

Repo: crates/rtps/src/submessages.rs (InfoReplySubmessage::read_body)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest, crates/rtps/src/submessages.rs::validity_tests::an_info_reply_locator_of_an_unknown_kind_is_left_out_and_counted

Status: done — die Kürzung wird erkannt; die Submessage ist ungültig und mit ihr der Rest der Nachricht, die Submessages davor bleiben. Ein Locator unbekannter Art in der Liste macht die Submessage nicht ungültig (§9.3.2.4: Herstellerarten): er wird ausgelassen und gezählt (skipped_unknown_locators), die übrigen bleiben.

§8.3.8.9 InfoReply: Receiver.unicastReplyLocatorList

Spec: §8.3.8.9, S. 66 — “Receiver.unicastReplyLocatorList = InfoReply.unicastLocatorList”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_info_reply)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_info_reply_sets_locators, crates/rtps/src/datagram.rs::tests::receiver_walk_info_reply_sets_reply_locators

Status: done

§8.3.8.9 InfoReply: Receiver.multicastReplyLocatorList

Spec: §8.3.8.9, S. 66 — “if ( MulticastFlag ) { Receiver.multicastReplyLocatorList = InfoReply.multicastLocatorList } else { Receiver.multicastReplyLocatorList = }”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_info_reply)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_info_reply_sets_locators, crates/rtps/src/receiver_state.rs::tests::an_info_reply_without_the_multicast_flag_empties_the_multicast_list

Status: done — ohne MulticastFlag wird die Liste geleert.

§8.3.8.10 InfoSource: Purpose

Spec: §8.3.8.10, S. 66 — “This message modifies the logical source of the Submessages that follow.”

Repo: —

Tests: —

Status: n/a (informative) — Zweckangabe.

§8.3.8.10 Table 8.48 InfoSource EndiannessFlag

Spec: §8.3.8.10, S. 67, Table 8.48 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/submessages.rs (InfoSourceSubmessage::write_body, InfoSourceSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::tests::info_source_roundtrip_be

Status: done

§8.3.8.10 Table 8.48 InfoSource protocolVersion

Spec: §8.3.8.10, S. 67, Table 8.48 — “protocolVersion: ProtocolVersion — Indicates the protocol used for subsequent Submessages.”

Repo: crates/rtps/src/submessages.rs (InfoSourceSubmessage::protocol_version)

Tests: crates/rtps/src/submessages.rs::tests::info_source_roundtrip_le

Status: done

§8.3.8.10 Table 8.48 InfoSource vendorId

Spec: §8.3.8.10, S. 67, Table 8.48 — “vendorId: VendorId — Indicates the VendorId of the vendor that originated the subsequent Submessages.”

Repo: crates/rtps/src/submessages.rs (InfoSourceSubmessage::vendor_id)

Tests: crates/rtps/src/submessages.rs::tests::info_source_roundtrip_le

Status: done

§8.3.8.10 Table 8.48 InfoSource guidPrefix

Spec: §8.3.8.10, S. 67, Table 8.48 — “guidPrefix: GuidPrefix — Identifies the Participant that is the container of the RTPS Writer entities that are the source of the Submessages that follow.”

Repo: crates/rtps/src/submessages.rs (InfoSourceSubmessage::guid_prefix)

Tests: crates/rtps/src/datagram.rs::tests::receiver_walk_attributes_submessages_after_info_source_to_the_new_prefix

Status: done

§8.3.8.10 InfoSource ungültig: submessageLength zu klein

Spec: §8.3.8.10, S. 67 — “submessageLength in the Submessage header is too small.”

Repo: crates/rtps/src/submessages.rs (InfoSourceSubmessage::read_body)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — die Kürzung wird erkannt; die Submessage ist ungültig und mit ihr der Rest der Nachricht, die Submessages davor bleiben (ParsedDatagram::invalid_rest, gezählt).

§8.3.8.10 InfoSource: sourceGuidPrefix, sourceVersion, sourceVendorId

Spec: §8.3.8.10, S. 67 — “Receiver.sourceGuidPrefix = InfoSource.guidPrefix; Receiver.sourceVersion = InfoSource.protocolVersion; Receiver.sourceVendorId = InfoSource.vendorId”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_info_source)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_info_source_resets_reply_locators_and_timestamp, crates/discovery/tests/opensplice_infosrc_regression.rs::opensplice_bundled_infosrc_datagrams_attribute_to_the_real_source

Status: done

§8.3.8.10 InfoSource: Reply-Listen = {LOCATOR_INVALID}

Spec: §8.3.8.10, S. 67 — “Receiver.unicastReplyLocatorList = { LOCATOR_INVALID }; Receiver.multicastReplyLocatorList = { LOCATOR_INVALID }”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_info_source)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_info_source_resets_reply_locators_and_timestamp

Status: done — beide Listen werden auf { LOCATOR_INVALID } gesetzt.

§8.3.8.10 InfoSource: haveTimestamp = false

Spec: §8.3.8.10, S. 67 — “haveTimestamp = false”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_info_source)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_info_source_resets_reply_locators_and_timestamp

Status: done

§8.3.8.11 InfoTimestamp: Purpose

Spec: §8.3.8.11, S. 67 — “This Submessage is used to send a timestamp which applies to the Submessages that follow within the same message.”

Repo: —

Tests: —

Status: n/a (informative) — Zweckangabe.

§8.3.8.11 Table 8.49 InfoTimestamp EndiannessFlag

Spec: §8.3.8.11, S. 67, Table 8.49 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/submessages.rs (InfoTimestampSubmessage::write_body, InfoTimestampSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::tests::info_timestamp_roundtrip_be

Status: done

§8.3.8.11 Table 8.49 InfoTimestamp InvalidateFlag

Spec: §8.3.8.11, S. 67, Table 8.49 — “InvalidateFlag … Indicates whether subsequent Submessages should be considered as having a timestamp or not.”

Repo: crates/rtps/src/submessages.rs (INFO_TIMESTAMP_FLAG_INVALIDATE, InfoTimestampSubmessage::invalidate)

Tests: crates/rtps/src/submessages.rs::tests::info_timestamp_invalidate_flag_yields_empty_body, crates/rtps/src/submessages.rs::tests::info_timestamp_decode_with_invalidate_ignores_body

Status: done

§8.3.8.11 Table 8.49 InfoTimestamp timestamp

Spec: §8.3.8.11, S. 67, Table 8.49 — “timestamp: Timestamp — Present only if the InvalidateFlag is not set in the header.”

Repo: crates/rtps/src/submessages.rs (InfoTimestampSubmessage::timestamp, InfoTimestampSubmessage::timestamp_body)

Tests: crates/rtps/src/submessages.rs::tests::info_timestamp_roundtrip_le, crates/rtps/src/reliable_writer.rs::tests::write_stamped_prepends_info_ts_before_data

Status: done

§8.3.8.11 InfoTimestamp ungültig: submessageLength zu klein

Spec: §8.3.8.11, S. 68 — “submessageLength in the Submessage header is too small.”

Repo: crates/rtps/src/submessages.rs (InfoTimestampSubmessage::read_body)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — die Kürzung wird erkannt; die Submessage ist ungültig und mit ihr der Rest der Nachricht, die Submessages davor bleiben (ParsedDatagram::invalid_rest, gezählt).

§8.3.8.11 InfoTimestamp: haveTimestamp und timestamp setzen

Spec: §8.3.8.11, S. 68 — “if ( !InfoTimestamp.InvalidateFlag ) { Receiver.haveTimestamp = true; Receiver.timestamp = InfoTimestamp.timestamp … } else { Receiver.haveTimestamp = false }”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::apply_info_timestamp)

Tests: crates/rtps/src/receiver_state.rs::tests::apply_info_timestamp_sets_value, crates/rtps/src/receiver_state.rs::tests::apply_info_timestamp_with_invalidate_clears, crates/rtps/src/datagram.rs::tests::receiver_walk_info_timestamp_invalidate_clears_have_timestamp

Status: done

§8.3.8.11 InfoTimestamp: Korrektur bei clockSkewDetected

Spec: §8.3.8.11, S. 68 — “if ( Receiver.clockSkewDetected ) { Receiver.timestamp += Receiver.rtpsReceptionTime - Receiver.rtpsSendTimestamp }”.

Repo: crates/rtps/src/receiver_state.rs (ReceiverState::note_reception, note_clock_skew, apply_info_timestamp); crates/rtps/src/datagram.rs (ReceptionClock, ReceiveContext); crates/dcps/src/runtime.rs (receive_context, RuntimeConfig::clock_skew_threshold_s)

Tests: crates/rtps/src/receiver_state.rs::tests::the_reception_time_is_kept_and_checked_against_the_send_time, crates/rtps/src/receiver_state.rs::tests::an_info_timestamp_is_corrected_by_the_clock_skew, crates/rtps/src/datagram.rs::tests::the_walk_with_a_reception_clock_detects_a_skew_and_corrects_the_timestamp, crates/dcps/tests/runtime_config_layering.rs::the_clock_skew_threshold_is_a_setting_and_off_by_default

Status: done — apply_info_timestamp addiert bei clockSkewDetected Empfangs- minus Sendezeit; in jedem Empfangspfad wirkt das, sobald wire.clock_skew_threshold_s gesetzt ist (Vorgabe aus, siehe §8.3.7.4 TimestampFlag).

§8.3.8.11 InfoTimestamp: Quellzeitstempel der folgenden Data/DataFrag

Spec: §8.3.8.11, S. 68 — “The reception of the InfoTimestamp submessage sets the source timestamp associated with any subsequent Data and DataFrag submessages.”

Repo: crates/rtps/src/receiver_state.rs, crates/dcps/src/runtime.rs (handle_user_datagram_from)

Tests: crates/rtps/src/datagram.rs::tests::receiver_walk_info_timestamp_invalidate_clears_have_timestamp, crates/rtps/src/datagram.rs::tests::a_header_extension_timestamp_is_no_source_timestamp, crates/rtps/tests/reliable_e2e.rs::e2e_source_timestamp_round_trips

Status: done — ein INFO_TS setzt den Quellzeitstempel der folgenden Data und DataFrag, der I-Flag-Fall löscht ihn; der Zeitstempel einer HeaderExtension ist rtpsSendTimestamp und kein Quellzeitstempel.

§8.3.8.12 NackFrag: Purpose

Spec: §8.3.8.12, S. 68 — “This Submessage can only contain negative acknowledgements. … Fragments can be negatively acknowledged in any order.”

Repo: —

Tests: —

Status: n/a (informative) — Zweckangabe.

§8.3.8.12 Table 8.50 NackFrag EndiannessFlag

Spec: §8.3.8.12, S. 68, Table 8.50 — “EndiannessFlag … Indicates endianness.”

Repo: crates/rtps/src/submessages.rs (NackFragSubmessage::write_body, NackFragSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::tests::nack_frag_roundtrip_be

Status: done

§8.3.8.12 Table 8.50 NackFrag readerId

Spec: §8.3.8.12, S. 68, Table 8.50 — “readerId: EntityId — Identifies the Reader entity that requests to receive certain fragments.”

Repo: crates/rtps/src/submessages.rs (NackFragSubmessage::reader_id)

Tests: crates/rtps/src/reliable_writer.rs::tests::nackfrag_dispatches_only_to_matching_proxy

Status: done

§8.3.8.12 Table 8.50 NackFrag writerId

Spec: §8.3.8.12, S. 69, Table 8.50 — “writerId: EntityId — Identifies the Writer entity that is the target of the NackFrag message.”

Repo: crates/rtps/src/submessages.rs (NackFragSubmessage::writer_id); crates/rtps/src/reliable_writer.rs (handle_nackfrag)

Tests: crates/rtps/src/reliable_writer.rs::tests::handle_nackfrag_queues_fragment_resends

Status: done

§8.3.8.12 Table 8.50 NackFrag writerSN

Spec: §8.3.8.12, S. 69, Table 8.50 — “writerSN: SequenceNumber — The sequence number for which some fragments are missing.”

Repo: crates/rtps/src/submessages.rs (NackFragSubmessage::writer_sn)

Tests: crates/rtps/src/reliable_writer.rs::tests::tick_resends_requested_fragments

Status: done

§8.3.8.12 Table 8.50 NackFrag fragmentNumberState

Spec: §8.3.8.12, S. 69, Table 8.50 — “fragmentNumberState: FragmentNumberSet — … The fragment numbers that appear in the set indicate missing fragments on the reader side.”

Repo: crates/rtps/src/submessages.rs (NackFragSubmessage::fragment_number_state); crates/rtps/src/reader_proxy.rs (requested_fragments_set)

Tests: crates/rtps/src/reader_proxy.rs::tests::requested_fragments_set_above_ack_only, crates/rtps/src/reliable_writer.rs::tests::handle_nackfrag_queues_fragment_resends

Status: done

§8.3.8.12 Table 8.50 NackFrag count

Spec: §8.3.8.12, S. 69, Table 8.50 — “count: Count — A counter that is incremented each time a new NackFrag message is sent.”

Repo: crates/rtps/src/reliable_reader.rs (build_nackfrag_datagram)

Tests: crates/rtps/src/reliable_reader.rs::tests::the_counts_of_acknack_and_nack_frag_rise_with_each_message

Status: done — aufeinanderfolgende NACK_FRAGs tragen die Zähler 1, 2, 3.

§8.3.8.12 NackFrag ungültig: submessageLength zu klein

Spec: §8.3.8.12, S. 69 — “submessageLength in the Submessage header is too small.”

Repo: crates/rtps/src/submessages.rs (NackFragSubmessage::read_body)

Tests: crates/rtps/src/datagram.rs::tests::a_submessage_length_too_small_invalidates_the_rest_and_keeps_what_came_before, crates/rtps/src/datagram.rs::tests::a_submessage_length_past_the_end_invalidates_the_rest

Status: done — die Kürzung wird erkannt; die Submessage ist ungültig und mit ihr der Rest der Nachricht, die Submessages davor bleiben (ParsedDatagram::invalid_rest, gezählt).

§8.3.8.12 NackFrag ungültig: writerSN ≤ 0

Spec: §8.3.8.12, S. 69 — “writerSN.value is zero or negative.”

Repo: crates/rtps/src/submessages.rs (NackFragSubmessage::read_body)

Tests: crates/rtps/src/submessages.rs::validity_tests::fragment_submessages_validity_rules

Status: done — writerSN unter 1 wird abgewiesen.

§8.3.8.12 NackFrag ungültig: fragmentNumberState ungültig

Spec: §8.3.8.12, S. 69 — “fragmentNumberState is invalid (as defined in 8.3.5.7).”

Repo: crates/rtps/src/submessages.rs (FragmentNumberSet::read_from)

Tests: crates/rtps/src/submessages.rs::validity_tests::fragment_submessages_validity_rules, crates/rtps/src/submessages.rs::tests::fnset_rejects_num_bits_above_256

Status: done — numBits > 256 und bitmapBase < 1 werden abgewiesen.

§8.3.8.12 NackFrag: writerGUID = {destGuidPrefix, writerId}

Spec: §8.3.8.12, S. 69 — “writerGUID = { Receiver.destGuidPrefix, NackFrag.writerId }”.

Repo: crates/dcps/src/runtime.rs (handle_user_datagram_from: rt.writer_slot(nf.writer_id))

Tests: crates/dcps/src/runtime.rs::tests::the_submessages_after_an_info_destination_for_another_participant_are_not_ours

Status: done

§8.3.8.12 NackFrag: readerGUID = {sourceGuidPrefix, readerId}

Spec: §8.3.8.12, S. 69 — “readerGUID = { Receiver.sourceGuidPrefix, NackFrag.readerId }”.

Repo: crates/dcps/src/runtime.rs (handle_user_datagram_from: Guid::new(src_prefix, nf.reader_id)); crates/rtps/src/reliable_writer.rs (handle_nackfrag)

Tests: crates/rtps/src/reliable_writer.rs::tests::handle_nackfrag_unknown_source_counts

Status: done

§8.3.8.13 Pad: Purpose

Spec: §8.3.8.13, S. 69 — “The purpose of this Submessage is to allow the introduction of any padding necessary to meet any desired memory- alignment requirements. It has no other meaning.”

Repo: —

Tests: —

Status: n/a (informative) — Zweckangabe.

§8.3.8.13 Pad: Länge aus submessageLength, immer gültig

Spec: §8.3.8.13, S. 69 — “This Submessage has no contents. … The amount of padding is determined by the value of submessageLength. … This Submessage is always valid.”

Repo: crates/rtps/src/datagram.rs (decode_datagram: PAD als ParsedSubmessage::Unknown übersprungen, Länge 0 als Länge)

Tests: crates/rtps/src/datagram.rs::tests::pad_submessage_is_skipped_and_the_data_behind_it_still_decodes, crates/rtps/src/datagram.rs::tests::pad_submessage_is_skipped_and_re_encoded_byte_for_byte

Status: done


§8.4 Behavior Module

§8.4.1 Overview

Spec: §8.4.1, S. 70 — Gliederung des Moduls; §8.4.2 enthält die Pflichten, §8.4.7–§8.4.12 zwei Referenzimplementierungen.

Repo: —

Tests: —

Status: n/a (informative) — Gliederung.

§8.4.1 DataWriter entfernt Changes nur nach Kommunikationsstand und QoS

Spec: §8.4.1, S. 70 — “It is the responsibility of the DDS DataWriter to only remove those CacheChange changes that can be removed based on the communication status and the DDS DataWriter’s QoS. For example, the HISTORY QoS setting of KEEP_LAST with a depth of 1 allows a DataWriter to remove a CacheChange if a more recent change replaces the value of the same data-object.”

Repo: crates/rtps/src/reliable_writer.rs (remove_acknowledged, KEEP_LAST-Verdrängung über HistoryCache::insert_returning_evicted); crates/dcps/src/runtime.rs (await_writer_room für KEEP_ALL)

Tests: crates/rtps/src/reliable_writer.rs::tests::keep_last_evicts_oldest_on_overflow, crates/rtps/src/history_cache.rs::tests::keep_last_per_instance_keeps_the_newest_of_each_instance, crates/dcps/tests/reader_room_backpressure.rs::a_full_keep_all_reader_blocks_its_writer_and_loses_nothing

Status: done

§8.4.1.1 Example Behavior

Spec: §8.4.1.1, S. 70–72 — “The contents of this sub clause are not part of the formal specification of the protocol.”

Repo: —

Tests: —

Status: n/a (informative) — ausdrücklich nicht Teil der formalen Spec.

§8.4.2 Behavior Required for Interoperability: Geltungsbereich

Spec: §8.4.2, S. 72–73 — die Pflichten gelten für den Austausch zwischen Implementierungen verschiedener Hersteller.

Repo: —

Tests: —

Status: n/a (informative) — Geltungsbereich; die Pflichten folgen einzeln.

§8.4.2.1 Nur RTPS-Nachrichten

Spec: §8.4.2.1, S. 73 — “No other messages can be used than the RTPS Messages defined in 8.3. … Vendors may extend Messages for vendor specific needs using the extension mechanisms provided by the protocol (see 8.6).”

Repo: crates/rtps/src/datagram.rs (decode_datagram, encode_datagram); crates/rtps/src/parameter_list.rs (Hersteller-PIDs SHM_LOCATOR, ZERODDS_TYPE_ID)

Tests: crates/rtps/tests/vendor_frames.rs::cyclone_session_re_encodes_byte_for_byte, crates/rtps/tests/vendor_frames.rs::rti_session_re_encodes_byte_for_byte

Status: done — die Abweichung bei der HeaderExtension-Kennung steht unter §9.4.5.1.1.

§8.4.2.1 Message Receiver umgesetzt

Spec: §8.4.2.1, S. 73 — “Implementations must implement the rules followed by the RTPS Message Receiver, as introduced in 8.3.4 … This requirement also includes proper Message formatting by preceding Entity Submessages with Interpreter Submessages when required”.

Repo: crates/rtps/src/datagram.rs (ParsedDatagram::receiver_walk); crates/rtps/src/reliable_writer.rs (INFO_TS und INFO_DST vor DATA, HEARTBEAT); crates/rtps/src/reliable_reader.rs (wrap_to_writer)

Tests: crates/rtps/src/datagram.rs::tests::receiver_walk_attributes_submessages_after_info_source_to_the_new_prefix, crates/rtps/src/reliable_writer.rs::tests::write_stamped_prepends_info_ts_before_data, crates/rtps/src/reliable_reader.rs::tests::pre_emptive_acknack_carries_info_dst

Status: done — der Receiver ist umgesetzt; die Items zu §8.3.4, §8.3.4.1 und §8.3.8, in denen er von der Spec abwich („Gültige Submessages vor einer ungültigen“, „destGuidPrefix im Nutzdatenpfad“ u. a.), stehen auf done.

§8.4.2.1 Zeitverhalten einstellbar

Spec: §8.4.2.1, S. 73 — “where the requirements on the protocol behavior allow delayed responses or specify periodic events, implementations must allow the end-user to tune those timing characteristics.”

Repo: crates/dcps/src/runtime.rs (RuntimeConfig::nack_response_delay, nack_suppression_duration, writer_heartbeat_period, reader_heartbeat_response_delay, reader_heartbeat_suppression_duration, spdp_period, wlp_period)

Tests: crates/dcps/tests/runtime_config_layering.rs::the_protocol_timing_parameters_are_settings, crates/rtps/src/reliable_writer.rs::tests::a_repair_waits_for_the_nack_response_delay, crates/rtps/src/reliable_writer.rs::tests::a_nack_inside_the_suppression_duration_is_ignored

Status: done — nackResponseDelay, nackSuppressionDuration, heartbeatPeriod, heartbeatResponseDelay, heartbeatSuppressionDuration, SPDP- und WLP-Periode sind einstellbar (writer.*_ms, reader.*_ms, discovery.*_ms, Man-Seite und Beispielkonfiguration).

§8.4.2.1 HEARTBEAT-Zeiten der Nutzer-Endpoints einstellbar

Spec: §8.4.2.1, S. 73 — wie vorheriges Item; §8.4.7.1 Table 8.53 heartbeatPeriod, §8.4.10.1 Table 8.67 heartbeatResponseDelay, heartbeatSuppressionDuration.

Repo: crates/dcps/src/runtime.rs (writer_heartbeat_period, reader_heartbeat_response_delay, reader_heartbeat_suppression_duration)

Tests: crates/dcps/tests/runtime_config_layering.rs::the_protocol_timing_parameters_are_settings

Status: done — writer.heartbeat_period_ms, reader.heartbeat_response_delay_ms, reader.heartbeat_suppression_duration_ms.

§8.4.2.1 SPDP und SEDP umgesetzt

Spec: §8.4.2.1, S. 73 — “For the purpose of interoperability, implementations must implement at least the Simple Participant Discovery Protocol and Simple Endpoint Discovery Protocol (see 8.5.1).”

Repo: crates/discovery/src/spdp.rs; crates/discovery/src/sedp/stack.rs

Tests: crates/discovery/src/spdp.rs::tests::beacon_serializes_to_decodable_datagram, crates/discovery/src/sedp/stack.rs::tests::end_to_end_discovery_between_two_stacks

Status: done — die Einzelpflichten stehen unter §8.5.

§8.4.2.2 Writer senden nicht außer der Reihe

Spec: §8.4.2.2, S. 73 — “A Writer must send out data samples in the order they were added to its HistoryCache.”

Repo: crates/rtps/src/reliable_writer.rs (write_sample_with_inline_qos: Senden nur an einen Proxy, der im Schritt ist; Reparaturen aufsteigend über next_requested_change)

Tests: crates/rtps/tests/reliable_e2e.rs::e2e_zero_loss_delivers_all_in_order, crates/rtps/src/reliable_writer.rs::tests::repairs_in_order_bring_a_lagging_proxy_into_step

Status: done

§8.4.2.2 Writer senden Inline-QoS auf Wunsch des Readers

Spec: §8.4.2.2, S. 73 — “A Writer must honor a Reader’s request to receive data messages with in-line QoS.”

Repo: crates/rtps/src/reliable_writer.rs (set_inline_writer_qos, sample_inline_qos); crates/rtps/src/reader_proxy.rs (ReaderProxy::expects_inline_qos)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_reader_that_expects_inline_qos_gets_the_writers_qos_with_each_data

Status: done

§8.4.2.2 Periodische HEARTBEATs (nur reliable)

Spec: §8.4.2.2, S. 73–74 — “A Writer must periodically inform each matching reliable Reader of the availability of a data sample by sending a periodic HEARTBEAT Message … For strict reliable communication, the Writer must continue to send HEARTBEAT Messages to a Reader until the Reader has either acknowledged receiving all available samples or has disappeared.”

Repo: crates/rtps/src/reliable_writer.rs (tick: announcing, heartbeat_due)

Tests: crates/rtps/src/reliable_writer.rs::tests::tick_emits_heartbeat_after_period, crates/rtps/src/reliable_writer.rs::tests::an_acknowledged_reader_is_heartbeated_until_it_answers_one, crates/rtps/src/reliable_writer.rs::tests::a_reader_that_acknowledged_the_cache_gets_no_periodic_heartbeat

Status: done

§8.4.2.2 Antwort auf eine negative Bestätigung (nur reliable)

Spec: §8.4.2.2, S. 74 — “When receiving an ACKNACK Message indicating a Reader is missing some data samples, the Writer must respond by either sending the missing data samples, sending a GAP message when the sample is not relevant, or sending a HEARTBEAT message when the sample is no longer available.”

Repo: crates/rtps/src/reliable_writer.rs (tick: DATA aus dem Cache, GAP über append_gap für nicht mehr vorhandene Changes)

Tests: crates/rtps/src/reliable_writer.rs::tests::tick_resends_requested_as_data_aggregated_with_hb, crates/rtps/src/reliable_writer.rs::tests::tick_resends_evicted_request_as_gap

Status: done

§8.4.2.2 HEARTBEAT und GAP mit Writer-Group-Information

Spec: §8.4.2.2, S. 74 — “A Writer belonging to a Group shall send HEARTBEAT or GAP Submessages to its matched Readers even if the Reader has acknowledged all of that Writer’s samples.”

Repo: —

Tests: crates/rtps/src/reliable_writer.rs::tests::a_group_writer_heartbeats_an_acknowledged_reader_when_the_group_moved_on, crates/rtps/src/reliable_writer.rs::tests::a_group_writer_with_an_empty_cache_is_due_for_a_heartbeat

Status: done

§8.4.2.3 Best-Effort-Reader sind passiv

Spec: §8.4.2.3, S. 74 — “A best-effort Reader is completely passive as it only receives data and does not send messages itself.”

Repo: crates/rtps/src/reliable_reader.rs (ReliableReader::tick_outbound)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_best_effort_reader_sends_no_acknack

Status: done — ein Reader mit set_best_effort(true) sendet weder ACKNACK noch NACK_FRAG, weder beim Match noch auf HEARTBEATs.

§8.4.2.3 Antwort auf HEARTBEAT ohne FinalFlag

Spec: §8.4.2.3, S. 74 — “Upon receiving a HEARTBEAT Message with final flag not set, the Reader must respond with an ACKNACK Message. … The response may be delayed to avoid message storms.”

Repo: crates/rtps/src/reliable_reader.rs (handle_heartbeat, tick_outbound)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_heartbeat_with_the_liveliness_flag_is_taken_as_a_heartbeat

Status: done

§8.4.2.3 Antwort auf HEARTBEAT mit fehlenden Samples

Spec: §8.4.2.3, S. 74 — “a Reader that is missing some data samples must respond with an ACKNACK Message indicating which data samples are missing. This requirement only applies if the Reader can accommodate these missing samples in its cache … The response is not required when a liveliness HEARTBEAT has both liveliness and final flags set”.

Repo: crates/rtps/src/reliable_reader.rs (handle_heartbeat, tick_outbound, full_for_the_consumer, build_acknack_datagram)

Tests: crates/rtps/src/reliable_reader.rs::tests::heartbeat_with_missing_triggers_acknack_after_delay, crates/rtps/src/reliable_reader.rs::tests::a_cache_full_for_the_consumer_holds_the_acknack_until_it_takes, crates/rtps/src/reliable_reader.rs::tests::a_cache_full_behind_a_missing_change_still_names_it

Status: done

§8.4.2.3 Einmal bestätigt, immer bestätigt (Reader)

Spec: §8.4.2.3, S. 74 — “Once a Reader has positively acknowledged receiving a sample using an ACKNACK Message, it can no longer negatively acknowledge that same sample at a later point.”

Repo: crates/rtps/src/writer_proxy.rs (acknack_base monoton; unreceive_change_set nur oberhalb der Basis)

Tests: crates/rtps/src/writer_proxy.rs::tests::acknack_base_walks_up, crates/rtps/src/reliable_reader.rs::tests::sample_rejected_by_a_full_cache_stays_missing_for_the_acknack

Status: done

§8.4.2.3 Writer sendet erneut bestätigte, wieder angeforderte Samples

Spec: §8.4.2.3, S. 74 — “if a Writer receives a negative acknowledgement to a previously positively acknowledged sample, and the Writer can still service the request, the Writer should send the sample.”

Repo: crates/rtps/src/reader_proxy.rs (requested_changes_set); crates/rtps/src/reliable_writer.rs (handle_acknack_window, tick)

Tests: crates/rtps/src/reader_proxy.rs::tests::a_request_for_an_acknowledged_change_is_kept, crates/rtps/src/reliable_writer.rs::tests::an_acknowledged_change_asked_for_again_is_sent_again

Status: done — eine erneute Anforderung eines bestätigten Samples bleibt stehen; der Writer sendet es, solange es im Cache ist, sonst einen GAP.

§8.4.2.3 ACKNACK nur als Antwort auf HEARTBEAT

Spec: §8.4.2.3, S. 74 — “In steady state, an ACKNACK Message can only be sent as a response to a HEARTBEAT Message from a Writer. ACKNACK Messages can be sent from a Reader when it first discovers a Writer as an optimization.”

Repo: crates/rtps/src/reliable_reader.rs (add_writer_proxy, handle_heartbeat, handle_data_frag_opening, tick_outbound)

Tests: crates/rtps/src/reliable_reader.rs::tests::acknack_and_nack_frag_wait_for_a_heartbeat, crates/rtps/src/reliable_reader.rs::tests::pre_emptive_acknack_emitted_after_add_writer_proxy

Status: done — ein ACKNACK entsteht aus einem HEARTBEAT (Table 8.77 T2) und beim ersten Match eines Writers; weder das erneute add_writer_proxy eines bekannten Writers noch ein DATA_FRAG mit Lücken setzen ihn.

§8.4.3 Implementing the RTPS Protocol

Spec: §8.4.3, S. 75 — “a compliant implementation of the protocol need only satisfy the requirements presented in 8.4.2. … Actual implementations need not necessarily follow the reference implementations.”

Repo: —

Tests: —

Status: n/a (informative) — stellt die Referenzimplementierungen frei. Die Übergänge unter §8.4.8–§8.4.12 werden gegen die ZeroDDS-Typen geprüft, die eine Referenzimplementierung abbilden: ReliableWriter (Stateful Writer, best effort und reliable, Nutzdatenpfad), ReliableReader (Stateful Reader), BestEffortWriter, ReliableStatelessWriter, BestEffortReader (nur in Tests verwendet) und der SPDP-Beacon.

§8.4.4 Zulässige Kombinationen von reliabilityLevel

Spec: §8.4.4, S. 75 — “An RTPS Writer cannot be matched to an RTPS Reader unless either the RTPS Writer has the reliabilityLevel set to RELIABLE, or else both the RTPS Writer and RTPS Reader have the reliabilityLevel set to BEST_EFFORT.”

Repo: crates/qos/src/policies/reliability.rs (ReliabilityKind-Ordnung); QoS-Abgleich beim Match in crates/dcps/src/runtime.rs; der ReaderProxy ist zuverlässig nur bei zuverlässigem Writer und Reader (ReaderProxy::new im SEDP-Match-Pfad von crates/dcps/src/runtime.rs)

Tests: crates/qos/src/policies/reliability.rs::tests::best_effort_lt_reliable, crates/qos/src/policies/reliability.rs::tests::ordering_reliable_higher_than_besteffort, crates/dcps/tests/transient_local_durability.rs::linux::transient_local_writer_delivers_history_to_late_joiner

Status: done — der Abgleich der angebotenen und verlangten QoS ist im DCPS-Audit geführt.

§8.4.4 Stateful und Stateless verständigen sich

Spec: §8.4.4, S. 75 — “a Stateful Writer is able to communicate with a Stateless Reader and vice versa.”

Repo: —

Tests: —

Status: n/a (informative) — Folgerung aus §8.4.2; keine eigene Anforderung.

§8.4.5 Notational Conventions

Spec: §8.4.5, S. 75–76, Table 8.51 — Abkürzungen DW, DR, W, RP, RL, R, WP, WHC, RHC.

Repo: —

Tests: —

Status: n/a (informative) — Schreibweise.

§8.4.6 Table 8.52 Duration_t

Spec: §8.4.6, S. 76, Table 8.52 — “Duration_t: Type used to hold time differences. Should have at least nano-second resolution.”

Repo: crates/qos/src/duration.rs (Duration {seconds, fraction}, 2⁻³² s)

Tests: crates/dcps/src/time.rs::tests::duration_zero_and_infinite_sentinels, crates/rtps/src/participant_data.rs::tests::duration_roundtrip_le

Status: done

§8.4.6 Table 8.52 ChangeForReaderStatusKind

Spec: §8.4.6, S. 76, Table 8.52 — “UNSENT, UNACKNOWLEDGED, REQUESTED, ACKNOWLEDGED, UNDERWAY”.

Repo: crates/rtps/src/reader_proxy.rs (highest_sent_sn, highest_acked_sn, requested_changes statt eines Status je Change)

Tests: crates/rtps/src/reader_proxy.rs::tests::next_unsent_change_walks_sequentially, crates/rtps/src/reader_proxy.rs::tests::acking_also_prunes_requested_changes

Status: done — als Zählerstände und Mengen abgebildet (§8.4.15.1).

§8.4.6 Table 8.52 ChangeFromWriterStatusKind

Spec: §8.4.6, S. 76, Table 8.52 — “NOT_AVAILABLE, MISSING, RECEIVED, UNKNOWN. There are three sub-kinds of NOT_AVAILABLE: NA_FILTERED, NA_REMOVED, NA_UNSPECIFIED”.

Repo: crates/rtps/src/writer_proxy.rs (ChangeFromWriterStatus, WriterProxy::change_status, NotAvailableKind, not_available_change_set, lost_changes_update); crates/rtps/src/reliable_reader.rs (ReliableReader::change_status, handle_gap)

Tests: crates/rtps/src/writer_proxy.rs::tests::change_status_is_kept_per_change_with_the_sub_kind, crates/rtps/src/writer_proxy.rs::tests::lost_changes_update_sets_na_removed_per_change, crates/rtps/src/writer_proxy.rs::tests::not_available_runs_are_joined_and_bounded, crates/rtps/src/reliable_reader.rs::tests::the_reader_keeps_the_status_of_each_change, crates/rtps/src/reliable_reader.rs::tests::a_gap_sorts_its_changes_by_the_filtered_count

Status: done — UNKNOWN, MISSING, RECEIVED und NOT_AVAILABLE mit den Unterarten NA_FILTERED, NA_REMOVED und NA_UNSPECIFIED werden je Änderung geführt (WriterProxy::change_status). Die NOT_AVAILABLE-Änderungen stehen als Läufe gleicher Unterart (höchstens 4096; älter heißt None). lost_changes_update trägt NA_REMOVED ein und zählt es; eine Änderung mit FilteredFlag trägt NA_FILTERED ein.

§8.4.6 Table 8.52 InstanceHandle_t

Spec: §8.4.6, S. 76, Table 8.52 — “Type used to represent the identity of a data-object whose changes in value are communicated by the RTPS protocol.”

Repo: crates/rtps/src/history_cache.rs (CacheChange::key_hash)

Tests: crates/rtps/src/history_cache.rs::tests::the_instance_index_follows_inserts_evictions_and_removals

Status: done — wie Table 8.2 (§8.2.1.2).

§8.4.6 Table 8.52 ParticipantMessageData

Spec: §8.4.6, S. 76, Table 8.52 — “Type used to hold data exchanged between Participants. The most notable use of this type is for the Writer Liveliness Protocol.”

Repo: crates/rtps/src/participant_message_data.rs (ParticipantMessageData)

Tests: crates/rtps/src/participant_message_data.rs::tests::participant_message_data_roundtrip_le

Status: done — Inhalt und Wire-Format unter §8.4.13.4 und §9.6.3.1.

§8.4.7.1 Table 8.53 Writer pushMode

Spec: §8.4.7.1, S. 78, Table 8.53 — “If pushMode==true, then the Writer will push changes to the reader. If pushMode==false, changes will only be announced via heartbeats and only be sent as response to the request of a reader.”

Repo: crates/rtps/src/reliable_writer.rs (set_push_mode, push_mode)

Tests: crates/rtps/src/reliable_writer.rs::tests::push_mode_false_announces_by_heartbeat_and_sends_only_on_request, crates/rtps/src/reliable_writer.rs::tests::push_mode_false_sends_no_data_on_the_piggyback_path

Status: done

§8.4.7.1 Table 8.53 Writer heartbeatPeriod

Spec: §8.4.7.1, S. 78, Table 8.53 — “heartbeatPeriod: Protocol tuning parameter that allows the RTPS Writer to repeatedly announce the availability of data by sending a Heartbeat Message.”

Repo: crates/rtps/src/reliable_writer.rs (ReliableWriterConfig::heartbeat_period, DEFAULT_HEARTBEAT_PERIOD)

Tests: crates/rtps/src/reliable_writer.rs::tests::heartbeat_due_follows_the_last_heartbeat, crates/rtps/src/reliable_writer.rs::tests::tick_emits_heartbeat_after_period

Status: done — die Einstellbarkeit für den Anwender ist unter §8.4.2.1 geführt.

§8.4.7.1 Table 8.53 Writer nackResponseDelay

Spec: §8.4.7.1, S. 78, Table 8.53 — “nackResponseDelay: Protocol tuning parameter that allows the RTPS Writer to delay the response to a request for data from a negative acknowledgment.”

Repo: crates/rtps/src/reliable_writer.rs (set_nack_response_delay); crates/rtps/src/reader_proxy.rs (repair_due)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_repair_waits_for_the_nack_response_delay, crates/rtps/src/reliable_writer.rs::tests::a_zero_nack_response_delay_repairs_on_the_next_tick

Status: done

§8.4.7.1 Table 8.53 Writer nackSuppressionDuration

Spec: §8.4.7.1, S. 78, Table 8.53 — “nackSuppressionDuration: Protocol tuning parameter that allows the RTPS Writer to ignore requests for data from negative acknowledgments that arrive ‘too soon’ after the corresponding change is sent.”

Repo: crates/rtps/src/reliable_writer.rs (set_nack_suppression_duration, too_soon)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_nack_inside_the_suppression_duration_is_ignored

Status: done

§8.4.7.1 Table 8.53 Writer lastChangeSequenceNumber

Spec: §8.4.7.1, S. 78, Table 8.53 — “Internal counter used to assign increasing sequence number to each change made by the Writer.”

Repo: crates/rtps/src/reliable_writer.rs (next_sn, last_written_sn)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_increments_sn_and_returns_data_datagram

Status: done

§8.4.7.1 Table 8.53 Writer writer_cache

Spec: §8.4.7.1, S. 78, Table 8.53 — “writer_cache: HistoryCache — Contains the history of CacheChange changes for this Writer.”

Repo: crates/rtps/src/reliable_writer.rs (ReliableWriter::cache)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_at_cache_capacity_is_error

Status: done

§8.4.7.1 Table 8.53 Writer dataMaxSizeSerialized

Spec: §8.4.7.1, S. 78, Table 8.53 — “Optional attribute that indicates the maximum size of any SerializedPayload that may be sent by the Writer.”

Repo: crates/dcps/src/dds_type.rs (MAX_SERIALIZED_SIZE); crates/dcps/src/publisher.rs (WriterRegistration); crates/dcps/src/runtime.rs (UserWriterConfig::data_max_size_serialized, build_publication_data)

Tests: crates/rtps/src/publication_data.rs::tests::the_max_payload_size_and_the_name_of_a_writer_travel

Status: done — das Attribut ist optional. Der Writer kündigt dataMaxSizeSerialized als PID_TYPE_MAX_SIZE_SERIALIZED an, wenn es gesetzt ist: aus DdsType::MAX_SERIALIZED_SIZE oder aus UserWriterConfig::data_max_size_serialized (der Wert steht ohne Encapsulation-Header, angekündigt wird er mit den 4 Oktetten des Headers). Ohne Wert kündigt er nichts an.

§8.4.7.1 Table 8.54 Writer new

Spec: §8.4.7.1, S. 79 — “this.lastChangeSequenceNumber := 0; this.writer_cache := new HistoryCache;” und Übernahme der Attribute aus dem Konstruktor.

Repo: crates/rtps/src/reliable_writer.rs (ReliableWriter::new: next_sn: 0, neuer HistoryCache)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_increments_sn_and_returns_data_datagram

Status: done

§8.4.7.1 Table 8.54 Writer new_change

Spec: §8.4.7.1, S. 79 — “The sequence number of the CacheChange is automatically set to be the sequenceNumber of the previous change plus one. … ++this.lastChangeSequenceNumber; a_change := new CacheChange(kind, this.guid, this.lastChangeSequenceNumber, data, inlineQos, handle);”

Repo: crates/rtps/src/reliable_writer.rs (stage_sample, write_lifecycle)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_increments_sn_and_returns_data_datagram, crates/rtps/src/writer.rs::tests::writer_sn_overflow_is_error

Status: done

§8.4.7.1 Default nackResponseDelay = 200 ms

Spec: §8.4.7.1, S. 79 — “nackResponseDelay.sec = 0; nackResponseDelay.nanosec = 200 * 1000 * 1000; //200 milliseconds”.

Repo: crates/rtps/src/reliable_writer.rs (DEFAULT_NACK_RESPONSE_DELAY, SPEC_NACK_RESPONSE_DELAY); crates/dcps/src/runtime.rs (RuntimeConfig::nack_response_delay)

Tests: crates/rtps/src/reliable_writer.rs::tests::nack_response_delay_defaults_to_the_spec_200_ms_and_suppression_to_zero, crates/dcps/tests/runtime_config_layering.rs::the_protocol_timing_parameters_are_settings

Status: done — DEFAULT_NACK_RESPONSE_DELAY und RuntimeConfig::nack_response_delay sind 200 ms; ein NACK wird erst nach dieser Zeit mit der Reparatur beantwortet (Test). writer.nack_response_delay_ms: 0 antwortet im nächsten Tick.

§8.4.7.1 Default nackResponseDelay

Spec: §8.4.7.1, S. 79 — “The following timing-related values are used as the defaults in order to facilitate ‘out-of-the-box’ interoperability between implementations.”

Repo: crates/rtps/src/reliable_writer.rs (DEFAULT_NACK_RESPONSE_DELAY, DEFAULT_NACK_SUPPRESSION_DURATION); crates/dcps/src/runtime.rs; man/man5/zerodds.yaml.5; packaging/linux/configs/zerodds.yaml.example

Tests: crates/dcps/tests/runtime_config_layering.rs::the_protocol_timing_parameters_are_settings, crates/rtps/src/reliable_writer.rs::tests::nack_response_delay_defaults_to_the_spec_200_ms_and_suppression_to_zero

Status: done — die Werte der Spec sind die Vorgaben: nackResponseDelay 200 ms, nackSuppressionDuration 0 (Laufzeit, YAML-Vorgabe, Man-Seite, Beispielkonfiguration). Die früheren 0 ms bleiben über writer.nack_response_delay_ms erreichbar; die Tests mit Millisekunden-Uhr setzen 0 ausdrücklich.

§8.4.7.1 Default nackSuppressionDuration = 0

Spec: §8.4.7.1, S. 79 — “nackSuppressionDuration.sec = 0; nackSuppressionDuration.nanosec = 0;”.

Repo: crates/rtps/src/reliable_writer.rs (DEFAULT_NACK_SUPPRESSION_DURATION)

Tests: crates/rtps/src/reliable_writer.rs::tests::nack_response_delay_defaults_to_the_spec_200_ms_and_suppression_to_zero

Status: done

§8.4.7.2 Table 8.55 StatelessWriter reader_locators

Spec: §8.4.7.2, S. 80, Table 8.55 — “The StatelessWriter maintains the list of locators to which it sends the CacheChanges. This list may include both unicast and multicast locators.”

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter::reader_locators, ReaderLocator); crates/discovery/src/spdp.rs (SpdpBeacon, Ziel-Locatoren)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::reader_locators_are_added_looked_up_and_removed

Status: done — die Liste besteht aus ReaderLocator-Objekten mit eigenem Zustand (highest_sent_seq_num, angeforderte Changes, expects_inline_qos).

§8.4.7.2 Table 8.56 StatelessWriter new

Spec: §8.4.7.2, S. 80 — “this.reader_locators := ;”

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter::new: reader_locators leer)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::reader_locators_are_added_looked_up_and_removed, crates/rtps/src/reliable_stateless_writer.rs::tests::shutdown_clears_the_cache_and_the_requests

Status: done

§8.4.7.2 Table 8.56 StatelessWriter reader_locator_add

Spec: §8.4.7.2, S. 80 — “ADD a_locator TO {this.reader_locators};”

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator) reader_locator_add

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::reader_locators_are_added_looked_up_and_removed

Status: done — ein Locator wird als ReaderLocator mit expectsInlineQos hinzugefügt, einmal je Locator. ReliableStatelessWriter wird von keinem Produktionspfad verwendet; kein Hersteller ist gemessen.

§8.4.7.2 Table 8.56 StatelessWriter reader_locator_remove

Spec: §8.4.7.3, S. 81 — “REMOVE a_locator FROM {this.reader_locators};”

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter::reader_locator_remove)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::reader_locators_are_added_looked_up_and_removed

Status: done — ein ReaderLocator wird entfernt; ein zweites Entfernen meldet false.

§8.4.7.2 Table 8.56 StatelessWriter unsent_changes_reset

Spec: §8.4.7.2, S. 81 — “This operation resets the ‘highestSentChangeSN’ for all the ReaderLocators … useful when called periodically to cause the StatelessWriter to keep re-sending all available changes”.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter::unsent_changes_reset, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::unsent_changes_reset_makes_every_change_unsent_again, crates/rtps/src/reliable_stateless_writer.rs::tests::unsent_changes_are_pushed_in_order_then_announced

Status: done — unsent_changes_reset setzt highestSentChangeSN aller ReaderLocatoren auf 0; der nächste Tick sendet alle Changes des Caches erneut an jeden Locator. ReliableStatelessWriter wird von keinem Produktionspfad verwendet; kein Hersteller ist gemessen.

§8.4.7.3 Table 8.57 ReaderLocator-Attribute

Spec: §8.4.7.3, S. 81, Table 8.57 — highestSentChangeSN, requestedChanges, locator, expectsInlineQos.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::reader_locators_are_added_looked_up_and_removed, crates/rtps/src/reliable_stateless_writer.rs::tests::unsent_changes_are_pushed_in_order_then_announced

Status: done — ReaderLocator führt locator, expects_inline_qos, highest_sent_seq_num und die angeforderten Changes. ReliableStatelessWriter wird von keinem Produktionspfad verwendet; kein Hersteller ist gemessen.

§8.4.7.3 Table 8.58 ReaderLocator-Operationen

Spec: §8.4.7.3, S. 81–82, Table 8.58 — new, next_requested_change, next_unsent_change, requested_changes, requested_changes_set, unsent_changes.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::unsent_changes_are_pushed_in_order_then_announced, crates/rtps/src/reliable_stateless_writer.rs::tests::an_acknack_is_answered_at_its_reply_locator_after_the_delay

Status: done — requested_changes, requested_changes_set, next_requested_change, unsent_changes sind Methoden des ReaderLocator; next_unsent_change steckt in der Push-Maschine (next_cached_above). ReliableStatelessWriter wird von keinem Produktionspfad verwendet; kein Hersteller ist gemessen.

§8.4.7.4 Table 8.59 StatefulWriter matched_readers

Spec: §8.4.7.4, S. 83, Table 8.59 — “The StatefulWriter keeps track of all the RTPS Readers matched with it. Each matched reader is represented by an instance of the ReaderProxy class.”

Repo: crates/rtps/src/reliable_writer.rs (reader_proxies, reader_proxies())

Tests: crates/rtps/src/reliable_writer.rs::tests::write_fans_out_to_all_reader_proxies

Status: done

§8.4.7.4 Table 8.60 StatefulWriter new

Spec: §8.4.7.4, S. 83 — “this.matched_readers := ;”

Repo: crates/rtps/src/reliable_writer.rs (ReliableWriter::new mit ReliableWriterConfig::reader_proxies)

Tests: crates/rtps/src/reliable_writer.rs::tests::is_acked_by_all_without_proxies_is_true

Status: done

§8.4.7.4 Table 8.60 StatefulWriter is_acked_by_all

Spec: §8.4.7.4, S. 83 — “return true IF and only IF FOREACH proxy IN this.matched_readers a_change_seq_num IN proxy.acknowledged_changes”.

Repo: crates/rtps/src/reliable_writer.rs (is_acked_by_all)

Tests: crates/rtps/src/reliable_writer.rs::tests::is_acked_by_all_follows_the_slowest_reader_proxy, crates/rtps/src/reliable_writer.rs::tests::is_acked_by_all_without_proxies_is_true

Status: done

§8.4.7.4 Table 8.60 StatefulWriter matched_reader_add

Spec: §8.4.7.4, S. 83–84 — “ADD a_reader_proxy TO {this.matched_readers};”

Repo: crates/rtps/src/reliable_writer.rs (add_reader_proxy)

Tests: crates/rtps/src/reliable_writer.rs::tests::add_reader_proxy_is_idempotent_on_same_guid, crates/rtps/src/reliable_writer.rs::tests::heartbeat_after_add_reader_proxy_is_non_final

Status: done

§8.4.7.4 Table 8.60 StatefulWriter matched_reader_remove

Spec: §8.4.7.4, S. 84 — “REMOVE a_reader_proxy FROM {this.matched_readers}; delete proxy;”

Repo: crates/rtps/src/reliable_writer.rs (remove_reader_proxy)

Tests: crates/rtps/src/reliable_writer.rs::tests::remove_reader_proxy_by_guid

Status: done

§8.4.7.4 Table 8.60 StatefulWriter matched_reader_lookup

Spec: §8.4.7.4, S. 84 — “FIND proxy IN this.matched_readers SUCH-THAT (proxy.remoteReaderGuid == a_reader_guid); return proxy;”

Repo: crates/rtps/src/reliable_writer.rs (handle_acknack_window, handle_nackfrag: Suche nach remote_reader_guid)

Tests: crates/rtps/src/reliable_writer.rs::tests::acknack_dispatches_to_matching_proxy_only

Status: done

§8.4.7.5 Table 8.61 ReaderProxy remoteReaderGuid

Spec: §8.4.7.5, S. 84, Table 8.61 — “remoteReaderGuid: GUID_t — Identifies the remote matched RTPS Reader that is represented by the ReaderProxy.”

Repo: crates/rtps/src/reader_proxy.rs (ReaderProxy::remote_reader_guid)

Tests: crates/rtps/src/reliable_writer.rs::tests::add_reader_proxy_is_idempotent_on_same_guid

Status: done

§8.4.7.5 Table 8.61 ReaderProxy remoteGroupEntityId

Spec: §8.4.7.5, S. 84, Table 8.61 — “remoteGroupEntityId: EntityId_t — Identifies the group to which the matched Reader belongs”.

Repo: crates/rtps/src/reader_proxy.rs (ReaderProxy::remote_group_entity_id, with_remote_group_entity_id); crates/dcps/src/runtime.rs (Match-Pfad, PID_GROUP_GUID der Subscription)

Tests: crates/rtps/src/reader_proxy.rs::tests::the_remote_group_entity_id_is_kept, crates/dcps/src/runtime.rs::tests::the_proxies_of_a_match_carry_the_remote_group_entity_id

Status: done — der Proxy führt remoteGroupEntityId; der Match-Pfad füllt ihn aus PID_GROUP_GUID der SEDP-Ankündigung des Readers, ENTITYID_UNKNOWN ohne Gruppe.

§8.4.7.5 Table 8.61 ReaderProxy unicastLocatorList

Spec: §8.4.7.5, S. 84, Table 8.61 — “List of unicast locators … that can be used to send messages to the matched RTPS Reader. The list may be empty.”

Repo: crates/rtps/src/reader_proxy.rs (ReaderProxy::unicast_locators)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_fans_out_to_every_unicast_locator_of_a_proxy

Status: done

§8.4.7.5 Table 8.61 ReaderProxy multicastLocatorList

Spec: §8.4.7.5, S. 84, Table 8.61 — “List of multicast locators … that can be used to send messages to the matched RTPS Reader. The list may be empty.”

Repo: crates/rtps/src/reader_proxy.rs (ReaderProxy::multicast_locators); crates/rtps/src/reliable_writer.rs (proxy_targets_of)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_reader_proxy_with_multicast_locators_is_sent_to_at_the_multicast_locator

Status: done — ein Proxy mit Multicast-Locatoren wird dort angesprochen (DATA und HEARTBEAT, ein Datagramm für die Gruppe), einer ohne an seinen Unicast-Locatoren. Der SEDP-Match-Pfad übergibt eine leere Liste („The list may be empty“); die Unicast-Locatoren des Readers gelten dann.

§8.4.7.5 Table 8.61 ReaderProxy highestSentChangeSN

Spec: §8.4.7.5, S. 84, Table 8.61 — “The highest sequence number of the changes that have been sent to the matched RTPS Reader.”

Repo: crates/rtps/src/reader_proxy.rs (highest_sent_sn)

Tests: crates/rtps/src/reader_proxy.rs::tests::next_unsent_change_walks_sequentially

Status: done

§8.4.7.5 Table 8.61 ReaderProxy requestedChanges

Spec: §8.4.7.5, S. 84, Table 8.61 — “A list of sequence numbers representing changes that were requested by the matched RTPS Reader.”

Repo: crates/rtps/src/reader_proxy.rs (requested_changes)

Tests: crates/rtps/src/reader_proxy.rs::tests::a_request_for_an_acknowledged_change_is_kept

Status: done

§8.4.7.5 Table 8.61 ReaderProxy acknowledgedChanges

Spec: §8.4.7.5, S. 84–85, Table 8.61 — “A list of sequence numbers representing changes that have been acknowledged by the matched RTPS Reader.”

Repo: crates/rtps/src/reader_proxy.rs (highest_acked_sn)

Tests: crates/rtps/src/reader_proxy.rs::tests::acked_changes_set_monotonic

Status: done — als höchste bestätigte Nummer geführt.

§8.4.7.5 Table 8.61 ReaderProxy expectsInlineQos

Spec: §8.4.7.5, S. 85, Table 8.61 — “Specifies whether the remote matched RTPS Reader expects in-line QoS to be sent along with any data.”

Repo: crates/rtps/src/reader_proxy.rs (expects_inline_qos, set_expects_inline_qos)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_reader_that_expects_inline_qos_gets_the_writers_qos_with_each_data

Status: done

§8.4.7.5 Table 8.61 ReaderProxy isActive

Spec: §8.4.7.5, S. 85, Table 8.61 — “isActive: bool — Specifies whether the remote Reader is responsive to the Writer.”

Repo: crates/rtps/src/reader_proxy.rs (note_activity, is_inactive)

Tests: crates/rtps/src/reader_proxy.rs::tests::proxy_becomes_inactive_after_threshold_elapses, crates/rtps/src/reader_proxy.rs::tests::proxy_is_active_after_note_activity

Status: done

§8.4.7.5 Matching folgt dem DDS-Match

Spec: §8.4.7.5, S. 85 — “The matching is a consequence of the match of the corresponding DDS entities. That is, the DDS DataWriter matches a DDS DataReader by Topic, has compatible QoS, and is not being explicitly ignored by the application that uses DDS.”

Repo: crates/dcps/src/runtime.rs (SEDP-Match, add_reader_proxy); crates/dcps/src/participant.rs (ignore_subscription)

Tests: crates/discovery/src/sedp/stack.rs::tests::end_to_end_discovery_between_two_stacks, crates/dcps/tests/xtypes_aware_match.rs::final_vs_appendable_mismatch_rejected_at_match_time

Status: done

§8.4.7.5 Table 8.62 ReaderProxy new

Spec: §8.4.7.5, S. 85 — “this.requested_changes := ; this.acknowledged_changes := ; this.highest_sent_seq_num := 0;”

Repo: crates/rtps/src/reader_proxy.rs (ReaderProxy::new)

Tests: crates/rtps/src/reader_proxy.rs::tests::fresh_proxy_has_zero_state

Status: done

§8.4.7.5 Table 8.62 ReaderProxy acked_changes_set

Spec: §8.4.7.5, S. 86 — “FOR_EACH seq_num <= committed_seq_num DO ADD seq_num TO this.acknowledged_changes”.

Repo: crates/rtps/src/reader_proxy.rs (acked_changes_set)

Tests: crates/rtps/src/reader_proxy.rs::tests::acked_changes_set_monotonic, crates/rtps/src/reader_proxy.rs::tests::acking_also_prunes_requested_changes

Status: done — der Parameter ist readerSNState.base, die bestätigte Obergrenze base − 1.

§8.4.7.5 Table 8.62 ReaderProxy next_requested_change

Spec: §8.4.7.5, S. 86 — “return MIN( this.requested_changes() );”

Repo: crates/rtps/src/reader_proxy.rs (next_requested_change)

Tests: crates/rtps/src/reader_proxy.rs::tests::next_requested_change_pulls_smallest_first

Status: done

§8.4.7.5 Table 8.62 ReaderProxy next_unsent_change

Spec: §8.4.7.5, S. 86 — “unsent_changes := { changes SUCH-THAT change.sequenceNumber > this.higuest_sent_seq_num } … ELSE return MIN { unsent_changes.sequenceNumber }”.

Repo: crates/rtps/src/reader_proxy.rs (next_unsent_change)

Tests: crates/rtps/src/reader_proxy.rs::tests::next_unsent_change_walks_sequentially, crates/rtps/src/reader_proxy.rs::tests::next_unsent_change_picks_up_after_cache_grows

Status: done — liefert highest_sent + 1 bis zum Cache-Maximum; nicht mehr vorhandene Nummern beantwortet tick mit GAP.

§8.4.7.5 Table 8.62 ReaderProxy requested_changes

Spec: §8.4.7.5, S. 86 — “return this.requested_changes”.

Repo: crates/rtps/src/reader_proxy.rs (pending_requested_count, next_requested_change)

Tests: crates/rtps/src/reader_proxy.rs::tests::a_request_for_an_acknowledged_change_is_kept

Status: done

§8.4.7.5 Table 8.62 ReaderProxy requested_changes_set

Spec: §8.4.7.5, S. 86 — “FOR_EACH seq_num IN req_seq_num_set DO ADD seq_num TO this.requested_changes;”

Repo: crates/rtps/src/reader_proxy.rs (requested_changes_set)

Tests: crates/rtps/src/reader_proxy.rs::tests::a_request_for_an_acknowledged_change_is_kept

Status: done — übernimmt jede angeforderte Nummer ab der Basis des ACKNACK, auch eine schon bestätigte (§8.4.2.3).

§8.4.7.5 Table 8.62 ReaderProxy unsent_changes

Spec: §8.4.7.5, S. 86 — “return ( this.next_unsent_change() != SEQUENCE_NUMBER_INVALID )”.

Repo: crates/rtps/src/reader_proxy.rs (highest_sent_sn gegen Cache-Maximum)

Tests: crates/rtps/src/reader_proxy.rs::tests::next_unsent_change_picks_up_after_cache_grows

Status: done

§8.4.7.5 Table 8.62 ReaderProxy unacked_changes

Spec: §8.4.7.5, S. 86 — “return ( highest_available_seq_num > highest_acked_seq_num )”.

Repo: crates/rtps/src/reader_proxy.rs (unacked_changes)

Tests: crates/rtps/src/reader_proxy.rs::tests::unacked_changes_detects_gap

Status: done

§8.4.8.1 Table 8.63 Best-Effort-StatelessWriter T1

Spec: §8.4.8.1, S. 87–88, Table 8.63 T1 — “a_locator := new ReaderLocator( locator, expectsInlineQos ); the_rtps_writer.reader_locator_add( a_locator );”

Repo: crates/discovery/src/spdp.rs (SpdpBeacon); crates/dcps/src/runtime.rs (RuntimeConfig::initial_peers, SPDP-Multicast-Locator)

Tests: crates/dcps/src/runtime.rs::tests::initial_peer_specs_expand_per_the_configured_participant_limit, crates/discovery/src/spdp.rs::tests::beacon_serializes_to_decodable_datagram

Status: done — der SPDP-Beacon ist ZeroDDS’ Best-Effort-StatelessWriter; seine Ziel-Locatoren stammen aus der Konfiguration (§8.5.3.1).

§8.4.8.1 Table 8.63 Best-Effort-StatelessWriter T2

Spec: §8.4.8.1, S. 88 — “triggered by the guard condition [RL::unsent_changes() == true] … The transition performs no logical actions”.

Repo: —

Tests: —

Status: n/a (informative) — Übergang ohne logische Aktion; beobachtbar ist T4.

§8.4.8.1 Table 8.63 Best-Effort-StatelessWriter T3

Spec: §8.4.8.1, S. 88 — “[RL::unsent_changes() == false] … The transition performs no logical actions”.

Repo: —

Tests: —

Status: n/a (informative) — Übergang ohne logische Aktion.

§8.4.8.1 Table 8.63 Best-Effort-StatelessWriter T4

Spec: §8.4.8.1, S. 88 — nächster ungesendeter Change; GAP für übersprungene Nummern; “DATA = new DATA(a_change); IF (the_reader_locator.expectsInlineQos) { DATA.inlineQos := … } DATA.readerId := ENTITYID_UNKNOWN; sendto the_reader_locator.locator, DATA;”

Repo: crates/discovery/src/spdp.rs (SpdpBeacon::serialize: je Ankündigung eine DATA mit fortlaufender Nummer)

Tests: crates/discovery/src/spdp.rs::tests::beacon_serializes_to_decodable_datagram

Status: done — die DATA trägt readerId = ENTITYID_SPDP_BUILTIN_PARTICIPANT_DETECTOR statt UNKNOWN (§8.3.8.2 lässt beides zu); da jede Nummer gesendet wird, entsteht kein GAP.

§8.4.8.1 Table 8.63 Best-Effort-StatelessWriter T5

Spec: §8.4.8.1, S. 88–89 — “the_rtps_writer.reader_locator_remove( the_reader_locator); delete the_reader_locator;”

Repo: —

Tests: —

Status: n/a (informative) — für SPDP sind die Locatoren fest konfiguriert (§8.5.3.1); ein Entfernen durch die Discovery tritt nicht auf.

§8.4.8.2 Table 8.64 Reliable-StatelessWriter T1

Spec: §8.4.8.2, S. 90, Table 8.64 T1 — “a_locator := new ReaderLocator( locator, expectsInlineQos ); the_rtps_writer.reader_locator_add( a_locator );”

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::reader_locators_are_added_looked_up_and_removed

Status: done — reader_locator_add(locator, expects_inline_qos). ReliableStatelessWriter wird von keinem Produktionspfad verwendet; kein Hersteller ist gemessen.

§8.4.8.2 Table 8.64 Reliable-StatelessWriter T2

Spec: §8.4.8.2, S. 90 — “[RL::unsent_changes() == true] … The transition performs no logical actions”.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::unsent_changes_are_pushed_in_order_then_announced

Status: done — ungesendete Changes setzen den Push-Zustand Pushing. ReliableStatelessWriter wird von keinem Produktionspfad verwendet; kein Hersteller ist gemessen.

§8.4.8.2 Table 8.64 Reliable-StatelessWriter T3

Spec: §8.4.8.2, S. 90 — “[RL::unsent_changes == false] … The transition performs no logical actions”.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::unsent_changes_are_pushed_in_order_then_announced

Status: done — ohne ungesendete Changes geht die Push-Maschine nach Announcing. ReliableStatelessWriter wird von keinem Produktionspfad verwendet; kein Hersteller ist gemessen.

§8.4.8.2 Table 8.64 Reliable-StatelessWriter T4

Spec: §8.4.8.2, S. 91 — nächsten ungesendeten Change als DATA mit readerId := ENTITYID_UNKNOWN senden, GAP für übersprungene Nummern; Nachbedingung higuest_sent_seq_num == a_change_seq_num.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::unsent_changes_are_pushed_in_order_then_announced, crates/rtps/src/reliable_stateless_writer.rs::tests::a_gap_precedes_the_data_after_a_hole_in_the_cache, crates/rtps/src/reliable_stateless_writer.rs::tests::the_related_qos_goes_out_with_the_data_only_where_it_is_expected, crates/rtps/src/reliable_stateless_writer.rs::tests::the_resend_per_tick_is_bounded

Status: done — der nächste ungesendete Change geht als DATA mit readerId = ENTITYID_UNKNOWN an den Locator, davor ein GAP mit filteredCount = 0 über die fehlenden Nummern; Inline-QoS des zugehörigen DDS-Writers nur bei expectsInlineQos; RL::can_send() ist die Grenze max_per_tick. ReliableStatelessWriter wird von keinem Produktionspfad verwendet; kein Hersteller ist gemessen.

§8.4.8.2 Table 8.64 Reliable-StatelessWriter T5

Spec: §8.4.8.2, S. 91 — periodisch “HEARTBEAT := new HEARTBEAT(the_rtps_writer.writerGuid, seq_num_min, seq_num_max); HEARTBEAT.FinalFlag := SET; HEARTBEAT.readerId := ENTITYID_UNKNOWN;”

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::an_announcing_locator_gets_a_final_heartbeat_each_period, crates/rtps/src/reliable_stateless_writer.rs::tests::a_heartbeat_of_an_empty_cache_has_first_after_last, crates/rtps/src/reliable_stateless_writer.rs::tests::the_heartbeat_count_wraps_at_u32_max

Status: done — HEARTBEAT mit FinalFlag gesetzt und readerId = ENTITYID_UNKNOWN je heartbeatPeriod an einen ankündigenden Locator; ein leerer Cache meldet firstSN = lastSN + 1. ReliableStatelessWriter wird von keinem Produktionspfad verwendet; kein Hersteller ist gemessen.

§8.4.8.2 Table 8.64 Reliable-StatelessWriter T6

Spec: §8.4.8.2, S. 91–92 — “FOREACH reply_locator_t IN { Receiver.unicastReplyLocatorList, Receiver.multicastReplyLocatorList } reader_locator := the_rtps_writer.reader_locator_lookup(reply_locator_t); reader_locator.requested_changes_set(ACKNACK.readerSNState.set);”

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::an_acknack_is_answered_at_its_reply_locator_after_the_delay, crates/rtps/src/reliable_stateless_writer.rs::tests::an_acknack_without_a_usable_reply_locator_is_counted

Status: done — ein ACKNACK setzt für jeden Reply-Locator des Receiver-Zustands, der einen Port nennt und ReaderLocator ist, requested_changes_set(readerSNState); ein ACKNACK ohne brauchbaren Reply-Locator (kein InfoReply) wird gezählt (unmatched_acknacks). ReliableStatelessWriter wird von keinem Produktionspfad verwendet; kein Hersteller ist gemessen.

§8.4.8.2 Table 8.64 Reliable-StatelessWriter T7

Spec: §8.4.8.2, S. 92 — “[RL::requested_changes() != ] … The transition performs no logical actions”.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::an_acknack_is_answered_at_its_reply_locator_after_the_delay

Status: done — angeforderte Changes setzen den Repair-Zustand MustRepair. ReliableStatelessWriter wird von keinem Produktionspfad verwendet; kein Hersteller ist gemessen.

§8.4.8.2 Table 8.64 Reliable-StatelessWriter T8

Spec: §8.4.8.2, S. 92 — “The transition performs the same logical actions performed by Transition T6”.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::an_acknack_is_answered_at_its_reply_locator_after_the_delay

Status: done — ein weiterer ACKNACK in MustRepair verfährt wie T6. ReliableStatelessWriter wird von keinem Produktionspfad verwendet; kein Hersteller ist gemessen.

§8.4.8.2 Table 8.64 Reliable-StatelessWriter T9

Spec: §8.4.8.2, S. 92 — “triggered by the firing of a timer indicating that the duration of W::nackResponseDelay has elapsed since the state must_repair was entered.”

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::an_acknack_is_answered_at_its_reply_locator_after_the_delay

Status: done — nach nackResponseDelay (set_nack_response_delay) geht die Maschine nach Repairing. ReliableStatelessWriter wird von keinem Produktionspfad verwendet; kein Hersteller ist gemessen.

§8.4.8.2 Table 8.64 Reliable-StatelessWriter T10 (DATA)

Spec: §8.4.8.2, S. 92 — “a_change_seq_num := the_reader_locator.next_requested_change(); … IF ( a_change != ) { DATA = new DATA(a_change); … DATA.readerId := ENTITYID_UNKNOWN; sendto the_reader_locator.locator, DATA; }”.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::an_acknack_is_answered_at_its_reply_locator_after_the_delay, crates/rtps/src/reliable_stateless_writer.rs::tests::the_related_qos_goes_out_with_the_data_only_where_it_is_expected

Status: done — next_requested_change geht als DATA mit readerId = ENTITYID_UNKNOWN an den Locator; Inline-QoS des DDS-Writers und des Changes bei expectsInlineQos. ReliableStatelessWriter wird von keinem Produktionspfad verwendet; kein Hersteller ist gemessen.

§8.4.8.2 Table 8.64 Reliable-StatelessWriter T10 (GAP)

Spec: §8.4.8.2, S. 92 — “ELSE { GAP = new GAP(a_change.sequenceNumber); GAP.readerId := ENTITYID_UNKNOWN; GAP.filteredCount := 0; sendto the_reader_locator.locator, GAP; }”.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::a_requested_change_that_left_the_cache_is_answered_by_a_gap

Status: done — ein angeforderter Change, der nicht mehr im Cache ist, wird mit einem GAP (filteredCount = 0) beantwortet. ReliableStatelessWriter wird von keinem Produktionspfad verwendet; kein Hersteller ist gemessen.

§8.4.8.2 Table 8.64 Reliable-StatelessWriter T11

Spec: §8.4.8.2, S. 93 — “[RL::requested_changes() == ] … The transition performs no logical actions”.

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::an_acknack_is_answered_at_its_reply_locator_after_the_delay

Status: done — ohne angeforderte Changes geht die Maschine nach Waiting. ReliableStatelessWriter wird von keinem Produktionspfad verwendet; kein Hersteller ist gemessen.

§8.4.8.2 Table 8.64 Reliable-StatelessWriter T12

Spec: §8.4.8.2, S. 93 — “the_rtps_writer.reader_locator_remove( the_reader_locator); delete the_reader_locator;”

Repo: crates/rtps/src/reliable_stateless_writer.rs (ReliableStatelessWriter, ReaderLocator)

Tests: crates/rtps/src/reliable_stateless_writer.rs::tests::reader_locators_are_added_looked_up_and_removed

Status: done — reader_locator_remove löscht den ReaderLocator. ReliableStatelessWriter wird von keinem Produktionspfad verwendet; kein Hersteller ist gemessen.

§8.4.9.1 Table 8.65 Best-Effort-StatefulWriter T1

Spec: §8.4.9.1, S. 94, Table 8.65 T1 — “a_reader_proxy := new ReaderProxy( remoteReaderGuid, remoteGroupEntityId, expectsInlineQos, unicastLocatorList, multicastLocatorList); the_rtps_writer.matched_reader_add(a_reader_proxy);”

Repo: crates/rtps/src/reliable_writer.rs (add_reader_proxy mit ReaderProxy::new(.., is_reliable: false)); crates/rtps/src/reader_proxy.rs (remote_group_entity_id); crates/dcps/src/runtime.rs (Match-Pfad)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_best_effort_reader_matched_late_gets_the_next_write, crates/rtps/src/reader_proxy.rs::tests::the_remote_group_entity_id_is_kept, crates/dcps/src/runtime.rs::tests::the_proxies_of_a_match_carry_the_remote_group_entity_id

Status: done — matched_reader_add nimmt remoteGroupEntityId, expectsInlineQos und beide Locator-Listen.

§8.4.9.1 Table 8.65 Best-Effort-StatefulWriter T2

Spec: §8.4.9.1, S. 94 — “[RP::unsent_changes() == true] … Note that for a Best-Effort Writer, W::pushMode == true … The transition performs no logical actions”.

Repo: —

Tests: —

Status: n/a (informative) — Übergang ohne logische Aktion.

§8.4.9.1 Table 8.65 Best-Effort-StatefulWriter T3

Spec: §8.4.9.1, S. 94 — “[RP::unsent_changes() == false] … The transition performs no logical actions”.

Repo: —

Tests: —

Status: n/a (informative) — Übergang ohne logische Aktion.

§8.4.9.1 Table 8.65 Best-Effort-StatefulWriter T4

Spec: §8.4.9.1, S. 94–95 — nächster ungesendeter Change; GAP für übersprungene Nummern mit filteredCount 0; DATA bei bestandenem DDS_FILTER, sonst GAP mit filteredCount 1; Inline-QoS bei expectsInlineQos; Nachbedingung higuest_sent_seq_num == a_change_seq_num.

Repo: crates/rtps/src/reliable_writer.rs (write_sample_with_inline_qos, tick, append_change, is_relevant, passes_dds_filter, gap_filtered_count); crates/rtps/src/reader_proxy.rs (ChangeFilter, with_filter)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_best_effort_reader_matched_late_gets_the_next_write, crates/rtps/src/reliable_writer.rs::tests::a_best_effort_reader_matched_late_is_pushed_what_the_cache_holds, crates/rtps/src/reliable_writer.rs::tests::a_best_effort_reader_behind_is_pushed_gaps_with_the_filtered_count, crates/rtps/src/reliable_writer.rs::tests::a_change_that_fails_the_readers_filter_is_a_gap_with_filtered_count_one, crates/rtps/src/reliable_writer.rs::tests::a_gap_for_a_number_the_cache_no_longer_holds_has_filtered_count_zero, crates/rtps/src/reliable_writer.rs::tests::write_fans_out_to_all_reader_proxies

Status: done — ein Proxy im Schritt erhält jeden neuen Change als DATA; ein zurückliegender erhält in tick jeden noch nicht gesendeten Change als DATA, eine Nummer, die der Cache nicht mehr hat, als GAP mit filteredCount 0. Besteht ein Change DDS_FILTER(the_reader_proxy, a_change) nicht (ReaderProxy::with_filter), geht ein GAP mit filteredCount 1 statt des DATA. Die Laufzeit setzt keinen Filter (DDS_FILTER darf eine leere Operation sein, §8.2.10.1); das Verhalten gegenüber Cyclone DDS, Fast DDS und OpenDDS ist nicht gemessen.

§8.4.9.1 Best-Effort-StatefulWriter: zurückliegender Proxy

Spec: §8.4.9.1, S. 95 — T4 sendet next_unsent_change() an jeden Proxy, “if ( a_change_seq_num > the_reader_proxy.higuest_sent_seq_num +1 ) { GAP = … }”.

Repo: crates/rtps/src/reliable_writer.rs (tick: next_unsent_change je Best-Effort-Proxy, append_change)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_best_effort_reader_matched_late_is_pushed_what_the_cache_holds

Status: done — ein zurückliegender Best-Effort-Proxy erhält die noch nicht gesendeten Changes der Reihe nach, ohne Anforderung; eine Nummer, die der Cache nicht mehr hat, als GAP.

§8.4.9.1 Table 8.65 Best-Effort-StatefulWriter T5

Spec: §8.4.9.1, S. 95–96 — “ADD a_change TO the_rtps_writer.writer_cache;” Nachbedingung “FOREACH proxy IN the_rtps_writer.matched_readers proxy.unsent_changes() == true”.

Repo: crates/rtps/src/reliable_writer.rs (stage_sample)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_fans_out_to_all_reader_proxies

Status: done

§8.4.9.1 Table 8.65 Best-Effort-StatefulWriter T6

Spec: §8.4.9.1, S. 96 — “the_rtps_writer.matched_reader_remove( the_reader_proxy); delete the_reader_proxy;”

Repo: crates/rtps/src/reliable_writer.rs (remove_reader_proxy)

Tests: crates/rtps/src/reliable_writer.rs::tests::remove_reader_proxy_by_guid

Status: done

§8.4.9.2 Table 8.66 Reliable-StatefulWriter T1

Spec: §8.4.9.2, S. 98, Table 8.66 T1 — “a_reader_proxy := new ReaderProxy( remoteReaderGuid, remoteGroupEntityId, expectsInlineQos, unicastLocatorList, multicastLocatorList); the_rtps_writer.matched_reader_add(a_reader_proxy);”

Repo: crates/rtps/src/reliable_writer.rs (add_reader_proxy); crates/rtps/src/reader_proxy.rs (remote_group_entity_id); crates/dcps/src/runtime.rs (Match-Pfad, skip_samples_up_to für VOLATILE)

Tests: crates/rtps/src/reliable_writer.rs::tests::heartbeat_after_add_reader_proxy_is_non_final, crates/rtps/src/reliable_writer.rs::tests::a_reader_matched_inside_an_open_coherent_set_gets_the_whole_set, crates/rtps/src/reader_proxy.rs::tests::the_remote_group_entity_id_is_kept, crates/dcps/src/runtime.rs::tests::the_proxies_of_a_match_carry_the_remote_group_entity_id

Status: done — matched_reader_add nimmt remoteGroupEntityId, expectsInlineQos und beide Locator-Listen.

§8.4.9.2 Table 8.66 Reliable-StatefulWriter T2

Spec: §8.4.9.2, S. 98–99 — “[RP::unsent_changes() != ] … The transition performs no logical actions”.

Repo: —

Tests: —

Status: n/a (informative) — Übergang ohne logische Aktion.

§8.4.9.2 Table 8.66 Reliable-StatefulWriter T3

Spec: §8.4.9.2, S. 99 — “[RP::unsent_changes() == false] … The transition performs no logical actions”.

Repo: —

Tests: —

Status: n/a (informative) — Übergang ohne logische Aktion.

§8.4.9.2 Table 8.66 Reliable-StatefulWriter T4

Spec: §8.4.9.2, S. 99–100 — nächster ungesendeter Change als DATA (oder GAP bei DDS_FILTER = false, filteredCount 1), GAP für aus dem Cache entfernte Nummern (filteredCount 0); “DATA.readerId := ENTITYID_UNKNOWN; // or ReaderProxy.entityId”.

Repo: crates/rtps/src/reliable_writer.rs (write_sample_with_inline_qos, write_with_heartbeat_stamped; tick für zurückliegende Proxies)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_increments_sn_and_returns_data_datagram, crates/rtps/src/reliable_writer.rs::tests::repairs_in_order_bring_a_lagging_proxy_into_step, crates/rtps/src/reliable_writer.rs::tests::a_reliable_proxy_behind_the_cache_is_pushed_into_step, crates/rtps/src/reliable_writer.rs::tests::a_repair_out_of_order_is_followed_by_the_changes_before_it, crates/rtps/src/reliable_writer.rs::tests::a_reader_asking_for_a_replaced_change_gets_the_current_one

Status: done — write sendet einen Change sofort an Proxies, die im Schritt sind; einem zurückliegenden Proxy (Late Joiner, oder einer, dessen Anfrage ein GAP beantwortet hat) schickt tick unter pushMode die ungesendeten Changes der Reihe nach, DATA für die im Cache, GAP für die entfernten. Ein in derselben Runde außer der Reihe reparierter Change geht nicht zweimal hinaus.

§8.4.9.2 Table 8.66 Reliable-StatefulWriter T5

Spec: §8.4.9.2, S. 100 — “[RP::unacked_changes() == false] … The transition performs no logical actions”.

Repo: crates/rtps/src/reliable_writer.rs (tick: kein periodischer HEARTBEAT ohne unbestätigte Changes)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_reader_that_acknowledged_the_cache_gets_no_periodic_heartbeat

Status: done

§8.4.9.2 Table 8.66 Reliable-StatefulWriter T6

Spec: §8.4.9.2, S. 100 — “[RP::unacked_changes() == true] … The transition performs no logical actions”.

Repo: crates/rtps/src/reliable_writer.rs (tick: announcing)

Tests: crates/rtps/src/reliable_writer.rs::tests::the_heartbeat_sent_with_a_change_is_answered_by_the_next_acknack

Status: done

§8.4.9.2 Table 8.66 Reliable-StatefulWriter T7

Spec: §8.4.9.2, S. 100 — “HEARTBEAT := new HEARTBEAT(the_rtps_writer.writerGuid, seq_num_min, seq_num_max); HEARTBEAT.FinalFlag := NOT_SET; HEARTBEAT.readerId := ENTITYID_UNKNOWN; send HEARTBEAT;”

Repo: crates/rtps/src/reliable_writer.rs (tick, append_heartbeat)

Tests: crates/rtps/src/reliable_writer.rs::tests::periodic_heartbeat_has_final_flag_unset, crates/rtps/src/reliable_writer.rs::tests::heartbeat_carries_cache_range

Status: done — der HEARTBEAT geht je Proxy mit dessen readerId; firstSN ist max(seq_num_min, highest_acked + 1) des Proxys.

§8.4.9.2 Table 8.66 Reliable-StatefulWriter T8

Spec: §8.4.9.2, S. 100 — “the_rtps_writer.acked_changes_set( ACKNACK.readerSNState.base - 1); the_reader_proxy.requested_changes_set( ACKNACK.readerSNState.set);”

Repo: crates/rtps/src/reliable_writer.rs (handle_acknack_window)

Tests: crates/rtps/src/reliable_writer.rs::tests::handle_acknack_updates_proxy_state, crates/rtps/src/reliable_writer.rs::tests::handle_acknack_with_lower_base_leaves_requested

Status: done

§8.4.9.2 Table 8.66 Reliable-StatefulWriter T9

Spec: §8.4.9.2, S. 100 — “[RP::requested_changes() != ] … The transition performs no logical actions”.

Repo: —

Tests: —

Status: n/a (informative) — Übergang ohne logische Aktion.

§8.4.9.2 Table 8.66 Reliable-StatefulWriter T10

Spec: §8.4.9.2, S. 101 — “The transition performs the same logical actions as Transition T8”.

Repo: crates/rtps/src/reliable_writer.rs (handle_acknack_window)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_full_nack_window_gets_a_heartbeat_with_its_repair

Status: done

§8.4.9.2 Table 8.66 Reliable-StatefulWriter T11

Spec: §8.4.9.2, S. 101 — “triggered by the firing of a timer indicating that the duration of W::nackResponseDelay has elapsed since the state must_repair was entered.”

Repo: crates/rtps/src/reader_proxy.rs (repair_due, note_nack)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_repair_waits_for_the_nack_response_delay

Status: done

§8.4.9.2 Table 8.66 Reliable-StatefulWriter T12

Spec: §8.4.9.2, S. 101–102 — angeforderten Change aus dem Cache als DATA (oder GAP mit filteredCount 1 bei DDS_FILTER = false), sonst “GAP = new GAP(a_change.sequenceNumber, the_reader_proxy.remoteReaderGuid); GAP.filteredCount := 0;”; Nachbedingung: der Change ist nicht mehr angefordert.

Repo: crates/rtps/src/reliable_writer.rs (tick: append_data, append_lifecycle, append_gap)

Tests: crates/rtps/src/reliable_writer.rs::tests::tick_resends_requested_as_data_aggregated_with_hb, crates/rtps/src/reliable_writer.rs::tests::tick_resends_evicted_request_as_gap, crates/rtps/src/reliable_writer.rs::tests::lifecycle_repair_reproduces_the_key

Status: done — der GAP enthält kein filteredCount-Feld; das entspricht einem nicht gezählten Change.

§8.4.9.2 Table 8.66 Reliable-StatefulWriter T13

Spec: §8.4.9.2, S. 102 — “[RP::requested_changes() == ] … The transition performs no logical actions”.

Repo: —

Tests: —

Status: n/a (informative) — Übergang ohne logische Aktion.

§8.4.9.2 Table 8.66 Reliable-StatefulWriter T14

Spec: §8.4.9.2, S. 102 — “ADD a_change TO the_rtps_writer.writer_cache;” Nachbedingung: jeder Proxy hat ungesendete Changes.

Repo: crates/rtps/src/reliable_writer.rs (stage_sample)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_fans_out_to_all_reader_proxies

Status: done

§8.4.9.2 Table 8.66 Reliable-StatefulWriter T15

Spec: §8.4.9.2, S. 102 — “triggered by the removal of a CacheChange ‘a_change’ from the HistoryCache of the RTPS Writer”.

Repo: crates/rtps/src/reliable_writer.rs (KEEP_LAST-Verdrängung in stage_sample, remove_acknowledged, remove_samples_up_to)

Tests: crates/rtps/src/reliable_writer.rs::tests::keep_last_stalled_reader_does_not_block_fresh_writes, crates/rtps/src/reliable_writer.rs::tests::tick_resends_evicted_request_as_gap

Status: done

§8.4.9.2 Table 8.66 Reliable-StatefulWriter T16

Spec: §8.4.9.2, S. 102 — “the_rtps_writer.matched_reader_remove( the_reader_proxy); delete the_reader_proxy;”

Repo: crates/rtps/src/reliable_writer.rs (remove_reader_proxy)

Tests: crates/rtps/src/reliable_writer.rs::tests::remove_reader_proxy_by_guid, crates/rtps/src/reliable_writer.rs::tests::the_unacked_window_fills_and_acknowledgements_free_it

Status: done

§8.4.10.1 Table 8.67 Reader heartbeatResponseDelay

Spec: §8.4.10.1, S. 103, Table 8.67 — “heartbeatResponseDelay: Protocol tuning parameter that allows the RTPS Reader to delay the sending of a positive or negative acknowledgment”.

Repo: crates/rtps/src/reliable_reader.rs (ReliableReaderConfig::heartbeat_response_delay, tick_outbound)

Tests: crates/rtps/src/reliable_reader.rs::tests::heartbeat_with_missing_triggers_acknack_after_delay

Status: done — die Einstellbarkeit für den Anwender ist unter §8.4.2.1 geführt.

§8.4.10.1 Table 8.67 Reader heartbeatSuppressionDuration

Spec: §8.4.10.1, S. 103, Table 8.67 — “heartbeatSuppressionDuration: Protocol tuning parameter that allows the RTPS Reader to ignore HEARTBEATs that arrive ‘too soon’ after a previous HEARTBEAT was received.”

Repo: crates/rtps/src/reliable_reader.rs (set_heartbeat_suppression_duration, handle_heartbeat)

Tests: crates/rtps/src/reliable_reader.rs::tests::heartbeat_suppression_duration_ignores_a_heartbeat_that_arrives_too_soon

Status: done

§8.4.10.1 Table 8.67 Reader reader_cache

Spec: §8.4.10.1, S. 103, Table 8.67 — “reader_cache: History Cache — Contains the history of CacheChange changes for this RTPS Reader.”

Repo: crates/rtps/src/reliable_reader.rs (WriterProxyState::received_cache); crates/dcps/src/subscriber.rs (Sample-Speicher des DataReader)

Tests: crates/rtps/src/reliable_reader.rs::tests::out_of_order_data_buffered_until_gap_filled, crates/rtps/src/reliable_reader.rs::tests::a_full_cache_takes_the_change_in_front_of_what_it_holds

Status: done

§8.4.10.1 Table 8.67 Reader expectsInlineQos

Spec: §8.4.10.1, S. 104, Table 8.67 — “expectsInlineQos: bool — Specifies whether the RTPS Reader expects in-line QoS to be sent along with any data.”

Repo: crates/rtps/src/subscription_data.rs (SubscriptionBuiltinTopicData::expects_inline_qos)

Tests: crates/rtps/src/subscription_data.rs::tests::expects_inline_qos_goes_out_when_set_and_reads_back

Status: done

§8.4.10.1 Default heartbeatResponseDelay = 500 ms

Spec: §8.4.10.1, S. 104 — “heartbeatResponseDelay.sec = 0; heartbeatResponseDelay.nanosec = 500 * 1000 * 1000; // 500 milliseconds”.

Repo: crates/rtps/src/reliable_reader.rs (DEFAULT_HEARTBEAT_RESPONSE_DELAY, SPEC_HEARTBEAT_RESPONSE_DELAY); crates/dcps/src/runtime.rs (RuntimeConfig::reader_heartbeat_response_delay)

Tests: crates/rtps/src/reliable_reader.rs::tests::default_heartbeat_suppression_duration_is_the_spec_zero, crates/dcps/tests/runtime_config_layering.rs::the_protocol_timing_parameters_are_settings

Status: done — DEFAULT_HEARTBEAT_RESPONSE_DELAY und RuntimeConfig::reader_heartbeat_response_delay sind 500 ms; reader.heartbeat_response_delay_ms: 0 antwortet im nächsten Tick.

§8.4.10.1 Default heartbeatResponseDelay

Spec: §8.4.10.1, S. 104 — “The following timing-related values are used as the defaults in order to facilitate ‘out-of-the-box’ interoperability between implementations.”

Repo: crates/rtps/src/reliable_reader.rs (DEFAULT_HEARTBEAT_RESPONSE_DELAY, DEFAULT_HEARTBEAT_SUPPRESSION_DURATION); crates/dcps/src/runtime.rs; crates/dcps/src/type_lookup_transport.rs; man/man5/zerodds.yaml.5; packaging/linux/configs/zerodds.yaml.example

Tests: crates/dcps/tests/runtime_config_layering.rs::the_protocol_timing_parameters_are_settings, crates/rtps/src/reliable_reader.rs::tests::default_heartbeat_suppression_duration_is_the_spec_zero

Status: done — die Werte der Spec sind die Vorgaben: heartbeatResponseDelay 500 ms, heartbeatSuppressionDuration 0 (Laufzeit, Man-Seite, Beispielkonfiguration). Die früheren 0 ms bleiben über reader.heartbeat_response_delay_ms erreichbar. §8.4.7.1 nennt keine heartbeatPeriod; sie bleibt 100 ms (writer.heartbeat_period_ms). Die eingebauten Reader von SEDP, Secure-Volatile und TypeLookup nutzen dieselbe Vorgabe.

§8.4.10.1 Default heartbeatSuppressionDuration = 0

Spec: §8.4.10.1, S. 104 — “heartbeatSuppressionDuration.sec = 0; heartbeatSuppressionDuration.nanosec = 0;”.

Repo: crates/rtps/src/reliable_reader.rs (DEFAULT_HEARTBEAT_SUPPRESSION_DURATION)

Tests: crates/rtps/src/reliable_reader.rs::tests::default_heartbeat_suppression_duration_is_the_spec_zero, crates/rtps/src/reliable_reader.rs::tests::heartbeat_storm_from_a_writer_that_never_fulfils_a_nack_cannot_arise, crates/discovery/src/sedp/reader.rs::tests::sedp_reader_does_not_storm_against_a_writer_that_never_delivers

Status: done — alle Reader laufen mit 0, auch die eingebauten von SEDP und VolatileSecure. Ein Writer, der dieselbe Spanne in kurzen Abständen neu ankündigt (HDDS 1.4.8: ein HEARTBEAT [1,1] etwa alle 1,5 ms), bekommt eine Antwort je heartbeatResponseDelay: die Verzögerung läuft ab dem ersten HEARTBEAT, der eine Antwort verlangt.

§8.4.10.1 Table 8.68 Reader new

Spec: §8.4.10.1, S. 104 — Übernahme von guid, Locator-Listen, reliabilityLevel, topicKind, expectsInlineQos, heartbeatResponseDelay; “this.reader_cache := new HistoryCache;”

Repo: crates/rtps/src/reliable_reader.rs (ReliableReader::new)

Tests: crates/rtps/src/reliable_reader.rs::tests::add_writer_proxy_increases_count

Status: done

§8.4.10.2 Table 8.69 StatelessReader new

Spec: §8.4.10.2, S. 104–105 — “The RTPS StatelessReader has no knowledge of the number of matched writers, nor does it maintain any state for each matched RTPS Writer.”

Repo: crates/rtps/src/reader.rs (BestEffortReader::new); crates/discovery/src/spdp.rs (SpdpReader::new)

Tests: crates/rtps/src/reader.rs::tests::reader_delivers_data_addressed_to_us, crates/discovery/src/spdp.rs::tests::reader_rejects_non_spdp_datagram

Status: done

§8.4.10.3 Table 8.70 StatefulReader matched_writers

Spec: §8.4.10.3, S. 105, Table 8.70 — “matched_writers: WriteProxy[*] — Used to maintain state on the remote Writers matched up with the Reader.”

Repo: crates/rtps/src/reliable_reader.rs (writer_proxies)

Tests: crates/rtps/src/reliable_reader.rs::tests::two_writers_with_overlapping_sn_spaces_both_delivered

Status: done

§8.4.10.3 Table 8.71 StatefulReader new

Spec: §8.4.10.3, S. 105–106 — “this.matched_writers := ;”

Repo: crates/rtps/src/reliable_reader.rs (ReliableReader::new)

Tests: crates/rtps/src/reliable_reader.rs::tests::no_pre_emptive_acknack_without_proxy

Status: done

§8.4.10.3 Table 8.71 StatefulReader matched_writer_add

Spec: §8.4.10.3, S. 106 — “ADD a_writer_proxy TO {this.matched_writers};”

Repo: crates/rtps/src/reliable_reader.rs (add_writer_proxy)

Tests: crates/rtps/src/reliable_reader.rs::tests::add_writer_proxy_increases_count, crates/rtps/src/reliable_reader.rs::tests::re_adding_known_writer_preserves_reliability_state

Status: done

§8.4.10.3 Table 8.71 StatefulReader matched_writer_remove

Spec: §8.4.10.3, S. 106 — “REMOVE a_writer_proxy FROM {this.matched_writers}; delete a_writer_proxy;”

Repo: crates/rtps/src/reliable_reader.rs (remove_writer_proxy, depart_writer_proxy)

Tests: crates/rtps/src/reliable_reader.rs::tests::remove_writer_proxy_drops_its_state, crates/rtps/src/reliable_reader.rs::tests::a_departed_writer_leaves_its_held_samples_with_the_reader

Status: done

§8.4.10.3 Table 8.71 StatefulReader matched_writer_lookup

Spec: §8.4.10.3, S. 106 — “FIND proxy IN this.matched_writers SUCH-THAT (proxy.remoteWriterGuid == a_writer_guid); return proxy;”

Repo: crates/rtps/src/reliable_reader.rs (proxy_index_by_writer)

Tests: crates/rtps/src/reliable_reader.rs::tests::same_entity_id_different_prefix_not_confused

Status: done

§8.4.10.4 WriterProxy folgt dem DDS-Match

Spec: §8.4.10.4, S. 106 — “The association is a consequence of the matching of the corresponding DDS Entities … the DDS DataReader matching a DDS DataWriter by Topic, having compatible QoS, belonging to a common partition, and not being explicitly ignored by the application that uses DDS.”

Repo: crates/dcps/src/runtime.rs (Match-Pfad, add_writer_proxy); crates/dcps/src/participant.rs (ignore_publication)

Tests: crates/dcps/src/runtime.rs::tests::partition_mismatch_blocks_match_without_any_incompatible_qos_event, crates/dcps/src/participant.rs::tests::ignore_publication_records_handle

Status: done

§8.4.10.4 Table 8.72 WriterProxy remoteWriterGuid

Spec: §8.4.10.4, S. 106, Table 8.72 — “remoteWriterGuid: GUID_t — Identifies the matched Writer.”

Repo: crates/rtps/src/writer_proxy.rs (WriterProxy::remote_writer_guid)

Tests: crates/rtps/src/reliable_reader.rs::tests::same_entity_id_different_prefix_not_confused

Status: done

§8.4.10.4 Table 8.72 WriterProxy unicastLocatorList

Spec: §8.4.10.4, S. 106, Table 8.72 — “List of unicast (address, port) combinations that can be used to send messages to the matched Writer or Writers. The list may be empty.”

Repo: crates/rtps/src/writer_proxy.rs (WriterProxy::unicast_locators); crates/rtps/src/reliable_reader.rs (tick_outbound: ACKNACK an diese Locatoren)

Tests: crates/rtps/src/reliable_reader.rs::tests::tick_emits_one_acknack_per_writer_with_missing

Status: done

§8.4.10.4 Table 8.72 WriterProxy multicastLocatorList

Spec: §8.4.10.4, S. 106, Table 8.72 — “List of multicast (address, port) combinations that can be used to send messages to the matched Writer or Writers. The list may be empty.”

Repo: crates/rtps/src/writer_proxy.rs (WriterProxy::multicast_locators, refresh_locators)

Tests: crates/rtps/src/reliable_reader.rs::tests::re_adding_known_writer_preserves_reliability_state

Status: done — die Liste wird geführt; ACKNACKs gehen an die Unicast-Locatoren.

§8.4.10.4 Table 8.72 WriterProxy dataMaxSizeSerialized

Spec: §8.4.10.4, S. 106, Table 8.72 — “Optional attribute that indicates the maximum size of any SerializedPayload that may be sent by the matched Writer.”

Repo: crates/rtps/src/reliable_reader.rs (set_writer_data_max_size, oversize_payload_count); crates/dcps/src/runtime.rs (Verdrahtung beim Anlegen des Writer-Proxys, reader.honor_data_max_size_serialized)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_payload_beyond_the_announced_maximum_is_refused_and_counted, crates/dcps/tests/runtime_config_layering.rs::the_data_max_size_setting_is_on_by_default_and_read_from_yaml

Status: done — der Reader übernimmt das Attribut aus der Ankündigung und weist ein SerializedPayload darüber ab (nach dem Öffnen eines geschützten Payloads; die Nummer gilt als nicht verfügbar, der Zähler oversize_payload_count steigt). Ein DATA_FRAG-Sample wird nach dem Zusammensetzen geprüft; AssemblerCaps begrenzt weiter die Größe zusammengesetzter Samples. Die benannte Einstellung reader.honor_data_max_size_serialized=false nimmt den Payload trotzdem an, für einen Writer, der seine eigene Ankündigung überschreitet (Fast DDS 3.6.1: 160 Oktette angekündigt, 100 036 gesendet).

§8.4.10.4 Table 8.72 WriterProxy changes_from_writer

Spec: §8.4.10.4, S. 106, Table 8.72 — “List of CacheChange changes received or expected from the matched RTPS Writer.”

Repo: crates/rtps/src/writer_proxy.rs (known_up_to, received, irrelevant, first_available_sn, last_available_sn)

Tests: crates/rtps/src/writer_proxy.rs::tests::the_known_run_answers_as_the_sets_of_every_sn_did

Status: done — als Zählerstände und Mengen abgebildet (§8.4.15.1).

§8.4.10.4 Table 8.72 WriterProxy remoteGroupEntityId

Spec: §8.4.10.4, S. 107, Table 8.72 — “remoteGroupEntityId: EntityId_t — Identifies the group to which the matched Reader belongs”.

Repo: crates/rtps/src/writer_proxy.rs (WriterProxy::remote_group_entity_id, with_remote_group_entity_id); crates/dcps/src/runtime.rs (Match-Pfad, PID_GROUP_GUID der Publication)

Tests: crates/rtps/src/writer_proxy.rs::tests::the_remote_group_entity_id_is_kept, crates/dcps/src/runtime.rs::tests::the_proxies_of_a_match_carry_the_remote_group_entity_id

Status: done — der Proxy führt remoteGroupEntityId; der Match-Pfad füllt ihn aus PID_GROUP_GUID der SEDP-Ankündigung des Writers, ENTITYID_UNKNOWN ohne Gruppe.

§8.4.10.4 Table 8.73 WriterProxy new

Spec: §8.4.10.4, S. 107 — “this.changes_from_writer := ; … initialized to UNKNOWN”.

Repo: crates/rtps/src/writer_proxy.rs (WriterProxy::new: first_available_sn = 1, last_available_sn = 0)

Tests: crates/rtps/src/writer_proxy.rs::tests::fresh_proxy_has_no_missing

Status: done

§8.4.10.4 Table 8.73 WriterProxy available_changes_max

Spec: §8.4.10.4, S. 108 — “seq_num := MAX { change.sequenceNumber SUCH-THAT ( change IN this.changes_from_writer AND ( change.status == RECEIVED OR change.status == NOT_AVAILABLE) ) }” unter der Bedingung, dass keine kleinere Nummer MISSING oder UNKNOWN ist.

Repo: crates/rtps/src/writer_proxy.rs (available_changes_max)

Tests: crates/rtps/src/writer_proxy.rs::tests::available_changes_max_stops_at_the_first_hole, crates/rtps/src/writer_proxy.rs::tests::available_changes_max_passes_over_an_irrelevant_change

Status: done

§8.4.10.4 Table 8.73 WriterProxy not_available_change_set

Spec: §8.4.10.4, S. 108 — “IF ( filteredCount == COUNT(this. a_seq_num_set) ) THEN change.status := NA_FILTERED; ELSE IF ( filteredCount == 0) change.status := NA_REMOVED; ELSE change.status := NA_UNSPECIFIED;”

Repo: crates/rtps/src/writer_proxy.rs (NotAvailableKind, WriterProxy::not_available_change_set, not_available_count, change_status); crates/rtps/src/reliable_reader.rs (handle_gap, not_available_count)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_gap_sorts_its_changes_by_the_filtered_count, crates/rtps/src/reliable_reader.rs::tests::the_reader_keeps_the_status_of_each_change, crates/rtps/src/writer_proxy.rs::tests::change_status_is_kept_per_change_with_the_sub_kind

Status: done — filteredCount gleich der Größe der Menge ergibt NA_FILTERED, 0 ergibt NA_REMOVED, dazwischen NA_UNSPECIFIED; der Status steht je Änderung. Ein GAP ohne FilteredCountFlag zählt als 0 (Annahme: das Feld fehlt bei Peers vor 2.5, deren GAP nur entfernte Änderungen meldet; nicht gegen einen Hersteller gemessen). Eine bereits bekannte Nummer wird nicht erneut gezählt oder umgesetzt.

§8.4.10.4 Table 8.73 WriterProxy lost_changes_update

Spec: §8.4.10.4, S. 108 — “FOREACH change IN this.changes_from_writer SUCH-THAT ( change.status == UNKNOWN OR change.status == MISSING AND seq_num < first_available_seq_num ) DO { change.status := NA_REMOVED; }”.

Repo: crates/rtps/src/writer_proxy.rs (lost_changes_update)

Tests: crates/rtps/src/writer_proxy.rs::tests::lost_changes_update_counts_what_was_neither_received_nor_irrelevant, crates/rtps/src/writer_proxy.rs::tests::lost_changes_update_retires_everything_below_the_new_base

Status: done

§8.4.10.4 Table 8.73 WriterProxy missing_changes

Spec: §8.4.10.4, S. 109 — “return { change IN this.changes_from_writer SUCH-THAT change.status == MISSING};”

Repo: crates/rtps/src/writer_proxy.rs (missing_changes)

Tests: crates/rtps/src/writer_proxy.rs::tests::missing_changes_respects_max_count, crates/rtps/src/writer_proxy.rs::tests::received_removes_from_missing

Status: done

§8.4.10.4 Table 8.73 WriterProxy missing_changes_update

Spec: §8.4.10.4, S. 109 — “FOREACH change IN this.changes_from_writer SUCH-THAT ( change.status == UNKNOWN AND seq_num <= last_available_seq_num ) DO { change.status := MISSING; }”.

Repo: crates/rtps/src/writer_proxy.rs (update_from_heartbeat: last_available_sn)

Tests: crates/rtps/src/writer_proxy.rs::tests::heartbeat_sets_available_range

Status: done

§8.4.10.4 Table 8.73 WriterProxy received_change_set

Spec: §8.4.10.4, S. 109 — “FIND change FROM this.changes_from_writer SUCH-THAT change.sequenceNumber == a_seq_num; change.status := RECEIVED”.

Repo: crates/rtps/src/writer_proxy.rs (received_change_set)

Tests: crates/rtps/src/writer_proxy.rs::tests::received_removes_from_missing, crates/rtps/src/writer_proxy.rs::tests::received_before_first_is_ignored

Status: done

§8.4.10.5 Table 8.74 ChangeFromWriter status

Spec: §8.4.10.5, S. 109–110, Table 8.74 — “status: ChangeFromWriter StatusKind — Indicates the status of a CacheChange relative to the RTPS Writer represented by the WriterProxy.” Werte UNKNOWN, MISSING, RECEIVED, NOT_AVAILABLE mit den Unterarten NA_FILTERED, NA_REMOVED, NA_UNSPECIFIED.

Repo: crates/rtps/src/writer_proxy.rs (ChangeFromWriterStatus, change_status, is_known, missing_changes, not_available_count)

Tests: crates/rtps/src/writer_proxy.rs::tests::change_status_is_kept_per_change_with_the_sub_kind, crates/rtps/src/writer_proxy.rs::tests::lost_changes_update_sets_na_removed_per_change, crates/rtps/src/reliable_reader.rs::tests::the_reader_keeps_the_status_of_each_change, crates/rtps/src/reliable_reader.rs::tests::a_gap_sorts_its_changes_by_the_filtered_count

Status: done — die vier Hauptwerte und die drei Unterarten von NOT_AVAILABLE werden je Änderung geführt (Item unter §8.4.6 Table 8.52 ChangeFromWriterStatusKind).

§8.4.10.5 Table 8.74 ChangeFromWriter is_relevant

Spec: §8.4.10.5, S. 109, Table 8.74 — “is_relevant: bool — Indicates whether the change is relevant to the RTPS Reader. The determination of relevant changes is affected by DDS DataReader TIME_BASED_FILTER QoS and also by the use of DDS ContentFilteredTopics.”

Repo: crates/rtps/src/history_cache.rs (ChangeKind::is_relevant, ChangeKind::AliveFiltered); crates/dcps/src/runtime.rs (tbf_should_deliver)

Tests: crates/rtps/src/history_cache.rs::tests::change_kind_alive_filtered_is_alive_but_not_relevant

Status: done

§8.4.11.1 Table 8.75 Best-Effort-StatelessReader T1

Spec: §8.4.11.1, S. 110–111, Table 8.75 T1 — “triggered by the creation of an RTPS StatelessReader … The transition performs no logical actions”.

Repo: —

Tests: —

Status: n/a (informative) — Übergang ohne logische Aktion.

§8.4.11.1 Table 8.75 Best-Effort-StatelessReader T2

Spec: §8.4.11.1, S. 111 — “a_change := new CacheChange(DATA); the_rtps_reader.reader_cache.add_change(a_change);”

Repo: crates/discovery/src/spdp.rs (SpdpReader::samples); crates/rtps/src/reader.rs (BestEffortReader::recv_datagram)

Tests: crates/discovery/src/spdp.rs::tests::samples_reads_every_participant_a_datagram_bundles, crates/rtps/src/reader.rs::tests::reader_handles_multiple_data_in_one_datagram

Status: done

§8.4.11.1 Table 8.75 Best-Effort-StatelessReader T3

Spec: §8.4.11.1, S. 111 — “triggered by the destruction of an RTPS Reader … The transition performs no logical actions”.

Repo: —

Tests: —

Status: n/a (informative) — Übergang ohne logische Aktion.

§8.4.11.2 Reliable StatelessReader nicht unterstützt

Spec: §8.4.11.2, S. 111 — “This combination is not supported by the RTPS protocol.”

Repo: —

Tests: —

Status: n/a (informative) — keine Anforderung; ZeroDDS hat keinen reliable StatelessReader.

§8.4.12.1 Table 8.76 Best-Effort-StatefulReader T1

Spec: §8.4.12.1, S. 112, Table 8.76 T1 — “a_writer_proxy := new WriterProxy(remoteWriterGuid, remoteGroupEntityId, unicastLocatorList, multicastLocatorList); the_rtps_reader.matched_writer_add(a_writer_proxy);”

Repo: crates/rtps/src/reliable_reader.rs (add_writer_proxy, set_best_effort); crates/rtps/src/writer_proxy.rs (remote_group_entity_id)

Tests: crates/rtps/src/reliable_reader.rs::tests::best_effort_reader_skips_leading_gap, crates/rtps/src/writer_proxy.rs::tests::the_remote_group_entity_id_is_kept, crates/dcps/src/runtime.rs::tests::the_proxies_of_a_match_carry_the_remote_group_entity_id

Status: done — matched_writer_add nimmt remoteGroupEntityId und beide Locator-Listen.

§8.4.12.1 Table 8.76 Best-Effort-StatefulReader T2

Spec: §8.4.12.1, S. 113 — “expected_seq_num := writer_proxy.available_changes_max() + 1; if ( a_change.sequenceNumber >= expected_seq_num ) { … add_change(a_change); received_change_set(…); if ( a_change.sequenceNumber > expected_seq_num ) { lost_changes_update(…) } }”.

Repo: crates/rtps/src/reliable_reader.rs (handle_data_into: gap_skipped, lost_changes_update bei best_effort)

Tests: crates/rtps/src/reliable_reader.rs::tests::best_effort_reader_skips_leading_gap, crates/rtps/src/reliable_reader.rs::tests::duplicate_data_is_rejected, crates/rtps/src/reliable_reader.rs::tests::a_best_effort_reader_counts_the_samples_a_gap_lost

Status: done

§8.4.12.1 Table 8.76 Best-Effort-StatefulReader T3

Spec: §8.4.12.1, S. 113 — “the_rtps_reader.matched_writer_remove( the_writer_proxy); delete the_writer_proxy;”

Repo: crates/rtps/src/reliable_reader.rs (remove_writer_proxy)

Tests: crates/rtps/src/reliable_reader.rs::tests::remove_writer_proxy_drops_its_state

Status: done

§8.4.12.1 Table 8.76 Best-Effort-StatefulReader T4

Spec: §8.4.12.1, S. 113 — “the_writer_proxy.not_available_change_set(GAP. sequence_number_set, GAP.filteredCount);”

Repo: crates/rtps/src/reliable_reader.rs (handle_gap)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_best_effort_reader_counts_the_samples_a_gap_lost, crates/rtps/src/reliable_reader.rs::tests::a_gap_sorts_its_changes_by_the_filtered_count, crates/rtps/src/reliable_reader.rs::tests::the_reader_keeps_the_status_of_each_change

Status: done — die Nummern des GAP werden mit der Unterart nach filteredCount als nicht verfügbar markiert und je Änderung gespeichert.

§8.4.12.2 Table 8.77 Reliable-StatefulReader T1

Spec: §8.4.12.2, S. 114–115, Table 8.77 T1 — “a_writer_proxy := new WriterProxy(remoteWriterGuid, remoteGroupEntityId, unicastLocatorList, multicastLocatorList); the_rtps_reader.matched_writer_add(a_writer_proxy);”

Repo: crates/rtps/src/reliable_reader.rs (add_writer_proxy); crates/rtps/src/writer_proxy.rs (remote_group_entity_id)

Tests: crates/rtps/src/reliable_reader.rs::tests::add_writer_proxy_increases_count, crates/rtps/src/reliable_reader.rs::tests::changes_a_writer_sent_before_the_match_are_requested_at_once, crates/rtps/src/writer_proxy.rs::tests::the_remote_group_entity_id_is_kept, crates/dcps/src/runtime.rs::tests::the_proxies_of_a_match_carry_the_remote_group_entity_id

Status: done — matched_writer_add nimmt remoteGroupEntityId und beide Locator-Listen.

§8.4.12.2 Table 8.77 Reliable-StatefulReader T2

Spec: §8.4.12.2, S. 114 — HEARTBEAT empfangen: “if (HB.FinalFlag == NOT_SET) then must_send_ack else if (HB.LivelinessFlag == NOT_SET) then may_send_ack else waiting”.

Repo: —

Tests: crates/rtps/src/reliable_reader.rs::tests::a_heartbeat_with_the_liveliness_flag_is_taken_as_a_heartbeat

Status: done

§8.4.12.2 Table 8.77 Reliable-StatefulReader T3

Spec: §8.4.12.2, S. 115 — “[W::missing_changes() == ] … The transition performs no logical actions.”

Repo: crates/rtps/src/reliable_reader.rs (handle_heartbeat: keine ACKNACK bei F = 1 ohne Fehlendes)

Tests: crates/rtps/src/reliable_reader.rs::tests::heartbeat_without_missing_and_final_schedules_no_acknack

Status: done

§8.4.12.2 Table 8.77 Reliable-StatefulReader T4

Spec: §8.4.12.2, S. 115 — “[W::missing_changes() != ] … The transition performs no logical actions.”

Repo: crates/rtps/src/reliable_reader.rs (handle_heartbeat: has_missing setzt pending_acknack_since)

Tests: crates/rtps/src/reliable_reader.rs::tests::final_heartbeat_from_unknown_to_data_writer_requests_the_missing_sn

Status: done

§8.4.12.2 Table 8.77 Reliable-StatefulReader T5

Spec: §8.4.12.2, S. 115–116 — nach heartbeatResponseDelay “missing_seq_num_set.base := the_writer_proxy.available_changes_max() + 1; … send ACKNACK(missing_seq_num_set);” — bei zu vielen fehlenden Nummern “the subset with smallest value of the sequence number”.

Repo: crates/rtps/src/reliable_reader.rs (tick_outbound, build_acknack_datagram); crates/rtps/src/submessages.rs (SequenceNumberSet::from_missing)

Tests: crates/rtps/src/reliable_reader.rs::tests::heartbeat_with_missing_triggers_acknack_after_delay, crates/rtps/src/submessages.rs::tests::snset_from_missing_spread_wide_stays_within_256_bits, crates/rtps/src/reliable_reader.rs::tests::a_partly_received_sample_is_asked_for_by_nack_frag_not_acknack

Status: done — Basis und kleinste Teilmenge stimmen; die Menge enthält nur Nummern, von denen kein Fragment vorliegt (die übrigen fordert NACK_FRAG an, §8.4.14.1).

§8.4.12.2 Table 8.77 Reliable-StatefulReader T6

Spec: §8.4.12.2, S. 116 — “Similar to T1 … The transition performs no logical actions in the virtual machine.”

Repo: —

Tests: —

Status: n/a (informative) — Übergang ohne logische Aktion.

§8.4.12.2 Table 8.77 Reliable-StatefulReader T7

Spec: §8.4.12.2, S. 116 — “the_writer_proxy.missing_changes_update( HEARTBEAT.lastSN); the_writer_proxy.lost_changes_update(HEARTBEAT.firstSN, true);”

Repo: crates/rtps/src/writer_proxy.rs (update_from_heartbeat)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_heartbeat_with_the_liveliness_flag_is_taken_as_a_heartbeat

Status: done

§8.4.12.2 Table 8.77 Reliable-StatefulReader T8

Spec: §8.4.12.2, S. 116 — “a_change := new CacheChange(DATA); the_reader.reader_cache.add_change(a_change); the_writer_proxy.received_change_set(a_change.sequenceNumber);”

Repo: crates/rtps/src/reliable_reader.rs (handle_data_into, store_received)

Tests: crates/rtps/src/reliable_reader.rs::tests::in_order_data_delivered_immediately, crates/rtps/src/reliable_reader.rs::tests::out_of_order_data_buffered_until_gap_filled

Status: done

§8.4.12.2 Table 8.77 Reliable-StatefulReader T9

Spec: §8.4.12.2, S. 116 — “the_writer_proxy.not_available_change_set(GAP. sequence_number_set, GAP.filteredCount);”

Repo: crates/rtps/src/reliable_reader.rs (handle_gap)

Tests: crates/rtps/src/reliable_reader.rs::tests::gap_after_the_held_data_releases_it, crates/rtps/src/reliable_reader.rs::tests::a_gap_sorts_its_changes_by_the_filtered_count, crates/rtps/src/reliable_reader.rs::tests::the_reader_keeps_the_status_of_each_change

Status: done — filteredCount wird ausgewertet (Item unter §8.4.10.4 Table 8.73 WriterProxy not_available_change_set); die Nummern stehen je Änderung als NOT_AVAILABLE.

§8.4.12.2 Table 8.77 Reliable-StatefulReader T10

Spec: §8.4.12.2, S. 116 — “the_rtps_reader.matched_writer_remove( the_writer_proxy); delete the_writer_proxy;”

Repo: crates/rtps/src/reliable_reader.rs (remove_writer_proxy, depart_writer_proxy)

Tests: crates/rtps/src/reliable_reader.rs::tests::remove_writer_proxy_drops_its_state, crates/rtps/src/reliable_reader.rs::tests::a_departed_writer_counts_what_is_missing_in_front_of_its_held_samples

Status: done

§8.4.12.3 ChangeFromWriter illustrated

Spec: §8.4.12.3, S. 117–118, Figure 8.25 — Zustände Unknown, Missing, NotRequested, Requested, Received, NotAvailable (Filtered, Removed, Unspecified) und die auslösenden Ereignisse.

Repo: —

Tests: —

Status: n/a (informative) — Veranschaulichung der Übergänge aus §8.4.10.4 und §8.4.12.2 (“It is illustrative”); keine eigene Anforderung.

§8.4.13 Writer Liveliness Protocol: Unterstützung verpflichtend

Spec: §8.4.13, S. 118 — “All implementations must support the Writer Liveliness Protocol in order to be interoperable.”

Repo: crates/dcps/src/wlp.rs (WlpEndpoint); crates/dcps/src/runtime.rs (DcpsRuntime::wlp)

Tests: crates/dcps/tests/wlp_integration.rs::linux_only::two_participants_exchange_automatic_wlp_heartbeats, crates/dcps/src/runtime.rs::tests::two_runtimes_exchange_wlp_heartbeat, crates/dcps/src/wlp.rs::tests::a_late_reader_is_told_by_heartbeat_and_gets_the_held_samples_on_request, crates/dcps/src/wlp.rs::tests::the_reader_is_treated_as_builtin_endpoint_qos_says

Status: done — Writer und Reader des Protokolls laufen in jedem Teilnehmer; der Writer hat die QoS aus §8.4.13.3 und behandelt den Reader nach builtinEndpointQos. Die Wire-Änderung des Writers ist gegen Cyclone, Fast DDS, OpenDDS und RTI nicht gemessen.

§8.4.13.1 Assoziation mit den Builtin-Endpunkten eines entdeckten Teilnehmers

Spec: §8.4.13.1, S. 118 — “once a Participant knows of the presence of another Participant, it can assume the presence of the built-in Endpoints made available by the remote Participant and establish the association with the locally matching built-in Endpoints.”

Repo: crates/dcps/src/wlp.rs (WlpEndpoint::add_peer_reader); crates/dcps/src/runtime.rs (spdp_announced, wlp_unicast_targets, answer_wlp_heartbeats)

Tests: crates/dcps/src/runtime.rs::tests::wlp_unicast_targets_prefers_metatraffic_then_default, crates/dcps/src/runtime.rs::tests::two_runtimes_assert_liveliness_reaches_peer, crates/dcps/src/wlp.rs::tests::only_a_participant_with_a_message_reader_gets_a_proxy

Status: done — aus jeder SPDP-Ankündigung entsteht (unverändert: bleibt) ein Reader-Proxy für den BuiltinParticipantMessageReader des Teilnehmers, wenn dessen availableBuiltinEndpoints ihn nennen; Ziel sind seine Metatraffic-Locatoren.

§8.4.13.1 Dasselbe Protokoll wie für Anwendungs-Endpunkte

Spec: §8.4.13.1, S. 118 — “The protocol used to communicate between built-in Endpoints is the same as used for application-defined Endpoints.”

Repo: crates/dcps/src/wlp.rs (WlpEndpoint: make_writer, write_pulse, add_peer_reader, handle_reader_messages, tick); crates/dcps/src/runtime.rs (WLP-Tick, spdp_announced)

Tests: crates/dcps/src/wlp.rs::tests::a_late_reader_is_told_by_heartbeat_and_gets_the_held_samples_on_request, crates/dcps/src/wlp.rs::tests::the_writer_heartbeats_until_the_reader_has_acknowledged

Status: done — der WLP-Writer ist ein ReliableWriter mit einem Reader-Proxy je Teilnehmer: DATA mit Piggyback-HEARTBEAT, periodische HEARTBEATs bis zur Bestätigung, Wiederholung nur des Angeforderten, GAP für überholte Nummern. Der Reader beantwortet HEARTBEATs (heartbeat_responses) und führt je Writer die höchste empfangene Sequenznummer.

§8.4.13.2 Builtin-Endpunkte BuiltinParticipantMessageWriter und -Reader

Spec: §8.4.13.2, S. 118 — “The RTPS Protocol reserves the following values of the EntityId_t for these built-in Endpoints: ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER”

Repo: crates/rtps/src/wire_types.rs (EntityId::BUILTIN_PARTICIPANT_MESSAGE_WRITER, EntityId::BUILTIN_PARTICIPANT_MESSAGE_READER); crates/dcps/src/wlp.rs (WlpEndpoint::handle_datagram)

Tests: crates/dcps/src/wlp.rs::tests::wlp_handle_datagram_updates_peer_state, crates/dcps/src/wlp.rs::tests::wlp_handle_datagram_ignores_non_wlp_traffic

Status: done — die Werte sind unter §9.3.1.3 geführt.

§8.4.13.3 Writer durability.kind = TRANSIENT_LOCAL

Spec: §8.4.13.3, S. 118 — “both the BuiltinParticipantMessageWriter and BuiltinParticipantMessageReader shall use the following QoS values: durability.kind = TRANSIENT_LOCAL_DURABILITY”.

Repo: crates/dcps/src/wlp.rs (WlpEndpoint: make_writer, write_pulse, add_peer_reader, handle_reader_messages, tick); crates/dcps/src/runtime.rs (WLP-Tick, spdp_announced)

Tests: crates/dcps/src/wlp.rs::tests::a_late_reader_is_told_by_heartbeat_and_gets_the_held_samples_on_request

Status: done — ein später hinzukommender Reader erhält die gehaltenen Proben mit dem ersten Tick, ohne sie anzufordern (die Historie hält eine Probe je Art, eine Anforderung träfe sonst eine neuere Probe), und ein HEARTBEAT sagt, was die Historie hält; fordert er sie erneut an, erhält er sie noch einmal.

§8.4.13.3 Writer history KEEP_LAST, depth 1

Spec: §8.4.13.3, S. 118–119 — “history.kind = KEEP_LAST_HISTORY_QOS”, “history.depth = 1”.

Repo: crates/dcps/src/wlp.rs (WlpEndpoint: make_writer, write_pulse, add_peer_reader, handle_reader_messages, tick); crates/dcps/src/runtime.rs (WLP-Tick, spdp_announced)

Tests: crates/dcps/src/wlp.rs::tests::the_history_holds_the_last_sample_of_each_kind

Status: done — die Historie hält die letzte Probe je Instanz (participantGuidPrefix, kind; PID_KEY_HASH in der In-line-QoS); überholte Proben werden nicht wiederholt.

§8.4.13.3 Reader durability.kind = TRANSIENT_LOCAL

Spec: §8.4.13.3, S. 118 — “both the BuiltinParticipantMessageWriter and BuiltinParticipantMessageReader shall use the following QoS values: durability.kind = TRANSIENT_LOCAL_DURABILITY”.

Repo: crates/dcps/src/wlp.rs (WlpEndpoint::heartbeat_responses: die Anforderung beginnt bei firstSN des HEARTBEAT, nicht beim Match)

Tests: crates/dcps/src/wlp.rs::tests::a_heartbeat_announcing_a_pulse_not_received_is_answered_with_a_request_for_it, crates/dcps/tests/cyclone_live_wlp.rs::cyclone_live_wlp_handshake

Status: done

§8.4.13.3 Reader history KEEP_LAST, depth 1

Spec: §8.4.13.3, S. 118–119 — “history.kind = KEEP_LAST_HISTORY_QOS”, “history.depth = 1”.

Repo: crates/dcps/src/wlp.rs (WlpEndpoint::peers: je Teilnehmer der zuletzt empfangene Stand)

Tests: crates/dcps/src/wlp.rs::tests::wlp_handle_datagram_updates_peer_state

Status: done — der Reader hält keine Proben, sondern übergibt jede empfangene Probe sofort an die Liveliness-Verwaltung der DataReader und merkt sich je Teilnehmer last_seen und last_kind.

§8.4.13.3 Writer reliability.kind = RELIABLE

Spec: §8.4.13.3, S. 119 — “The BuiltinParticipantMessageWriter shall use reliability.kind = RELIABLE_RELIABILITY_QOS.”

Repo: crates/dcps/src/wlp.rs (WlpEndpoint: make_writer, write_pulse, add_peer_reader, handle_reader_messages, tick); crates/dcps/src/runtime.rs (WLP-Tick, spdp_announced)

Tests: crates/dcps/src/wlp.rs::tests::the_writer_heartbeats_until_the_reader_has_acknowledged, crates/dcps/src/wlp.rs::tests::a_late_reader_is_told_by_heartbeat_and_gets_the_held_samples_on_request

Status: done — der Writer führt Zustand je Reader (Reader-Proxy), sendet HEARTBEATs bis zur Bestätigung und wiederholt auf ACKNACK (handle_reader_messages).

§8.4.13.3 Reader RELIABLE oder BEST_EFFORT

Spec: §8.4.13.3, S. 119 — “The BuiltinParticipantMessageReader may be configured to use either RELIABLE_RELIABILITY_QOS or BEST_EFFORT_RELIABILITY_QOS. If the BuiltinParticipantMessageReader is configured to use BEST_EFFORT_RELIABILITY_QOS then the BEST_EFFORT_PARTICIPANT_MESSAGE_DATA_READER flag in ParticipantProxy::builtinEndpointQos shall be set.”

Repo: crates/dcps/src/wlp.rs (WlpEndpoint::heartbeat_responses)

Tests: crates/dcps/src/wlp.rs::tests::a_heartbeat_announcing_a_pulse_not_received_is_answered_with_a_request_for_it, crates/dcps/src/wlp.rs::tests::once_the_pulse_arrived_a_final_heartbeat_gets_no_answer_and_a_plain_one_the_ack

Status: done — der Reader beantwortet HEARTBEATs wie ein RELIABLE-Reader; das Flag entfällt, ZeroDDS sendet kein PID_BUILTIN_ENDPOINT_QOS.

§8.4.13.3 Writer behandelt den Reader nach builtinEndpointQos

Spec: §8.4.13.3, S. 119 — “If the ParticipantProxy::builtinEndpointQos is included in the SPDPdiscoveredParticipantData, then the BuiltinParticipantMessageWriter shall treat the BuiltinParticipantMessageReader as indicated by the flags. If the ParticipantProxy::builtinEndpointQos is not included then the BuiltinParticipantMessageWriter shall treat the BuiltinParticipantMessageReader as if it is configured with RELIABLE_RELIABILITY_QOS.”

Repo: crates/dcps/src/wlp.rs (WlpEndpoint::add_peer_reader, sync_proxy); crates/dcps/src/runtime.rs (spdp_announced)

Tests: crates/dcps/src/wlp.rs::tests::the_reader_is_treated_as_builtin_endpoint_qos_says

Status: done — mit builtinEndpointQos und dem Flag ist der Reader ein Best-Effort-Proxy (keine HEARTBEATs), sonst RELIABLE.

§8.4.13.4 Figure 8.26 ParticipantMessageData

Spec: §8.4.13.4, S. 119, Figure 8.26 — “Figure 8.26 defines the ParticipantMessageData datatype associated with the RTPS built-in Endpoint for the DCPSParticipantMessage Topic.” Attribute participantGuidPrefix, kind, data.

Repo: crates/rtps/src/participant_message_data.rs (ParticipantMessageData, to_cdr, from_cdr)

Tests: crates/rtps/src/participant_message_data.rs::tests::participant_message_data_octets_are_those_of_9_6_3_1, crates/rtps/src/participant_message_data.rs::tests::participant_message_data_reads_the_fast_dds_beat, crates/rtps/src/participant_message_data.rs::tests::participant_message_data_roundtrip_with_topic_token

Status: done

§8.4.13.5 AUTOMATIC: Probe schneller als die kürzeste Lease

Spec: §8.4.13.5, S. 119 — “If the Participant contains one or more Writers with a liveliness of AUTOMATIC_LIVELINESS_QOS, then one sample is written at a rate faster than the smallest lease duration among the Writers sharing this QoS.”

Repo: crates/dcps/src/runtime.rs (refresh_wlp_period: ein Drittel der kürzesten endlichen Lease eines AUTOMATIC-Writers, höchstens ein Drittel der Teilnehmer-Lease); crates/dcps/src/wlp.rs (WlpEndpoint::tick)

Tests: crates/dcps/tests/liveliness_qos.rs::linux::an_automatic_writer_that_never_writes_stays_alive_at_a_remote_reader, crates/dcps/src/wlp.rs::tests::wlp_tick_emits_again_after_period, crates/dcps/src/runtime.rs::tests::wlp_period_default_is_lease_over_three

Status: done — die AUTOMATIC-Probe geht auch ohne AUTOMATIC-Writer aus.

§8.4.13.5 MANUAL_BY_PARTICIPANT: eigene Probe

Spec: §8.4.13.5, S. 119 — “Similarly, a separate sample is written if the Participant contains one or more Writers with a liveliness of MANUAL_BY_PARTICIPANT_LIVELINESS_QOS at a rate faster than the smallest lease duration among these Writers.”

Repo: crates/dcps/src/runtime.rs (DcpsRuntime::assert_liveliness, refresh_manual_by_participant); crates/dcps/src/wlp.rs (WlpEndpoint::assert_participant, refresh_participant)

Tests: crates/dcps/src/wlp.rs::tests::wlp_assert_participant_emits_manual_pulse, crates/dcps/src/wlp.rs::tests::refreshes_before_the_tick_share_one_manual_by_participant_sample, crates/dcps/tests/wlp_integration.rs::linux_only::manual_by_participant_pulse_arrives_at_peer, crates/dcps/src/runtime.rs::tests::a_manual_by_participant_writer_refreshes_the_participant_liveliness

Status: done — die Probe wird bei DomainParticipant::assert_liveliness und bei write, assert_liveliness, dispose und unregister_instance eines MANUAL_BY_PARTICIPANT-Writers geschrieben; Aufrufe vor dem Tick teilen sich eine Probe.

§8.4.13.5 Zwei Instanzen, Schlüssel participantGuidPrefix und kind

Spec: §8.4.13.5, S. 119 — “The instances are distinguished using their DDS key, which is comprised of the participantGuidPrefix and kind fields. Each of the two types of liveliness QoS handled through this protocol will result in a unique kind field and therefore form two distinct instances in the HistoryCache.”

Repo: crates/dcps/src/wlp.rs (WlpEndpoint::write_pulse)

Tests: crates/dcps/src/wlp.rs::tests::the_history_holds_the_last_sample_of_each_kind, crates/dcps/src/wlp.rs::tests::wlp_assert_participant_emits_manual_pulse, crates/dcps/src/wlp.rs::tests::wlp_handle_datagram_updates_peer_state

Status: done — die Instanz ist (participantGuidPrefix, kind); der KeyHash (12 Oktette Prefix, 4 Oktette kind, Big-Endian) steht als PID_KEY_HASH in der In-line-QoS jeder DATA, die Historie hält eine Probe je Instanz.

§8.4.13.5 participantGuidPrefix des schreibenden Teilnehmers

Spec: §8.4.13.5, S. 119 — “In both liveliness cases the participantGuidPrefix field contains the GuidPrefix_t of the Participant that is writing the data (and therefore asserting the liveliness of its Writers).”

Repo: crates/dcps/src/wlp.rs (WlpEndpoint::encode_pulse: ParticipantMessageData::automatic(self.own_prefix))

Tests: crates/dcps/src/wlp.rs::tests::wlp_handle_datagram_updates_peer_state, crates/rtps/src/participant_message_data.rs::tests::participant_message_data_automatic_default_data_empty

Status: done

§8.4.13.5 MANUAL_BY_TOPIC nicht über den BuiltinParticipantMessageWriter

Spec: §8.4.13.5, S. 119 — “The DDS liveliness kind MANUAL_BY_TOPIC_LIVELINESS_QOS is not implemented using the BuiltinParticipantMessageWriter and BuiltinParticipantMessageReader. It is discussed in 8.7.2.2.3.”

Repo: crates/dcps/src/publisher.rs (DataWriter::assert_liveliness → DcpsRuntime::assert_writer_liveliness_eid: HEARTBEAT mit LivelinessFlag)

Tests: crates/dcps/src/runtime.rs::tests::assert_liveliness_keeps_a_manual_writer_alive_without_writing, crates/rtps/src/reliable_writer.rs::tests::liveliness_heartbeat_is_a_final_heartbeat_with_the_liveliness_flag

Status: done — DcpsRuntime::assert_writer_liveliness schreibt zusätzlich eine Probe mit der Herstellerart 0x80000001; die DCPS-API ruft diese Funktion nicht auf.

§8.4.14 Optionales Verhalten

Spec: §8.4.14, S. 119 — “Optional features may not be supported by all RTPS implementations. An optional feature does not affect basic interoperability, but is only available if all implementations involved support it.”

Repo: —

Tests: —

Status: n/a (informative) — Einordnung der folgenden Unterabschnitte, keine Anforderung.

§8.4.14.1 Large Data: Transportgrenzen und Fragment-Submessages

Spec: §8.4.14.1, S. 120 — “a transport may impose its own limitations. For example, it may limit the maximum packet size (e.g., 64K for UDP) … 8.3.8 introduces the following Submessages to enable fragmenting large data: DataFrag, HeartbeatFrag, NackFrag”.

Repo: —

Tests: —

Status: n/a (informative) — Begründung, keine Anforderung; die Submessages sind unter §8.3.8 geführt.

§8.4.14.1 Fragmentgröße aus den Transporten des Writers

Spec: §8.4.14.1, S. 120 — “All transports available to the Writer must be able to accommodate DataFrag Submessages containing at least one fragment. This means the transport with the smallest maximum message size determines the fragment size.” “Note the fragment size is determined by all transports available to the Writer, not simply the subset of transports required to reach all currently known Readers.”

Repo: crates/transport/src/lib.rs (Transport::max_message_size, DEFAULT_MAX_MESSAGE_SIZE); crates/transport-udp/src/udp_transport.rs (UdpTransportConfig::max_message_size); crates/transport-shm, transport-uds, transport-tcp, transport-tsn (je max_message_size); crates/dcps/src/layered_transport.rs (Minimum der Legs); crates/rtps/src/reliable_writer.rs (fragment_size_for_message_size); crates/dcps/src/runtime.rs (Writer-Anlage)

Tests: crates/dcps/src/runtime.rs::tests::a_writers_fragment_size_follows_the_message_size_of_its_transport, crates/rtps/src/reliable_writer.rs::tests::the_fragment_size_is_bounded_by_what_the_field_holds, crates/transport-udp/src/udp_transport.rs::tests::max_message_size_is_the_configured_one_up_to_the_datagram_limit, crates/dcps/tests/runtime_config_layering.rs::the_udp_message_size_is_a_setting, crates/rtps/src/reliable_writer.rs::tests::fragment_size_is_fixed_and_a_larger_path_gets_one_data

Status: done — jeder Transport nennt seine größte Nachricht (Transport::max_message_size; UDP einstellbar mit transport.udp.max_message_size, Vorgabe 1472; SHM und UDS ihr Datagramm-Limit, TCP die Rahmengrenze, TSN 1500; der Schichten-Transport das Minimum seiner Legs). Die Fragmentgröße eines Writers ist die Nachricht des kleinsten Transports abzüglich 128 Oktette, fest für das Leben des Writers: 1344 bei der Vorgabe.

§8.4.14.1 Fragmentgröße fest je Writer

Spec: §8.4.14.1, S. 120 — “The fragment size must be fixed for a given Writer and is identical for all remote Readers. By fixing the fragment size, the data a fragment number refers to does not depend on a particular remote Reader.”

Repo: crates/rtps/src/reliable_writer.rs (ReliableWriter::fragment_size_for, needs_fragmentation); crates/rtps/src/reader_proxy.rs (ReaderProxy::message_limit)

Tests: crates/rtps/src/reliable_writer.rs::tests::fragment_size_is_fixed_and_a_larger_path_gets_one_data, crates/rtps/src/reliable_writer.rs::tests::the_fragment_size_does_not_depend_on_the_reader_expecting_inline_qos

Status: done — die Fragmentgröße wird nach dem Anlegen des Writers nicht mehr geändert (set_fragmentation entfällt) und ist für alle Reader dieselbe; die In-line-QoS, die ein Fragment kürzt, wird mit ihrer größten Länge für irgendeinen Reader gezählt, sodass auch expectsInlineQos eines Readers sie nicht ändert.

§8.4.14.1 Fragmentgröße ≤ 65536

Spec: §8.4.14.1, S. 120 — “The fragment size must satisfy: fragment size <= 65536 bytes.”

Repo: crates/rtps/src/reliable_writer.rs (MAX_FRAGMENT_SIZE, ReliableWriter::try_new, ReliableWriter::new, fragment_size_for)

Tests: crates/rtps/src/reliable_writer.rs::tests::the_fragment_size_is_bounded_by_what_the_field_holds

Status: done — fragmentSize des DATA_FRAG ist ein unsigned short; 65536 hat keine Kodierung, die Grenze ist 65535. try_new weist größere Werte mit einem Fehler ab (new bricht ab). Ein DATA_FRAG hält seine 32 festen Oktette, die Inline-QoS und das Fragment in den 65535 Oktetten von octetsToNextHeader; die Fragmentgröße liegt entsprechend höchstens bei 65503.

§8.4.14.1 DataFrag in aufsteigender Fragmentnummer

Spec: §8.4.14.1, S. 120 — “DataFrag Submessages are sent in order, where ordering is defined by increasing fragment numbers.”

Repo: crates/rtps/src/reliable_writer.rs (push_sample_datagrams)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_above_fragment_size_packs_the_fragments_a_message_carries

Status: done

§8.4.14.1 Fragmentieren nur, wenn nötig (je Sequenznummer)

Spec: §8.4.14.1, S. 120 — “Data must only be fragmented if required. … Likewise, for variable size data types, a regular Data Submessage must be used if fragmentation is not required for a particular sequence number.”

Repo: crates/rtps/src/reliable_writer.rs (needs_fragmentation, push_sample_datagrams)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_under_fragment_size_produces_single_data, crates/rtps/src/reliable_writer.rs::tests::write_above_fragment_size_packs_the_fragments_a_message_carries, crates/rtps/tests/reliable_e2e.rs::e2e_frag_mixed_data_and_data_frag

Status: done

§8.4.14.1 Reguläres Data auf Transporten ohne Fragmentierungsbedarf

Spec: §8.4.14.1, S. 120 — “If multiple transports are available to the Writer and some transports do not require fragmentation, a regular Data Submessage must be sent on those transports instead.”

Repo: crates/rtps/src/reader_proxy.rs (ReaderProxy::set_message_limit); crates/rtps/src/reliable_writer.rs (needs_fragmentation, unfragmented_room); crates/dcps/src/runtime.rs (Match eines Readers auf demselben Host)

Tests: crates/rtps/src/reliable_writer.rs::tests::fragment_size_is_fixed_and_a_larger_path_gets_one_data

Status: done — ein Reader auf demselben Host (Loopback, Nachrichtengröße LOOPBACK_MTU) erhält ein Sample, das in eine Nachricht passt, als eine DATA; ein entfernter Reader desselben Writers erhält dasselbe Sample als DATA_FRAGs der Writer-Größe.

§8.4.14.1 Inline-QoS mit dem ersten DataFrag

Spec: §8.4.14.1, S. 120 — “For a given sequence number, if in-line QoS parameters are used, they must be included with the first DataFrag Submessage (containing the fragment with fragment number equal to 1).”

Repo: crates/rtps/src/reliable_writer.rs (build_data_frag_submessage_datagram: sample_inline_qos an jedem DATA_FRAG)

Tests: crates/rtps/src/reliable_writer.rs::tests::an_oversized_coherent_set_member_goes_out_as_marked_fragments, crates/rtps/src/reliable_writer.rs::tests::keyed_alive_preserves_inline_hash_on_data_fragments_and_rebuilds, crates/rtps/src/fragment_assembler.rs::tests::the_first_fragments_inline_qos_reaches_the_completed_sample

Status: done

§8.4.14.1 Empfehlung: mehrere Fragmente je DataFrag

Spec: §8.4.14.1, S. 120 — “If a transport can accommodate multiple fragments of the given fragment size, it is recommended that implementations concatenate as many fragments as possible into a single DataFrag message.”

Repo: crates/rtps/src/reliable_writer.rs (fragments_per_message, push_sample_datagrams, Antwort auf NACK_FRAG in tick); crates/rtps/src/reader_proxy.rs (next_requested_fragment_run_after)

Tests: crates/rtps/src/reliable_writer.rs::tests::the_fragments_of_a_sample_fill_the_messages_and_no_more, crates/rtps/src/reliable_writer.rs::tests::write_above_fragment_size_packs_the_fragments_a_message_carries, crates/rtps/src/reader_proxy.rs::tests::next_requested_fragment_run_after_pulls_neighbours_of_one_sn

Status: done — ein DATA_FRAG enthält so viele Fragmente, wie die Nachricht an den Reader trägt (fragmentsInSubmessage); das gilt für den ersten Versand und für die Antwort auf ein NACK_FRAG (benachbarte angeforderte Fragmente). Bei der Vorgabe von 1472 Oktetten passt ein Fragment in eine Nachricht.

§8.4.14.1 Flusssteuerung

Spec: §8.4.14.1, S. 121 — “When sending multiple DataFrag messages, flow control may be required to avoid flooding the network. … This is not part of the RTPS specification.”

Repo: —

Tests: —

Status: n/a (informative) — laut Text nicht Teil der Spezifikation.

§8.4.14.1 Zusammensetzen: danach Verhalten wie Data

Spec: §8.4.14.1, S. 121 — “Once all fragments have been received, the same protocol behavior applies as for a regular Data Submessage.”

Repo: crates/rtps/src/reliable_reader.rs (handle_data_frag: received_change_set, store_received, collect_in_order_for)

Tests: crates/rtps/tests/reliable_e2e.rs::e2e_frag_many_samples_3_fragments_each_10_percent_loss, crates/rtps/tests/reliable_e2e.rs::e2e_frag_large_sample_30_percent_loss, crates/rtps/src/reliable_reader.rs::tests::a_reassembled_sample_with_the_filtered_flag_is_known_but_not_delivered, crates/rtps/src/reliable_reader.rs::tests::a_reassembled_key_is_a_dispose_or_a_registration_as_a_data_is

Status: done — Bestätigung, Auslieferung in Reihenfolge und Auswertung der Inline-QoS des ersten Fragments (Status-Info mit D, U und F, Key-Registrierung, gerichtetes Schreiben, Coherent Set, Gruppe) wie bei Data.

§8.4.14.1 Fragmente in beliebiger Reihenfolge

Spec: §8.4.14.1, S. 121 — “Note that implementations must be able to handle out-of-order arrival of DataFrag submessages.”

Repo: crates/rtps/src/fragment_assembler.rs (FragmentAssembler::insert)

Tests: crates/rtps/src/fragment_assembler.rs::tests::fragments_complete_out_of_order, crates/rtps/src/fragment_assembler.rs::tests::out_of_order_fragments_preserve_known_zero_key

Status: done

§8.4.14.1 Heartbeat nur für vollständig verfügbare Nummern

Spec: §8.4.14.1, S. 121 — “A Heartbeat message must only include those sequence numbers for which all fragments are available.”

Repo: crates/rtps/src/reliable_writer.rs (write_sample_with_inline_qos: stage_sample legt das ganze Sample in den HistoryCache, bevor ein Fragment gesendet wird; lastSN des HEARTBEAT ist last_written_sn)

Tests: crates/rtps/tests/reliable_e2e.rs::e2e_frag_large_sample_30_percent_loss

Status: done

§8.4.14.1 Positive Bestätigung erst nach allen Fragmenten

Spec: §8.4.14.1, S. 121 — “an AckNack message must only positively acknowledge a sequence number when all fragments were received for that sequence number.”

Repo: crates/rtps/src/reliable_reader.rs (handle_data_frag: received_change_set erst, wenn FragmentAssembler::insert das Sample liefert)

Tests: crates/rtps/tests/reliable_e2e.rs::e2e_frag_large_sample_30_percent_loss, crates/rtps/tests/reliable_e2e.rs::e2e_frag_many_samples_3_fragments_each_10_percent_loss

Status: done

§8.4.14.1 AckNack nur für vollständig fehlende Nummern

Spec: §8.4.14.1, S. 121 — “Likewise, a sequence number must be negatively acknowledged only when all fragments are missing.”

Repo: —

Tests: crates/rtps/src/reliable_reader.rs::tests::a_partly_received_sample_is_asked_for_by_nack_frag_not_acknack

Status: done

§8.4.14.1 NackFrag für einen Teil der Fragmente

Spec: §8.4.14.1, S. 121 — “In order to negatively acknowledge a subset of fragments for a given sequence number, a NackFrag Submessage must be used. When data is fragmented, a Heartbeat may trigger both AckNack and NackFrag Submessages.”

Repo: crates/rtps/src/reliable_reader.rs (tick_outbound: ein NACK_FRAG je unvollständiger Sequenznummer, dann das ACKNACK; build_nackfrag_datagram)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_partly_received_sample_is_asked_for_by_nack_frag_not_acknack

Status: done

§8.4.14.1 HeartbeatFrag für teilweise verfügbare Nummern

Spec: §8.4.14.1, S. 121 — “If a Writer wants to inform a Reader on the partial availability of fragments for a given sequence number, a HeartbeatFrag Submessage can be used instead.”

Repo: —

Tests: —

Status: n/a (informative) — keine Anforderung; die Antwort des Readers auf HeartbeatFrag ist unter §8.3.8.7 geführt.

§8.4.14.1 NackFrag nur als Antwort auf Heartbeat oder HeartbeatFrag

Spec: §8.4.14.1, S. 121 — “A NackFrag Submessage can only be sent in response to a Heartbeat or HeartbeatFrag submessage.”

Repo: crates/rtps/src/reliable_reader.rs (handle_heartbeat, handle_heartbeat_frag, handle_data_frag_opening, tick_outbound)

Tests: crates/rtps/src/reliable_reader.rs::tests::acknack_and_nack_frag_wait_for_a_heartbeat, crates/rtps/src/reliable_reader.rs::tests::a_heartbeat_frag_is_answered_when_an_available_fragment_is_missing

Status: done — NACK_FRAG geht nur im Tick nach einem HEARTBEAT oder HEARTBEAT_FRAG aus; ein DATA_FRAG, das Fragmente offen lässt, löst keinen aus. Ein verlorenes Fragment wird mit dem nächsten HEARTBEAT des Writers angefordert.

§8.4.15 Implementation Guidelines

Spec: §8.4.15, S. 121 — “The contents of this sub clause are not part of the formal specification of the protocol.”

Repo: —

Tests: —

Status: n/a (informative) — laut Text nicht Teil der Spezifikation.

§8.4.15.1 Implementierung von ReaderProxy und WriterProxy

Spec: §8.4.15.1, S. 121–122 — “In practice, what is required is that the ReaderProxy is able to implement the operations used by the protocol and this does not require the use of explicit associations.”

Repo: —

Tests: —

Status: n/a (informative) — Leitfaden nach §8.4.15.

§8.4.15.2 Gap und AckNack effizient nutzen

Spec: §8.4.15.2, S. 122 — “implementations that combine multiple Gap and AckNack Submessages and take advantage of the ability of these Submessages to contain a set of sequence number will be more efficient”.

Repo: —

Tests: —

Status: n/a (informative) — Leitfaden nach §8.4.15.

§8.4.15.3 Mehrere Data-Submessages zusammenfassen

Spec: §8.4.15.3, S. 122 — “implementations that combine Submessages into a single RTPS message will in general make better utilization of CPU and bandwidth.”

Repo: —

Tests: —

Status: n/a (informative) — Leitfaden nach §8.4.15.

§8.4.15.4 HeartBeat an Data anhängen

Spec: §8.4.15.4, S. 122 — “A particularly useful case is the piggybacking of HeartBeat Submessages following Data Submessages.”

Repo: —

Tests: —

Status: n/a (informative) — Leitfaden nach §8.4.15.

§8.4.15.5 Senden an unbekannte readerId

Spec: §8.4.15.5, S. 122 — “Implementations are encouraged to use this feature to minimize bandwidth usage.”

Repo: —

Tests: —

Status: n/a (informative) — Leitfaden nach §8.4.15.

§8.4.15.6 Ressourcen von nicht antwortenden Readern zurückgewinnen

Spec: §8.4.15.6, S. 123 — “the Writer should be allowed to deem the Reader as ‘Inactive’ and proceed in updating its queue.”

Repo: —

Tests: —

Status: n/a (informative) — Leitfaden nach §8.4.15.

§8.4.15.7 Count in Heartbeat, HeartbeatFrag, AckNack und NackFrag

Spec: §8.4.15.7, S. 123 — “an implementation should ensure that same logical HEARTBEATs are tagged with the same Count.” “The Count element should be incremented and compared according to modular arithmetic rules in order to accommodate the integer overflow.”

Repo: —

Tests: —

Status: n/a (informative) — Leitfaden nach §8.4.15; die Pflichten zu Count stehen unter §8.3.8.

§8.5 Discovery Module

§8.5 Entdeckung entfernter Entitäten und Builtin-Topics

Spec: §8.5, S. 123 — “DDS implementations must automatically discover the presence of remote entities, both when they join and leave the network. This discovery information is made accessible to the user through DDS built-in topics.”

Repo: crates/dcps/src/builtin_subscriber.rs (BuiltinSubscriber); crates/dcps/src/runtime.rs (handle_spdp_datagram, SEDP-Ereignisse)

Tests: crates/dcps/tests/builtin_topic_readers.rs::linux_e2e::spdp_receive_populates_dcps_participant_reader, crates/dcps/tests/builtin_topic_readers.rs::linux_e2e::sedp_pub_sub_populates_dcps_publication_and_subscription_readers, crates/dcps/tests/endpoint_delete_unmatch_e2e.rs::linux_e2e::dropping_a_writer_unmatches_the_remote_reader

Status: done

§8.5.1 SPDP und SEDP als Mindestumfang

Spec: §8.5.1, S. 124 — “For the purpose of interoperability, all RTPS implementations must provide at least the following discovery protocols: 1. Simple Participant Discovery Protocol (SPDP) 2. Simple Endpoint Discovery Protocol (SEDP)”. Ebenso §8.5.3, S. 125, und §8.5.4, S. 130.

Repo: crates/discovery/src/spdp.rs; crates/discovery/src/sedp/stack.rs (SedpStack)

Tests: crates/discovery/tests/spdp_loopback_e2e.rs::two_zerodds_participants_discover_each_other, crates/discovery/src/sedp/stack.rs::tests::end_to_end_discovery_between_two_stacks

Status: done

§8.5.1 Weitere PDP und EDP

Spec: §8.5.1, S. 124 — “Implementations may choose to support multiple PDPs and EDPs, possibly vendor-specific.” “How this information is used by a Participant to configure its local Endpoints depends on the actual implementation of the RTPS protocol and is not part of the discovery protocol specification.”

Repo: —

Tests: —

Status: n/a (informative) — keine Anforderung.

§8.5.2 Builtin-Topics und ihre RTPS-Endpunkte

Spec: §8.5.2, S. 124 — “There are four pre-defined built-in Topics: “DCPSParticipant,” “DCPSSubscription,” “DCPSPublication,” and “DCPSTopic.”” “The built-in DataReaders act as regular DDS DataReaders and can also be accessed by the user through the DDS API.” “RTPS maps each built-in DDS DataWriter or DataReader to an associated built-in RTPS Endpoint.”

Repo: crates/dcps/src/builtin_subscriber.rs (vier Builtin-DataReader); crates/discovery/src/spdp.rs; crates/discovery/src/sedp/stack.rs

Tests: crates/dcps/tests/builtin_topic_readers.rs::builtin_subscriber_has_all_four_readers_pre_created, crates/dcps/src/builtin_subscriber.rs::tests::sinks_push_topic_lands_in_reader

Status: done

§8.5.3.1 SPDP-Builtin-Endpunkte

Spec: §8.5.3.1, S. 125 — “For each Participant, the SPDP creates two RTPS built-in Endpoints: the SPDPbuiltinParticipantWriter and the SPDPbuiltinParticipantReader.”

Repo: crates/discovery/src/spdp.rs (SpdpBeacon, SpdpReader); crates/dcps/src/runtime.rs (DcpsRuntime::spdp_beacon)

Tests: crates/discovery/src/spdp.rs::tests::beacon_serializes_to_decodable_datagram, crates/dcps/src/runtime.rs::tests::two_runtimes_discover_each_other_via_spdp

Status: done

§8.5.3.1 SPDPbuiltinParticipantWriter: Best-Effort-StatelessWriter

Spec: §8.5.3.1, S. 125 — “The SPDPbuiltinParticipantWriter is an RTPS Best-Effort StatelessWriter.”

Repo: crates/discovery/src/spdp.rs (SpdpBeacon::serialize: DATA ohne HEARTBEAT, ohne Zustand je Empfänger)

Tests: crates/discovery/src/spdp.rs::tests::beacon_uses_spdp_builtin_writer_id, crates/discovery/src/spdp.rs::tests::beacon_serializes_to_decodable_datagram

Status: done

§8.5.3.1 Ein Datenobjekt im HistoryCache, bei Änderung ersetzt

Spec: §8.5.3.1, S. 125 — “The HistoryCache of the SPDPbuiltinParticipantWriter contains a single data-object of type SPDPdiscoveredParticipantData. The value of this data-object is set from the attributes in the Participant. If the attributes change, the data-object is replaced.”

Repo: crates/discovery/src/spdp.rs (SpdpBeacon::data); crates/dcps/src/runtime.rs (Beacon-Aktualisierung bei geänderter USER_DATA)

Tests: crates/dcps/tests/set_qos_after_enable.rs::a_user_data_change_reaches_the_peers_builtin_reader

Status: done

§8.5.3.1 Periodisches Senden derselben Änderung

Spec: §8.5.3.1, S. 125 — “This is achieved by periodically calling StatelessWriter::unsent_changes_reset, which causes the StatelessWriter to resend all changes present in its HistoryCache to all locators.”

Repo: crates/discovery/src/spdp.rs (SpdpBeacon::serialize, set_new_sn_each_period); crates/dcps/src/runtime.rs (RuntimeConfig::spdp_new_sequence_per_period)

Tests: crates/discovery/src/spdp.rs::tests::the_resent_beacon_keeps_its_sequence_number_until_the_data_changes, crates/discovery/src/spdp.rs::tests::beacon_increments_sequence_number

Status: done — die periodische Ankündigung wiederholt die eine Änderung mit ihrer Sequenznummer; eine Änderung der Teilnehmerdaten ist eine neue Änderung. Die Form von Cyclone DDS und OpenDDS (neue Nummer je Periode, gemessen in tools/wire-capture/rtps-sessions) ist die Einstellung discovery.spdp_new_sequence_per_period. Nicht gemessen: ob ein Cyclone- oder OpenDDS-Reader den Teilnehmer bei wiederholter Nummer am Leben hält.

§8.5.3.1 Periode: Vorgabe nach PSM, kleiner als leaseDuration

Spec: §8.5.3.1, S. 125 — “The periodic rate at which the SPDPbuiltinParticipantWriter sends out the SPDPdiscoveredParticipantData defaults to a PSM specified value. This period should be smaller than the leaseDuration specified in the SPDPdiscoveredParticipantData”.

Repo: crates/dcps/src/runtime.rs (default_spdp_period_for, DEFAULT_SPDP_PERIOD, Schlüssel discovery.spdp_period_ms)

Tests: crates/dcps/src/runtime.rs::tests::a_short_lease_without_a_period_beacons_three_times_a_lease, crates/dcps/tests/runtime_config_layering.rs::the_protocol_timing_parameters_are_settings

Status: done — die Vorgabe ist die der PSM, 30 s; bei einer Lease unter 90 s höchstens ein Drittel der Lease, damit die Periode kleiner als leaseDuration bleibt.

§8.5.3.1 Vorkonfigurierte Unicast- und Multicast-Locatoren

Spec: §8.5.3.1, S. 125 — “The pre-configured list of locators may include both unicast and multicast locators. Port numbers are defined by each PSM.”

Repo: crates/dcps/src/runtime.rs (send_spdp_multicast, send_spdp_unicast, expand_initial_peer)

Tests: crates/dcps/src/runtime.rs::tests::multicast_free_discovery_via_initial_peers, crates/dcps/src/runtime.rs::tests::expand_initial_peer_ip_only_yields_well_known_port_range

Status: done

§8.5.3.1 SPDPbuiltinParticipantReader und Wahl des EDP

Spec: §8.5.3.1, S. 125 — “The contained information includes what Endpoint Discovery Protocols the remote Participant supports. The proper Endpoint Discovery Protocol is then used for exchanging Endpoint information with the remote Participant.”

Repo: crates/discovery/src/sedp/stack.rs (on_participant_discovered: nach builtin_endpoint_set)

Tests: crates/discovery/src/sedp/stack.rs::tests::discovered_participant_wires_all_four_endpoints_when_present, crates/discovery/src/sedp/stack.rs::tests::partial_endpoint_set_wires_only_matching_sides

Status: done

§8.5.3.1 Optional: Ankündigung an einen bisher unbekannten Teilnehmer

Spec: §8.5.3.1, S. 125 — “Implementations can minimize any start-up delays by sending an additional SPDPdiscoveredParticipantData in response to receiving this data-object from a previously unknown Participant, but this behavior is optional.”

Repo: crates/dcps/src/runtime.rs (directed_spdp_targets, SpdpResponseTargets)

Tests: crates/dcps/src/runtime.rs::tests::the_spdp_response_axis_decides_the_targets, crates/rtps/src/dialect.rs::tests::the_spdp_response_default_answers_the_beacon_source

Status: done

§8.5.3.1 Optional: Locatorliste um entdeckte Teilnehmer erweitern

Spec: §8.5.3.1, S. 125 — “Implementations may also enable the user to choose whether to automatically extend the pre-configured list of locators with new locators from newly discovered Participants. … These last two features are optional and not required for the purpose of interoperability.”

Repo: crates/dcps/src/runtime.rs (send_spdp_unicast: periodische Ankündigung auch an die Metatraffic-Locatoren entdeckter Teilnehmer)

Tests: crates/dcps/src/runtime.rs::tests::an_initial_peer_a_discovered_participant_covers_is_left_to_the_fan_out

Status: done — die Erweiterung ist nicht abschaltbar.

§8.5.3.2 Figure 8.27 SPDPdiscoveredParticipantData

Spec: §8.5.3.2, S. 125 — “the SPDPdiscoveredParticipantData specializes the ParticipantProxy and therefore includes all the information necessary to configure a discovered Participant. The SPDPdiscoveredParticipantData also specializes the DDS-defined DDS::ParticipantBuiltinTopicData”.

Repo: crates/rtps/src/participant_data.rs (ParticipantBuiltinTopicData: Attribute des ParticipantProxy, user_data, lease_duration, manual_liveliness_count, builtin_endpoint_qos)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full, crates/rtps/src/participant_data.rs::tests::manual_liveliness_count_and_builtin_endpoint_qos_go_out_and_read_back

Status: done

§8.5.3.2 Table 8.78 domainId

Spec: §8.5.3.2, S. 126, Table 8.78 — “domainId: DomainId_t — Identifies the DDS domainId of the associated DDS DomainParticipant.”

Repo: crates/rtps/src/participant_data.rs (domain_id, PID_DOMAIN_ID); crates/dcps/src/runtime.rs (Beacon mit domain_id: Some(domain_id))

Tests: crates/dcps/src/runtime.rs::tests::a_participant_of_another_domain_id_is_not_discovered, crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§8.5.3.2 Table 8.78 domainTag

Spec: §8.5.3.2, S. 126, Table 8.78 — “domainTag: string — Identifies the DDS domainTag of the associated DDS DomainParticipant.”

Repo: crates/rtps/src/participant_data.rs (domain_tag, PID_DOMAIN_TAG)

Tests: crates/rtps/src/participant_data.rs::tests::domain_tag_goes_out_when_set_and_reads_back, crates/dcps/src/runtime.rs::tests::a_participant_of_another_domain_tag_is_not_discovered

Status: done

§8.5.3.2 Table 8.78 protocolVersion

Spec: §8.5.3.2, S. 126, Table 8.78 — “protocolVersion: ProtocolVersion_t — Identifies the RTPS protocol version used by the Participant.”

Repo: crates/rtps/src/participant_data.rs (protocol_version, PID_PROTOCOL_VERSION)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§8.5.3.2 Table 8.78 guidPrefix

Spec: §8.5.3.2, S. 126, Table 8.78 — “guidPrefix: GuidPrefix_t — The common GuidPrefix_t of the Participant and all the Endpoints contained within the Participant.”

Repo: crates/rtps/src/participant_data.rs (guid, PID_PARTICIPANT_GUID)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_decode_requires_guid_pid, crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§8.5.3.2 Table 8.78 vendorId

Spec: §8.5.3.2, S. 126, Table 8.78 — “vendorId: VendorId_t — Identifies the vendor of the DDS middleware that contains the Participant.”

Repo: crates/rtps/src/participant_data.rs (vendor_id, PID_VENDOR_ID)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: partial — ZeroDDS sendet 0x01F0, keinen von der OMG zugewiesenen Wert (blocked-Item unter §8.3.5.2).

§8.5.3.2 Table 8.78 expectsInlineQos

Spec: §8.5.3.2, S. 126, Table 8.78 — “expectsInlineQos: bool — Describes whether the Readers within the Participant expect that the QoS values that apply to each data modification are encapsulated included with each Data.”

Repo: crates/rtps/src/participant_data.rs (expects_inline_qos, PID_EXPECTS_INLINE_QOS)

Tests: crates/rtps/src/participant_data.rs::tests::expects_inline_qos_goes_out_when_set_and_reads_back

Status: done

§8.5.3.2 Table 8.78 metatrafficUnicastLocatorList

Spec: §8.5.3.2, S. 126, Table 8.78 — “List of unicast locators (transport, address, port combinations) that can be used to send messages to the built-in Endpoints contained in the Participant.”

Repo: crates/rtps/src/participant_data.rs (metatraffic_unicast_locators, PID_METATRAFFIC_UNICAST_LOCATOR)

Tests: crates/rtps/src/participant_data.rs::tests::decode_retains_all_repeated_unicast_locators_in_order_le_and_be, crates/dcps/src/runtime.rs::tests::wlp_unicast_targets_prefers_metatraffic_then_default

Status: done

§8.5.3.2 Table 8.78 metatrafficMulticastLocatorList

Spec: §8.5.3.2, S. 126, Table 8.78 — “List of multicast locators (transport, address, port combinations) that can be used to send messages to the built-in Endpoints contained in the Participant.”

Repo: crates/rtps/src/participant_data.rs (metatraffic_multicast_locators, PID_METATRAFFIC_MULTICAST_LOCATOR)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full, crates/rtps/src/participant_data.rs::tests::decode_zero_locators_yields_empty_lists

Status: done

§8.5.3.2 Table 8.78 defaultUnicastLocatorList

Spec: §8.5.3.2, S. 127, Table 8.78 — “defaultUnicastLocatorList: Locator_t[1..*] … These are the unicast locators that will be used in case the Endpoint does not specify its own set of Locators, so at least one Locator must be present.”

Repo: crates/rtps/src/participant_data.rs (default_unicast_locators); crates/dcps/src/runtime.rs (announce_locators: nie leer)

Tests: crates/dcps/src/runtime.rs::tests::announce_locators_automatic_is_non_empty_and_includes_probe, crates/rtps/src/participant_data.rs::tests::encode_dedups_exact_duplicate_locators

Status: done

§8.5.3.2 Table 8.78 defaultMulticastLocatorList

Spec: §8.5.3.2, S. 127, Table 8.78 — “Default list of multicast locators … These are the multicast locators that will be used in case the Endpoint does not specify its own set of Locators.”

Repo: crates/rtps/src/participant_data.rs (default_multicast_locators, PID_DEFAULT_MULTICAST_LOCATOR)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done — ZeroDDS kündigt keinen Default-Multicast-Locator an.

§8.5.3.2 Table 8.78 availableBuiltinEndpoints

Spec: §8.5.3.2, S. 127, Table 8.78 — “All Participants must support the SEDP. This attribute identifies the kinds of built-in SEDP Endpoints that are available in the Participant.”

Repo: crates/rtps/src/participant_data.rs (builtin_endpoint_set, endpoint_flag); crates/dcps/src/runtime.rs (ALL_STANDARD plus TOPICS_ANNOUNCER/TOPICS_DETECTOR)

Tests: crates/rtps/src/participant_data.rs::tests::endpoint_flag_bit_positions_match_spec, crates/dcps/src/runtime.rs::tests::spdp_announces_standard_bits_by_default

Status: done

§8.5.3.2 Table 8.78 leaseDuration

Spec: §8.5.3.2, S. 127, Table 8.78 — “How long a Participant should be considered alive every time an announcement is received from the Participant. If a Participant fails to send another announcement within this time period, the Participant can be considered gone.”

Repo: crates/rtps/src/participant_data.rs (lease_duration, PID_PARTICIPANT_LEASE_DURATION); crates/discovery/src/spdp.rs (DiscoveredParticipantsCache::drain_expired)

Tests: crates/rtps/src/participant_data.rs::tests::to_pl_cdr_be_is_big_endian_roundtrips_and_omits_credential_tokens

Status: done

§8.5.3.2 Table 8.78 manualLivelinessCount

Spec: §8.5.3.2, S. 127, Table 8.78 — “manualLivelinessCount: Count_t — Used to implement MANUAL_BY_PARTICIPANT liveliness QoS. When liveliness is asserted, the manualLivelinessCount is incremented and a new SPDPdiscoveredParticipantData is sent.”

Repo: crates/rtps/src/participant_data.rs (manual_liveliness_count); crates/dcps/src/runtime.rs (bump_manual_liveliness_count, spdp_announced); crates/dcps/src/wlp.rs (take_manual_participant_written)

Tests: crates/rtps/src/participant_data.rs::tests::manual_liveliness_count_and_builtin_endpoint_qos_go_out_and_read_back, crates/dcps/src/runtime.rs::tests::the_manual_liveliness_count_of_the_announcement_counts_up, crates/dcps/src/runtime.rs::tests::a_changed_manual_liveliness_count_renews_the_manual_writers_of_that_participant, crates/dcps/src/wlp.rs::tests::a_written_manual_sample_is_reported_once

Status: done — wird eine MANUAL_BY_PARTICIPANT-Probe geschrieben, steigt der Zähler (höchstens einmal je Tick) und eine neue Ankündigung geht hinaus; ein Empfänger, bei dem sich der Zähler eines bekannten Teilnehmers ändert, wertet das als manuelle Liveliness-Zusicherung dieses Teilnehmers (Test: n, n + 1 erneuert die MANUAL_BY_PARTICIPANT-Writer des Teilnehmers am Reader).

§8.5.3.2 Table 8.78 builtinEndpointQos

Spec: §8.5.3.2, S. 127, Table 8.78 — “builtinEndpointQos: BuiltinEndpointQos_t — Provides additional information on the QoS of the built-in Endpoints supported by the Participant.”

Repo: crates/rtps/src/participant_data.rs (builtin_endpoint_qos); crates/dcps/src/wlp.rs (WlpEndpoint::add_peer_reader)

Tests: crates/rtps/src/participant_data.rs::tests::manual_liveliness_count_and_builtin_endpoint_qos_go_out_and_read_back, crates/dcps/src/wlp.rs::tests::the_reader_is_treated_as_builtin_endpoint_qos_says

Status: done — das Feld wird gelesen und geschrieben; der WLP-Writer behandelt den Reader danach (§8.4.13.3). ZeroDDS selbst kündigt keines an: sein Reader ist RELIABLE.

§8.5.3.2 Weitere EDP über die Erweiterungsmechanismen

Spec: §8.5.3.2, S. 127 — “There are currently no other Endpoint Discovery Protocols defined by the RTPS specification. In order to extend SPDPdiscoveredParticipantData to include additional EDPs, the standard RTPS extension mechanisms can be used.”

Repo: —

Tests: —

Status: n/a (informative) — keine Anforderung.

§8.5.3.2.1 availableBuiltinEndpoints: ankündbare Endpunkte

Spec: §8.5.3.2, S. 127 — “The builtin endpoints that may be announced in the availableBuiltinEndpoints include: PUBLICATIONS_DETECTOR, PUBLICATIONS_ANNOUNCER, SUBSCRIPTIONS_DETECTOR, SUBSCRIPTIONS_ANNOUNCER, TOPICS_DETECTOR, TOPICS_ANNOUNCER, PARTICIPANT_MESSAGE_READER, and PARTICIPANT_MESSAGE_WRITER. The availableBuiltinEndpoints may also announce builtin endpoints defined in other DDS specifications.”

Repo: crates/rtps/src/participant_data.rs (endpoint_flag, ALL_STANDARD, ALL_SECURE)

Tests: crates/rtps/src/participant_data.rs::tests::endpoint_flag_roundtrip_through_pl_cdr, crates/dcps/src/runtime.rs::tests::spdp_announces_secure_bits_when_configured, crates/dcps/tests/type_lookup_e2e.rs::announces_type_lookup_endpoints_in_spdp

Status: done

§8.5.3.3 EntityIds der SPDP-Endpunkte

Spec: §8.5.3.3, S. 128 — “The Protocol reserves the following values of the EntityId_t for the SPDP built-in Endpoints: ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER”

Repo: crates/rtps/src/wire_types.rs (EntityId::SPDP_BUILTIN_PARTICIPANT_WRITER, EntityId::SPDP_BUILTIN_PARTICIPANT_READER)

Tests: crates/rtps/src/wire_types.rs::tests::spdp_builtin_participant_writer_layout, crates/rtps/src/wire_types.rs::tests::spdp_builtin_participant_reader_layout

Status: done

§8.5.3.3 Table 8.79 SPDP-Writer unicastLocatorList

Spec: §8.5.3.3, S. 128, Table 8.79 — “unicastLocatorList: Transport-kinds and addresses are either auto-detected or configured by the application. Ports are a parameter to the SPDP initialization or else are set to a PSM-specified value that depends on the domainId.”

Repo: crates/dcps/src/runtime.rs (announce_locators, spdp_unicast_port)

Tests: crates/dcps/src/runtime.rs::tests::spdp_unicast_port_follows_rtps_formula, crates/dcps/src/runtime.rs::tests::announce_locators_pins_to_single_interface

Status: done

§8.5.3.3 Table 8.79 SPDP-Writer multicastLocatorList

Spec: §8.5.3.3, S. 128, Table 8.79 — “multicastLocatorList: Defaults to a PSM-specified value.”

Repo: crates/rtps/src/wire_types.rs (spdp_multicast_port, Gruppe 239.255.0.1); crates/dcps/src/runtime.rs (spdp_multicast_group)

Tests: crates/rtps/src/wire_types.rs::tests::spdp_default_multicast_is_239_255_0_1, crates/rtps/src/wire_types.rs::tests::spdp_multicast_port_domain_0_is_7400

Status: done

§8.5.3.3 Table 8.79 SPDP-Writer reliabilityLevel

Spec: §8.5.3.3, S. 128, Table 8.79 — “reliabilityLevel: BEST_EFFORT”.

Repo: crates/discovery/src/spdp.rs (SpdpBeacon)

Tests: crates/discovery/src/spdp.rs::tests::beacon_serializes_to_decodable_datagram

Status: done

§8.5.3.3 Table 8.79 SPDP-Writer topicKind

Spec: §8.5.3.3, S. 128, Table 8.79 — “topicKind: WITH_KEY”.

Repo: crates/rtps/src/wire_types.rs (EntityId::SPDP_BUILTIN_PARTICIPANT_WRITER: BuiltinWriterWithKey)

Tests: crates/rtps/src/wire_types.rs::tests::spdp_builtin_participant_writer_layout

Status: done

§8.5.3.3 Table 8.79 SPDP-Writer resendPeriod

Spec: §8.5.3.3, S. 128, Table 8.79 — “resendPeriod: Defaults to a PSM-specified value.”

Repo: crates/dcps/src/runtime.rs (RuntimeConfig::spdp_period, ZERODDS_SPDP_PERIOD_MS)

Tests: crates/dcps/src/runtime.rs::tests::a_short_lease_without_a_period_beacons_three_times_a_lease, crates/dcps/tests/runtime_config_layering.rs::the_protocol_timing_parameters_are_settings

Status: done — einstellbar (discovery.spdp_period_ms); die Vorgabe ist 30 s, die PSM-Vorgabe.

§8.5.3.3 Table 8.79 SPDP-Writer readerLocators

Spec: §8.5.3.3, S. 128, Table 8.79 — “readerLocators: ”.

Repo: crates/dcps/src/runtime.rs (RuntimeConfig::initial_peers, expand_initial_peer, Multicast-Ziel)

Tests: crates/dcps/src/runtime.rs::tests::initial_peer_specs_reach_the_runtime_without_touching_the_environment, crates/dcps/src/runtime.rs::tests::initial_peer_specs_expand_per_the_configured_participant_limit

Status: done

§8.5.3.3 Table 8.80 SPDP-Reader unicastLocatorList

Spec: §8.5.3.3, S. 129, Table 8.80 — “unicastLocatorList: … Ports are a parameter to the SPDP initialization or else are set to a PSM-specified value that depends on the domainId.”

Repo: crates/dcps/src/runtime.rs (spdp_unicast-Socket auf spdp_unicast_port)

Tests: crates/dcps/src/runtime.rs::tests::spdp_unicast_port_follows_rtps_formula

Status: done

§8.5.3.3 Table 8.80 SPDP-Reader multicastLocatorList

Spec: §8.5.3.3, S. 129, Table 8.80 — “multicastLocatorList: . Defaults to a PSM-specified value.”

Repo: crates/dcps/src/runtime.rs (spdp_multicast_rx, spdp_multicast_group)

Tests: crates/dcps/src/runtime.rs::tests::start_refuses_spdp_group_outside_allowlist, crates/discovery/tests/spdp_loopback_e2e.rs::loopback_multicast_self_discovery

Status: done

§8.5.3.3 Table 8.80 SPDP-Reader reliabilityLevel

Spec: §8.5.3.3, S. 129, Table 8.80 — “reliabilityLevel: BEST_EFFORT”.

Repo: crates/discovery/src/spdp.rs (SpdpReader: zustandslos, ohne ACKNACK)

Tests: crates/discovery/src/spdp.rs::tests::samples_reads_every_participant_a_datagram_bundles

Status: done

§8.5.3.3 Table 8.80 SPDP-Reader topicKind

Spec: §8.5.3.3, S. 129, Table 8.80 — “topicKind: WITH_KEY”.

Repo: crates/rtps/src/wire_types.rs (EntityId::SPDP_BUILTIN_PARTICIPANT_READER: BuiltinReaderWithKey)

Tests: crates/rtps/src/wire_types.rs::tests::spdp_builtin_participant_reader_layout

Status: done

§8.5.3.3 SPDP-Reader: HistoryCache nach Teilnehmer-GUID

Spec: §8.5.3.3, S. 129 — “The HistoryCache of the SPDPbuiltinParticipantReader contains information on all active discovered participants; the key used to identify each data-object corresponds to the Participant GUID.” “If an entry with a matching key is not there, a new entry is added keyed by the GUID of the Participant.”

Repo: crates/discovery/src/spdp.rs (DiscoveredParticipantsCache: Schlüssel data.guid.prefix)

Tests: crates/discovery/src/spdp.rs::tests::cache_insert_returns_true_for_new_participant, crates/discovery/src/spdp.rs::tests::cache_get_returns_inserted_participant

Status: done

§8.5.3.3 SPDP-Reader: veraltete Einträge entfernen

Spec: §8.5.3.3, S. 129 — “Periodically, the SPDP examines the SPDPbuiltinParticipantReader HistoryCache looking for stale entries defined as those that have not been refreshed for a period longer than their specified leaseDuration. Stale entries are removed.”

Repo: crates/discovery/src/spdp.rs (DiscoveredParticipantsCache::drain_expired); crates/dcps/src/runtime.rs (Aufruf je Tick)

Tests: crates/discovery/src/spdp.rs::tests::participant_lease_lifecycle_observation_and_infinite, crates/dcps/src/runtime.rs::tests::participant_lease_lifecycle_hard_death_and_same_prefix

Status: done — drain_expired entfernt schon bei Gleichheit von verstrichener Zeit und leaseDuration.

§8.5.3.4 Table 8.81 SPDP_WELL_KNOWN_UNICAST_PORT

Spec: §8.5.3.4, S. 129, Table 8.81 — “SPDP_WELL_KNOWN_UNICAST_PORT — entries in SPDPbuiltinParticipantReader.unicastLocatorList, unicast entries in SPDPbuiltinParticipantWriter.readerLocators”.

Repo: crates/rtps/src/wire_types.rs (spdp_unicast_port); crates/dcps/src/runtime.rs (expand_initial_peer)

Tests: crates/dcps/src/runtime.rs::tests::spdp_unicast_port_follows_rtps_formula, crates/dcps/src/runtime.rs::tests::expand_initial_peer_ip_only_yields_well_known_port_range

Status: done

§8.5.3.4 Table 8.81 SPDP_WELL_KNOWN_MULTICAST_PORT

Spec: §8.5.3.4, S. 129, Table 8.81 — “SPDP_WELL_KNOWN_MULTICAST_PORT — entries in SPDPbuiltinParticipantReader.multicastLocatorList, multicast entries in SPDPbuiltinParticipantWriter.readerLocators”.

Repo: crates/rtps/src/wire_types.rs (spdp_multicast_port)

Tests: crates/rtps/src/wire_types.rs::tests::spdp_multicast_port_domain_1_is_7650, crates/rtps/src/wire_types.rs::tests::spdp_multicast_port_domain_5_is_8650

Status: done

§8.5.4.1 Assoziation mit den SEDP-Endpunkten eines entdeckten Teilnehmers

Spec: §8.5.4.1, S. 130 — “once a Participant knows of the presence of another Participant, it can assume the presence of the built-in Endpoints made available by the remote participant and establish the association with the locally-matching built-in Endpoints.”

Repo: crates/discovery/src/sedp/stack.rs (on_participant_discovered)

Tests: crates/discovery/src/sedp/stack.rs::tests::discovered_participant_wires_all_four_endpoints_when_present, crates/discovery/src/sedp/stack.rs::tests::self_discovery_is_ignored

Status: done

§8.5.4.1 SEDP: dasselbe Protokoll wie für Anwendungs-Endpunkte

Spec: §8.5.4.1, S. 130 — “The protocol used to communicate between built-in Endpoints is the same as used for application-defined Endpoints.”

Repo: crates/discovery/src/sedp/writer.rs (make_sedp_writer: ReliableWriter); crates/discovery/src/sedp/reader.rs (ReliableReader)

Tests: crates/discovery/src/sedp/stack.rs::tests::end_to_end_discovery_between_two_stacks, crates/discovery/src/sedp/stack.rs::tests::a_heartbeat_past_a_hole_releases_the_buffered_subscription

Status: done

§8.5.4.2 SEDP-Endpunkte zuverlässig

Spec: §8.5.4.2, S. 130 — “The SEDP therefore maps each corresponding built-in DDS DataWriter or DataReader into corresponding reliable RTPS Writer and Reader Endpoints.” “it is sufficient that an implementation provides the required built-in Endpoints and reliable communication that satisfies the general requirements listed in 8.4.2.”

Repo: crates/discovery/src/sedp/writer.rs (make_sedp_writer); crates/discovery/src/sedp/reader.rs

Tests: crates/discovery/src/sedp/stack.rs::tests::a_heartbeat_past_a_hole_releases_the_buffered_subscription, crates/discovery/tests/cyclone_sedp_replay.rs::cyclone_sedp_publication_fixture_flows_through_stack

Status: done — die Abweichungen der zuverlässigen Writer und Reader von §8.4.2 sind dort geführt.

§8.5.4.2 EntityIds der SEDP-Endpunkte

Spec: §8.5.4.2, S. 130–131 — “The RTPS Protocol reserves the following values of the EntityId_t for the built-in Endpoints: ENTITYID_SEDP_BUILTIN_PUBLICATIONS_ANNOUNCER … ENTITYID_SEDP_BUILTIN_TOPICS_DETECTOR”

Repo: crates/rtps/src/wire_types.rs (EntityId::SEDP_BUILTIN_PUBLICATIONS_WRITER, EntityId::SEDP_BUILTIN_SUBSCRIPTIONS_READER und die übrigen)

Tests: crates/rtps/src/wire_types.rs::tests::sedp_publications_writer_layout, crates/rtps/src/wire_types.rs::tests::sedp_subscriptions_reader_layout

Status: done — die Werte sind unter §9.3.1.3 geführt.

§8.5.4.3 Topics-Endpunkte optional

Spec: §8.5.4.3, S. 131 — “it is not required to implement the SEDPbuiltinTopicsReader and SEDPbuiltinTopicsWriter built-in Endpoints and for the purpose of interoperability, implementations should not rely on their presence in remote Participants.”

Repo: crates/discovery/src/sedp/stack.rs (on_participant_discovered: Topics-Proxies nur bei gesetzten Bits)

Tests: crates/discovery/src/sedp/stack.rs::tests::the_topics_bits_wire_the_topics_writer_and_reader, crates/discovery/src/sedp/stack.rs::tests::partial_endpoint_set_wires_only_matching_sides

Status: done

§8.5.4.3 Nur die benötigten Builtin-Endpunkte

Spec: §8.5.4.3, S. 131 — “a Participant is only required to provide the built-in Endpoints required for matching up local and remote Endpoints.”

Repo: —

Tests: —

Status: n/a (informative) — keine Anforderung; ZeroDDS stellt alle SEDP-Endpunkte bereit.

§8.5.4.4 Figure 8.30 DiscoveredWriterData

Spec: §8.5.4.4, S. 131 — “DiscoveredWriterData extends DDS::PublicationBuiltinTopicData” “the “Discovered” DataTypes also include all the information that may be needed by an implementation of the protocol to configure the RTPS Endpoints. This information is contained in the RTPS ReaderProxy and WriterProxy.”

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData: QoS, key, unicast_locators, multicast_locators, group_guid, data_max_size_serialized)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies, crates/discovery/tests/vendor_discovery_frames.rs::cyclone_announcements_read_and_write_back, crates/rtps/src/publication_data.rs::tests::the_max_payload_size_and_the_name_of_a_writer_travel, crates/rtps/src/publication_data.rs::tests::the_writers_group_travels_as_pid_group_guid

Status: done — die Attribute des WriterProxy stehen in der Ankündigung: Writer-GUID, beide Locator-Listen, dataMaxSizeSerialized (PID_TYPE_MAX_SIZE_SERIALIZED) und die Gruppe (PID_GROUP_GUID, daraus remoteGroupEntityId).

§8.5.4.4 Figure 8.30 DiscoveredReaderData

Spec: §8.5.4.4, S. 131 — “DiscoveredReaderData extends the DDS-defined DDS::SubscriptionBuiltinTopicData”.

Repo: crates/rtps/src/subscription_data.rs (SubscriptionBuiltinTopicData: QoS, key, unicast_locators, multicast_locators, expects_inline_qos, content_filter)

Tests: crates/rtps/src/publication_data.rs::tests::the_writers_group_travels_as_pid_group_guid

Status: done

§8.5.4.4 Figure 8.30 DiscoveredTopicData

Spec: §8.5.4.4, S. 131 — “DiscoveredTopicData extends DDS::TopicBuiltinTopicData.”

Repo: crates/rtps/src/topic_data.rs (TopicBuiltinTopicData)

Tests: crates/discovery/src/sedp/stack.rs::tests::two_stacks_exchange_a_topic_its_new_qos_and_its_dispose, crates/discovery/src/sedp/stack.rs::tests::a_cyclone_topic_and_its_dispose_are_read_by_cyclones_own_key

Status: done

§8.5.4.4 Fehlende Angaben: Vorgaben der PSM

Spec: §8.5.4.4, S. 132 — “An implementation of the protocol need not necessarily send all information contained in the DataTypes. If any information is not present, the implementation can assume the default values, as defined by the PSM.”

Repo: crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs (Vorgabe je fehlendem PID)

Tests: crates/rtps/src/publication_data.rs::tests::an_absent_reliability_parameter_reads_as_reliable_on_a_publication, crates/rtps/src/publication_data.rs::tests::participant_key_fallback_when_pid_missing

Status: done — die Vorgabe je PID ist unter §9.6.3.2 geführt.

§8.5.4.4 Table 8.82 Publications: DataType

Spec: §8.5.4.4, S. 133, Table 8.82 — “DataType: DiscoveredWriterData”.

Repo: crates/discovery/src/sedp/writer.rs (SedpPublicationsWriter::announce: PublicationBuiltinTopicData::to_pl_cdr_le)

Tests: crates/discovery/tests/sedp_loopback.rs::publication_announce_then_reader_fills_cache

Status: done

§8.5.4.4 Table 8.82 Publications: Cardinality

Spec: §8.5.4.4, S. 133, Table 8.82 — “Cardinality: The number of DataWriters contained by the DomainParticipant. There is a one-to-one correspondence between each DataWriter in the participant and a data-object that describes the DataWriter stored in the WriterHistoryCache for the SEDPbuiltinPublicationsWriter.”

Repo: crates/discovery/src/sedp/writer.rs (make_sedp_writer: eine Änderung je Instanz, SEDP_MAX_CHANGES; SedpPublicationsWriter::announce mit der Endpunkt-GUID als Schlüssel)

Tests: crates/discovery/src/sedp/writer.rs::tests::every_endpoint_keeps_one_change_for_a_reader_that_matches_later

Status: done

§8.5.4.4 Table 8.82 Publications: Einfügen

Spec: §8.5.4.4, S. 133, Table 8.82 — “Data-Object insertion: Each time a DataWriter is created in the DomainParticipant.”

Repo: crates/dcps/src/runtime.rs (announce_publication beim Anlegen des Writers)

Tests: crates/dcps/tests/builtin_topic_readers.rs::linux_e2e::sedp_pub_sub_populates_dcps_publication_and_subscription_readers

Status: done

§8.5.4.4 Table 8.82 Publications: Ändern

Spec: §8.5.4.4, S. 133, Table 8.82 — “Data-Object modification: Each time the QoS of an existing DataWriter is modified.”

Repo: crates/dcps/src/runtime.rs (reannounce_publication)

Tests: crates/dcps/tests/set_qos_after_enable.rs::a_topic_data_change_reaches_the_writers_announcement, crates/dcps/src/runtime.rs::tests::a_partition_change_unmatches_without_a_status_and_is_announced

Status: done

§8.5.4.4 Table 8.82 Publications: Löschen

Spec: §8.5.4.4, S. 133, Table 8.82 — “Data-Object deletion: Each time an existing DataWriter belonging to the DomainParticipant is deleted.”

Repo: crates/discovery/src/sedp/writer.rs (SedpPublicationsWriter::dispose); crates/dcps/src/runtime.rs (dispose_publication beim Löschen)

Tests: crates/dcps/tests/endpoint_delete_unmatch_e2e.rs::linux_e2e::dropping_a_writer_unmatches_the_remote_reader

Status: done

§8.5.4.4 Table 8.83 Subscriptions: DataType

Spec: §8.5.4.4, S. 134, Table 8.83 — “DataType: DiscoveredReaderData”.

Repo: crates/discovery/src/sedp/writer.rs (SedpSubscriptionsWriter::announce)

Tests: crates/discovery/tests/sedp_loopback.rs::subscription_announce_then_reader_fills_cache

Status: done

§8.5.4.4 Table 8.83 Subscriptions: Cardinality

Spec: §8.5.4.4, S. 134, Table 8.83 — “Cardinality: The number of DataReaders contained by the DomainParticipant. There is a one-to-one correspondence between each DataReaders in the Participant and a data-object that describes the DataReaders stored in the WriterHistoryCache for the SEDPbuiltinSubscriptionsWriter.”

Repo: —

Tests: crates/discovery/src/sedp/writer.rs::tests::every_endpoint_keeps_one_change_for_a_reader_that_matches_later

Status: done — derselbe Writer-Aufbau (make_sedp_writer) wie unter Table 8.82 Cardinality, Ankündigung mit der GUID als Schlüssel.

§8.5.4.4 Table 8.83 Subscriptions: Einfügen

Spec: §8.5.4.4, S. 134, Table 8.83 — “Data-Object insertion: Each time a DataReader is created in the DomainParticipant.”

Repo: crates/dcps/src/runtime.rs (announce_subscription beim Anlegen des Readers)

Tests: crates/dcps/tests/builtin_topic_readers.rs::linux_e2e::sedp_pub_sub_populates_dcps_publication_and_subscription_readers

Status: done

§8.5.4.4 Table 8.83 Subscriptions: Ändern

Spec: §8.5.4.4, S. 134, Table 8.83 — “Data-Object modification: Each time the QoS of an existing DataReader is modified.”

Repo: crates/dcps/src/runtime.rs (announce_subscription nach set_qos)

Tests: crates/dcps/tests/set_qos_after_enable.rs::a_reader_deadline_change_makes_the_pair_incompatible, crates/dcps/src/runtime.rs::tests::the_content_filter_travels_in_the_subscription_and_is_reannounced

Status: done

§8.5.4.4 Table 8.83 Subscriptions: Löschen

Spec: §8.5.4.4, S. 134, Table 8.83 — “Data-Object deletion: Each time an existing DataReader belonging to the DomainParticipant is deleted.”

Repo: crates/discovery/src/sedp/writer.rs (SedpSubscriptionsWriter::dispose)

Tests: crates/dcps/tests/endpoint_delete_unmatch_e2e.rs::linux_e2e::dropping_a_reader_unmatches_the_remote_writer

Status: done

§8.5.4.4 Table 8.84 Topics: DataType

Spec: §8.5.4.4, S. 134, Table 8.84 — “DataType: DiscoveredTopicData”.

Repo: crates/discovery/src/sedp/writer.rs (SedpTopicsWriter::announce)

Tests: crates/discovery/src/sedp/stack.rs::tests::two_stacks_exchange_a_topic_its_new_qos_and_its_dispose

Status: done

§8.5.4.4 Table 8.84 Topics: Cardinality

Spec: §8.5.4.4, S. 134, Table 8.84 — “Cardinality: The number of Topics created by the DomainParticipant. There is a one-to-one correspondence between each Topic created by the DomainParticipant and a data-object that describes the Topic stored in the WriterHistoryCache for the builtinTopicsWriter.”

Repo: —

Tests: crates/discovery/src/sedp/writer.rs::tests::every_endpoint_keeps_one_change_for_a_reader_that_matches_later

Status: done — derselbe Writer-Aufbau (make_sedp_writer) wie unter Table 8.82 Cardinality, Ankündigung mit der GUID als Schlüssel.

§8.5.4.4 Table 8.84 Topics: Einfügen

Spec: §8.5.4.4, S. 134, Table 8.84 — “Data-Object insertion: Each time a Topic is created in the DomainParticipant.”

Repo: crates/dcps/src/participant.rs (announce_topic beim Anlegen bzw. Aktivieren)

Tests: crates/dcps/tests/builtin_topic_readers.rs::linux_e2e::a_created_topic_reaches_dcps_topic_with_every_member_and_its_deletion_disposes_it

Status: done

§8.5.4.4 Table 8.84 Topics: Ändern

Spec: §8.5.4.4, S. 134, Table 8.84 — “Data-Object modification: Each time the QoS of an existing Topic is modified.”

Repo: crates/dcps/src/topic.rs (set_qos → announce_topic)

Tests: crates/discovery/src/sedp/stack.rs::tests::two_stacks_exchange_a_topic_its_new_qos_and_its_dispose

Status: done — der Test prüft den SEDP-Stack, nicht den Aufruf aus Topic::set_qos.

§8.5.4.4 Table 8.84 Topics: Löschen

Spec: §8.5.4.4, S. 134, Table 8.84 — “Data-Object deletion: Each time an existing Topic belonging to the DomainParticipant is deleted.”

Repo: crates/dcps/src/runtime.rs (dispose_local_topic)

Tests: crates/dcps/tests/builtin_topic_readers.rs::linux_e2e::delete_topic_disposes_the_announced_topic_and_a_writer_holds_it

Status: done

§8.5.5 Zusammenspiel mit der virtuellen Maschine

Spec: §8.5.5, S. 134 — “To further illustrate the SPDP and SEDP, this specification describes how the information provided by the SPDP can be used to configure the SEDP built-in Endpoints in the RTPS virtual machine.”

Repo: —

Tests: —

Status: n/a (informative) — Einleitung zu §8.5.5.1 und §8.5.5.2.

§8.5.5.1 Neuer Teilnehmer: domainId vergleichen

Spec: §8.5.5.1, S. 134–135 — “IF ( participant_data.domainId != local_participant.domainId ) THEN RETURN;”

Repo: crates/dcps/src/runtime.rs (spdp_announced: PID_DOMAIN_ID)

Tests: crates/dcps/src/runtime.rs::tests::a_participant_of_another_domain_id_is_not_discovered, crates/dcps/src/runtime.rs::tests::a_beacon_of_another_domain_is_named_once_per_sender

Status: done — ein fehlendes PID_DOMAIN_ID gilt als eigene Domain.

§8.5.5.1 Neuer Teilnehmer: domainTag vergleichen

Spec: §8.5.5.1, S. 135 — “IF ( !STRING_EQUAL(participant_data.domainTag, local_participant.domainTag) ) THEN RETURN;”

Repo: crates/dcps/src/runtime.rs (spdp_announced)

Tests: crates/dcps/src/runtime.rs::tests::a_participant_of_another_domain_tag_is_not_discovered

Status: done

§8.5.5.1 Neuer Teilnehmer: Proxies je angekündigtem Endpunkt

Spec: §8.5.5.1, S. 135–136 — “IF ( PUBLICATIONS_DETECTOR IS_IN participant_data.availableEndpoints ) THEN … writer.matched_reader_add(proxy);” und entsprechend für PUBLICATIONS_ANNOUNCER, SUBSCRIPTIONS_DETECTOR, SUBSCRIPTIONS_ANNOUNCER, TOPICS_DETECTOR, TOPICS_ANNOUNCER.

Repo: crates/discovery/src/sedp/stack.rs (on_participant_discovered)

Tests: crates/discovery/src/sedp/stack.rs::tests::discovered_participant_wires_all_four_endpoints_when_present, crates/discovery/src/sedp/stack.rs::tests::the_topics_bits_wire_the_topics_writer_and_reader, crates/discovery/tests/opensplice_spdp_bundle.rs::the_participant_with_the_detectors_gets_the_local_sedp_writers_proxies

Status: done — die Proxies erhalten die Metatraffic-Unicast-Locatoren (ersatzweise die Default-Unicast-Locatoren), keine Multicast-Locatoren.

§8.5.5.2 Teilnehmer entfernt: Proxies der SEDP-Endpunkte entfernen

Spec: §8.5.5.2, S. 136 — “Based on the remote Participant’s leaseDuration, a local Participant ‘local_participant’ concludes that a previously discovered Participant with GUID_t participant_guid is no longer present. The Participant ‘local_participant’ must reconfigure any local Endpoints that were communicating with Endpoints in the Participant”.

Repo: crates/discovery/src/sedp/stack.rs (on_participant_lost); crates/dcps/src/runtime.rs (Lease-Ablauf und Abmeldung)

Tests: crates/discovery/src/sedp/stack.rs::tests::on_participant_lost_clears_proxies_and_cache, crates/discovery/tests/cyclone_sedp_replay.rs::replay_after_participant_lost_stops_accepting_publications, crates/dcps/src/runtime.rs::tests::participant_lease_lifecycle_hard_death_and_same_prefix

Status: done

§8.5.6 Andere Entdeckungsprotokolle

Spec: §8.5.6, S. 136 — “Remote Participants using a different vendor’s RTPS implementation must be contacted using at least the SPDP to ensure interoperability. There is no such requirement when the remote Participant uses the same RTPS implementation.”

Repo: crates/dcps/src/runtime.rs (SPDP läuft in jedem Teilnehmer; Abkürzung im selben Prozess über inproc_announce_publication)

Tests: crates/dcps/src/runtime.rs::tests::handle_spdp_registers_real_fastdds_participant, crates/discovery/tests/fastdds_spdp_repro.rs::zerodds_parses_real_fastdds_spdp

Status: done

§8.5.6 Gemeinsames EDP

Spec: §8.5.6, S. 137 — “All Participants must support at least the SEDP, so they always have at least one EDP in common. However, if two Participants both support another EDP, this alternative protocol can be used instead.”

Repo: —

Tests: —

Status: n/a (informative) — die Pflicht zu SEDP ist unter §8.5.1 geführt; der Rest ist eine Erlaubnis.

§8.6 Versioning and Extensibility

§8.6 Höhere Minor-Versionen verarbeiten

Spec: §8.6, S. 137 — “Implementations of this version of the RTPS protocol should be able to process RTPS Messages not only with the same major version but possibly higher minor versions.”

Repo: crates/rtps/src/datagram.rs (decode_datagram: nur eine höhere Major-Version wird abgewiesen)

Tests: crates/rtps/src/datagram.rs::tests::decode_accepts_minor_version_above_supported, crates/rtps/src/datagram.rs::tests::decode_rejects_major_version_above_supported

Status: done

§8.6.1 Unbekannte Submessages überspringen

Spec: §8.6.1, S. 137 — “Additional Submessages with other submessageIds can be introduced and used anywhere in an RTPS Message. An implementation should skip over unknown Submessages using the submessageLength field in the SubmessageHeader.”

Repo: crates/rtps/src/datagram.rs (decode_datagram, ParsedSubmessage::Unknown)

Tests: crates/rtps/src/datagram.rs::tests::decode_skips_unknown_submessage_without_must_understand, crates/rtps/src/datagram.rs::tests::decode_skips_an_unknown_submessage_whatever_its_flags

Status: done — eine Submessage mit unbekannter SubmessageId wird nach submessageLength übersprungen, auch mit gesetztem Flag-Bit 7 (§8.3.4.1 Regel 3 kennt kein Must-Understand auf Submessage-Ebene).

§8.6.1 Zusätzliche Felder am Ende einer Submessage überspringen

Spec: §8.6.1, S. 137 — “Additional fields can be added to the end of a Submessage that was already defined in the current minor version. An implementation should skip over additional fields using the submessageLength field in the SubmessageHeader.”

Repo: crates/rtps/src/datagram.rs (decode_submessage); die read_body der Submessages in crates/rtps/src/submessages.rs

Tests: crates/rtps/src/datagram.rs::tests::additional_fields_at_the_end_of_a_known_submessage_are_skipped

Status: done — HEARTBEAT, ACKNACK, GAP, HEARTBEAT_FRAG, NACK_FRAG, INFO_TS, INFO_SRC, INFO_REPLY, INFO_REPLY_IP4 und INFO_DST ergeben mit acht Oktetten mehr am Ende des Körpers denselben Wert wie ohne. Bei DATA und DATA_FRAG endet der Körper mit den Nutzdaten; neue Felder davor überspringt octetsToInlineQos.

§8.6.1 Unbekannte Builtin-Endpunkte ignorieren

Spec: §8.6.1, S. 137 — “Additional built-in Endpoints with new IDs can be added. An implementation should ignore any unknown built-in Endpoints.”

Repo: crates/discovery/src/sedp/stack.rs (Zuordnung nur bekannter EntityIds); crates/discovery/src/sedp/stack.rs (on_participant_discovered: nur bekannte Bits)

Tests: crates/discovery/src/sedp/stack.rs::tests::routing_unknown_with_wrong_writer_does_not_match, crates/discovery/src/sedp/stack.rs::tests::partial_endpoint_set_wires_only_matching_sides

Status: done

§8.6.1 Unbekannte Parameter ignorieren

Spec: §8.6.1, S. 137 — “Additional parameters with new parameterIds can be added. An implementation should ignore any unknown parameters.”

Repo: crates/rtps/src/parameter_list.rs (ParameterList::from_bytes); crates/rtps/src/publication_data.rs (Decoder übergehen unbekannte PIDs)

Tests: crates/rtps/src/publication_data.rs::tests::unknown_pids_are_skipped, crates/rtps/src/parameter_list.rs::tests::validate_must_understand_in_data_pipeline_optional_unknown_pid_passes

Status: done — unbekannte PIDs mit Must-Understand-Bit sind unter §9.4.2.11 geführt.

§8.6.1 Erweiterungen erhöhen die Minor-Version

Spec: §8.6.1, S. 137 — “All such changes require an increase of the minor version number.”

Repo: —

Tests: —

Status: n/a (informative) — Anforderung an künftige Fassungen der Spezifikation.

§8.6.2 Unveränderliches innerhalb der Major-Version

Spec: §8.6.2, S. 137 — “A Submessage cannot be deleted. A Submessage cannot be modified except as described in 8.6.1. The meaning of submessageIds cannot be modified.”

Repo: —

Tests: —

Status: n/a (informative) — Anforderung an künftige Fassungen der Spezifikation.

§8.7 Implementing DDS QoS and advanced DDS features using RTPS

§8.7 DDS-QoS und erweiterte Funktionen über RTPS

Spec: §8.7, S. 137 — “This sub clause defines how to use RTPS to implement the DDS QoS parameters.” “This sub clause forms a normative part of the specification for the purpose of interoperability.”

Repo: —

Tests: —

Status: n/a (informative) — Einleitung; die Anforderungen stehen in §8.7.1 bis §8.7.10.

§8.7.1 Inline-QoS des Writers auf Wunsch des Readers

Spec: §8.7.1, S. 138 — “A stateless Reader’s need for receiving in-line QoS to get information on remote Writers is the justification for requiring a Writer to send in-line QoS if the Reader requests them (8.4.2.2.2).” “For immutable QoS, all RxO QoS are sent in-line … Mutable QoS relevant to the Reader are sent in-line so they may take effect immediately”.

Repo: crates/rtps/src/reliable_writer.rs (sample_inline_qos: inline_writer_qos für Reader mit expectsInlineQos); crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_reader_that_expects_inline_qos_gets_the_writers_qos_with_each_data, crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.1 TOPIC_NAME in der Inline-QoS

Spec: §8.7.1, S. 138 — “If in-line QoS parameters are expected, implementations must also include the topic name as an in-line parameter.”

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::TOPIC_NAME zuerst)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.1 Coherent-Set- und Filter-Parameter

Spec: §8.7.1, S. 138 — “Independent of whether Readers expect in-line QoS parameters, a Data Submessage may also contain in-line parameters related to coherent sets and content-filtered topics.”

Repo: —

Tests: —

Status: n/a (informative) — Verweis auf §8.7.3 und §8.7.6.

§8.7.1 Zustandsbehaftete Reader dürfen Inline-QoS übergehen

Spec: §8.7.1, S. 138 — “For improved performance, stateful implementations may ignore in-line QoS and instead rely solely on cached values obtained through Discovery.”

Repo: —

Tests: —

Status: n/a (informative) — keine Anforderung; ZeroDDS-Reader übernehmen die QoS des Writers aus SEDP.

§8.7.2 Table 8.85 USER_DATA

Spec: §8.7.2, S. 138, Table 8.85 — “USER_DATA — None — No”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: nicht in IN_LINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 TOPIC_DATA

Spec: §8.7.2, S. 138, Table 8.85 — “TOPIC_DATA — None — No”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: nicht in IN_LINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 GROUP_DATA

Spec: §8.7.2, S. 138, Table 8.85 — “GROUP_DATA — None — No”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: nicht in IN_LINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 DURABILITY

Spec: §8.7.2, S. 138, Table 8.85 — “DURABILITY — See 8.7.2.2.1 — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::DURABILITY)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 DURABILITY_SERVICE

Spec: §8.7.2, S. 138, Table 8.85 — “DURABILITY_SERVICE — None — No”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: nicht in IN_LINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 PRESENTATION

Spec: §8.7.2, S. 138, Table 8.85 — “PRESENTATION — See 8.7.2.2.2 — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::PRESENTATION)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 DEADLINE

Spec: §8.7.2, S. 138, Table 8.85 — “DEADLINE — None — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::DEADLINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 LATENCY_BUDGET

Spec: §8.7.2, S. 138, Table 8.85 — “LATENCY_BUDGET — None — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::LATENCY_BUDGET)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 OWNERSHIP

Spec: §8.7.2, S. 138, Table 8.85 — “OWNERSHIP — None — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::OWNERSHIP)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 OWNERSHIP_STRENGTH

Spec: §8.7.2, S. 138, Table 8.85 — “OWNERSHIP_STRENGTH — None — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::OWNERSHIP_STRENGTH)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 LIVELINESS

Spec: §8.7.2, S. 138, Table 8.85 — “LIVELINESS — See 8.7.2.2.3 — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::LIVELINESS)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 TIME_BASED_FILTER

Spec: §8.7.2, S. 139, Table 8.85 — “TIME_BASED_FILTER — See 8.7.2.2.4 — No”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: nicht in IN_LINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 PARTITION

Spec: §8.7.2, S. 139, Table 8.85 — “PARTITION — None — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::PARTITION)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 RELIABILITY

Spec: §8.7.2, S. 139, Table 8.85 — “RELIABILITY — See 8.7.2.2.5 — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::RELIABILITY)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 TRANSPORT_PRIORITY

Spec: §8.7.2, S. 139, Table 8.85 — “TRANSPORT_PRIORITY — None — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::TRANSPORT_PRIORITY, wenn nicht 0)

Tests: crates/rtps/src/publication_data.rs::tests::a_transport_priority_goes_in_line_and_not_into_the_announcement

Status: done

§8.7.2 Table 8.85 LIFESPAN

Spec: §8.7.2, S. 139, Table 8.85 — “LIFESPAN — None — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::LIFESPAN)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 DESTINATION_ORDER

Spec: §8.7.2, S. 139, Table 8.85 — “DESTINATION_ORDER — See 8.7.2.2.6 — Yes”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: pid::DESTINATION_ORDER)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 HISTORY

Spec: §8.7.2, S. 139, Table 8.85 — “HISTORY — None — No”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: nicht in IN_LINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 RESOURCE_LIMITS

Spec: §8.7.2, S. 139, Table 8.85 — “RESOURCE_LIMITS — None — No”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: nicht in IN_LINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 ENTITY_FACTORY

Spec: §8.7.2, S. 139, Table 8.85 — “ENTITY_FACTORY — None — No”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: nicht in IN_LINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 WRITER_DATA_LIFECYCLE

Spec: §8.7.2, S. 139, Table 8.85 — “WRITER_DATA_LIFECYCLE — See 8.7.2.2.7 — No”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: nicht in IN_LINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2 Table 8.85 READER_DATA_LIFECYCLE

Spec: §8.7.2, S. 139, Table 8.85 — “READER_DATA_LIFECYCLE — None — No”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos: nicht in IN_LINE)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2.1 Fehlende Inline-QoS: Vorgabe nach DDS

Spec: §8.7.2.1, S. 139 — “If a Reader expects to receive in-line QoS parameters and any of these QoS parameters are missing, it will assume the default value for that QoS parameter, where the default is defined by DDS.”

Repo: —

Tests: —

Status: n/a (informative) — die Bedingung tritt nicht ein: ZeroDDS-Reader kündigen expectsInlineQos = FALSE an und übernehmen die QoS des Writers aus SEDP.

§8.7.2.1 TOPIC_NAME für selbstbeschreibende Nachrichten

Spec: §8.7.2.1, S. 139 — “In order to achieve self-describing messages, not only the parameters defined in Table 8.85 have to be sent with the submessage, but also a parameter TOPIC_NAME.”

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§8.7.2.2.1 DURABILITY

Spec: §8.7.2.2.1, S. 139 — “While volatile and transient-local durability do not affect the RTPS protocol, support for transient and persistent durability may. This is not covered in the current version of the specification.”

Repo: —

Tests: —

Status: n/a (informative) — keine Anforderung.

§8.7.2.2.2 PRESENTATION

Spec: §8.7.2.2.2, S. 139 — “Sub clause 8.7.5 defines how to implement the GROUP ordered access policy of the PRESENTATION QoS. Sub clause 8.7.6 defines how to implement the coherent access policy of the PRESENTATION QoS.”

Repo: —

Tests: —

Status: n/a (informative) — Verweis auf §8.7.5 und §8.7.6.

§8.7.2.2.3 LIVELINESS AUTOMATIC

Spec: §8.7.2.2.3, S. 139 — “DDS_AUTOMATIC_LIVELINESS_QOS : liveliness is maintained through the BuiltinParticipantMessageWriter. … implementations must refresh the Participant’s liveliness (i.e., send the ParticipantMessageData, see (8.4.13.5) at a rate faster than the smallest lease duration among the Writers.”

Repo: crates/dcps/src/runtime.rs (refresh_wlp_period); crates/dcps/src/wlp.rs (WlpEndpoint::tick)

Tests: crates/dcps/tests/liveliness_qos.rs::linux::an_automatic_writer_that_never_writes_stays_alive_at_a_remote_reader

Status: done

§8.7.2.2.3 LIVELINESS MANUAL_BY_PARTICIPANT

Spec: §8.7.2.2.3, S. 139 — “If the Participant has any MANUAL_BY_PARTICIPANT Writers, implementations must check periodically to see if write(), assert_liveliness(), dispose(), or unregister_instance() was called for any of them. The period for this check equals the smallest lease duration among the Writers. If any of the operations were called, implementations must refresh the Participant’s liveliness (i.e., send the ParticipantMessageData, see 8.4.13.5).”

Repo: crates/dcps/src/runtime.rs (refresh_manual_by_participant, Aufrufe in write_user_sample_*, write_user_lifecycle_with, assert_writer_liveliness_eid, bump_manual_liveliness_count); crates/dcps/src/wlp.rs

Tests: crates/dcps/src/runtime.rs::tests::a_manual_by_participant_writer_refreshes_the_participant_liveliness, crates/dcps/src/wlp.rs::tests::refreshes_before_the_tick_share_one_manual_by_participant_sample, crates/dcps/src/runtime.rs::tests::the_manual_liveliness_count_of_the_announcement_counts_up

Status: done — write, assert_liveliness, dispose und unregister_instance eines MANUAL_BY_PARTICIPANT-Writers veranlassen eine ParticipantMessageData mit MANUAL_LIVELINESS_UPDATE beim nächsten Tick (statt einer Prüfung im Takt der kleinsten Lease) und erhöhen den manualLivelinessCount der SPDP-Ankündigung.

§8.7.2.2.3 LIVELINESS MANUAL_BY_TOPIC

Spec: §8.7.2.2.3, S. 140 — “The standard RTPS Messages that result from calling write(), dispose(), or unregister_instance() on a Writer Entity suffice to assert the liveliness of a Writer with LIVELINESS QoS set to MANUAL_BY_TOPIC. When assert_liveliness() is called, the Writer must send a Heartbeat Message with final flag and liveliness flag set.”

Repo: crates/rtps/src/reliable_writer.rs (liveliness_heartbeat); crates/dcps/src/runtime.rs (assert_writer_liveliness_eid)

Tests: crates/rtps/src/reliable_writer.rs::tests::liveliness_heartbeat_is_a_final_heartbeat_with_the_liveliness_flag, crates/dcps/tests/liveliness_qos.rs::linux::assert_liveliness_keeps_a_manual_writer_alive_at_a_remote_reader, crates/dcps/src/runtime.rs::tests::a_manual_writer_goes_not_alive_when_silent_and_back_when_it_writes

Status: done

§8.7.2.2.4 TIME_BASED_FILTER auf der Writer-Seite

Spec: §8.7.2.2.4, S. 140 — “Implementations may optimize bandwidth usage by applying a time-based filter on the Writer side. … When one or more data updates are filtered out on the Writer side, implementations must send a Gap Submessage instead, indicating which samples were filtered out. This Submessage must be sent before the next update”.

Repo: —

Tests: —

Status: open — eine optionale Funktion; ZeroDDS wendet TIME_BASED_FILTER nur auf der Reader-Seite an (tbf_should_deliver) und sendet kein GAP für zeitgefilterte Samples.

§8.7.2.2.5 RELIABILITY

Spec: §8.7.2.2.5, S. 140 — “Implementations must meet the reliable RTPS protocol requirements for interoperability, defined in 8.4.2.”

Repo: —

Tests: —

Status: n/a (informative) — Verweis; die Anforderungen sind unter §8.4.2 geführt.

§8.7.2.2.6 DESTINATION_ORDER BY_SOURCE_TIMESTAMP

Spec: §8.7.2.2.6, S. 140 — “In order to implement the DDS_BY_SOURCE_TIMESTAMP_DESTINATIONORDER_QOS policy, implementations must include an InfoTimestamp Submessage with every update from a Writer.”

Repo: crates/rtps/src/reliable_writer.rs (append_info_ts vor jeder DATA und jedem DATA_FRAG); crates/dcps/src/runtime.rs (jeder write erhält einen Quellzeitstempel)

Tests: crates/rtps/src/reliable_writer.rs::tests::write_stamped_prepends_info_ts_before_data, crates/rtps/src/reliable_writer.rs::tests::write_lifecycle_prepends_info_ts_before_data, crates/rtps/src/reliable_writer.rs::tests::resend_carries_original_info_ts

Status: done

§8.7.2.2.7 WRITER_DATA_LIFECYCLE autodispose

Spec: §8.7.2.2.7, S. 140 — “If autodispose_unregistered_instances is enabled, Data Messages that unregister an instance must also dispose it.”

Repo: crates/dcps/src/publisher.rs (unregister_instance: DISPOSED mit UNREGISTERED bei autodispose_unregistered_instances)

Tests: crates/dcps/tests/writer_data_lifecycle_qos.rs::autodispose_default_true_unregister_disposes, crates/dcps/tests/lifecycle_wire_e2e.rs::linux::unregister_with_autodispose_false_propagates_unregister_only

Status: done

§8.7.3 Filterung auf der Reader-Seite

Spec: §8.7.3, S. 140 — “When filtering on the Reader side only, samples which do not pass the filter are simply dropped by the middleware. In this case, no further extensions to RTPS are needed.”

Repo: crates/dcps/src/subscriber.rs (Filter des ContentFilteredTopic)

Tests: crates/dcps/tests/content_filtered_reader.rs::a_reader_on_a_content_filtered_topic_delivers_what_the_filter_accepts, crates/dcps/tests/content_filter.rs::filter_drops_samples_that_return_false

Status: done

§8.7.3 Filterung auf der Writer-Seite

Spec: §8.7.3, S. 140 — “In order to support Writer side filtering, standard RTPS extension mechanisms are used to: Include Reader filter information during the Endpoint discovery phase. Include filter results with each data sample.” §8.7.3.4, S. 142: “Writer side filtering constitutes an optimization and is optional”.

Repo: —

Tests: —

Status: open — eine optionale Funktion; ZeroDDS filtert nicht auf der Writer-Seite. Die Filterangaben des Readers in SEDP sind unter §8.7.3.1 geführt.

§8.7.3 Hinweise des Writers: ALIVE_FILTERED, ContentFilterInfo, ausgelassene Daten

Spec: §8.7.3, S. 140 — “The Writer may indicate to a Reader that a Sample has been filtered … by sending a directed Data message that includes only the key information (DataFlag=0), indicating in the Inline Qos that the instance state is ALIVE_FILTERED.” “Alternatively, the Writer may not send a Data message at all. This is only allowed if the previous sample for that Instance was already filtered for that Reader”.

Repo: —

Tests: —

Status: open — Teil der optionalen Filterung auf der Writer-Seite (§8.7.3), die ZeroDDS nicht ausführt.

§8.7.3.1 ContentFilterProperty_t in DiscoveredReaderData

Spec: §8.7.3.1, S. 141 — “RTPS adds an additional ContentFilterProperty_t field to DiscoveredReaderData, defined in Table 8.86.”

Repo: crates/rtps/src/subscription_data.rs (SubscriptionBuiltinTopicData::content_filter, ContentFilterProperty)

Tests: crates/rtps/src/subscription_data.rs::tests::subscription_with_content_filter_roundtrip_le, crates/dcps/src/runtime.rs::tests::the_content_filter_travels_in_the_subscription_and_is_reannounced

Status: done

§8.7.3.1 Table 8.86 contentFilteredTopicName

Spec: §8.7.3.1, S. 141, Table 8.86 — “contentFilteredTopicName: string — Name of the Content-filtered Topic associated with the Reader. Must have non-zero length.”

Repo: crates/rtps/src/subscription_data.rs (ContentFilterProperty::content_filtered_topic_name); crates/dcps/src/participant.rs (create_contentfilteredtopic lehnt einen leeren Namen ab)

Tests: crates/rtps/src/subscription_data.rs::tests::content_filter_property_roundtrip_le, crates/dcps/src/participant.rs::tests::create_contentfilteredtopic_rejects_empty_name

Status: done

§8.7.3.1 Table 8.86 relatedTopicName

Spec: §8.7.3.1, S. 141, Table 8.86 — “relatedTopicName: string — Name of the Topic related to the Content-filtered Topic. Must have non-zero length.”

Repo: crates/rtps/src/subscription_data.rs (ContentFilterProperty::related_topic_name); crates/dcps/src/topic.rs (ContentFilteredTopic::property)

Tests: crates/rtps/src/subscription_data.rs::tests::content_filter_property_roundtrip_le

Status: done

§8.7.3.1 Table 8.86 filterClassName

Spec: §8.7.3.1, S. 141, Table 8.86 — “filterClassName: string … Must have non-zero length. RTPS predefines the following values: “DDSSQL” Default filter class name if none specified.”

Repo: crates/rtps/src/subscription_data.rs (filter_class::DDSSQL); crates/dcps/src/topic.rs (ContentFilteredTopic::content_filter_property: DDSSQL oder die registrierte Klasse)

Tests: crates/rtps/src/subscription_data.rs::tests::content_filter_property_roundtrip_le, crates/dcps/src/runtime.rs::tests::the_content_filter_travels_in_the_subscription_and_is_reannounced, crates/dcps/tests/custom_content_filter.rs::a_registered_filter_class_is_named_announced_and_applied

Status: done

§8.7.3.1 Table 8.86 filterExpression

Spec: §8.7.3.1, S. 141, Table 8.86 — “filterExpression: string — The actual filter expression. Must be a valid expression for the filter class specified using filterClassName. Must have non-zero length.”

Repo: crates/rtps/src/subscription_data.rs (ContentFilterProperty::filter_expression); crates/dcps/src/participant.rs (create_contentfilteredtopic lehnt einen leeren Ausdruck ab)

Tests: crates/rtps/src/subscription_data.rs::tests::content_filter_property_roundtrip_le, crates/dcps/src/participant.rs::tests::create_contentfilteredtopic_rejects_empty_expression

Status: done

§8.7.3.1 Table 8.86 expressionParameters

Spec: §8.7.3.1, S. 141, Table 8.86 — “expressionParameters: stringSequence — Defines the value for each parameter in the filter expression. Can have zero length if the filter expression contains no parameters.”

Repo: crates/rtps/src/subscription_data.rs (ContentFilterProperty::expression_parameters)

Tests: crates/rtps/src/subscription_data.rs::tests::content_filter_property_roundtrip_le, crates/dcps/src/runtime.rs::tests::the_content_filter_travels_in_the_subscription_and_is_reannounced

Status: done

§8.7.3.1 Writer ohne passende Filterklasse

Spec: §8.7.3.1, S. 141 — “In order for the Writer to apply the filter, it must have been configured to handle filters of the specified filter class. If not, the Writer will simply ignore the filter information and not filter any data samples.”

Repo: —

Tests: —

Status: open — Teil der optionalen Filterung auf der Writer-Seite (§8.7.3), die ZeroDDS nicht ausführt.

§8.7.3.1 Geänderte Filterparameter über die Endpunkt-Entdeckung

Spec: §8.7.3.1, S. 141 — “Each time the parameters are modified, the updated information is exchanged using the Endpoint discovery protocol.”

Repo: crates/dcps/src/runtime.rs (update_user_reader_content_filter)

Tests: crates/dcps/src/runtime.rs::tests::the_content_filter_travels_in_the_subscription_and_is_reannounced

Status: done

§8.7.3.2 Gefiltertes Sample anzeigen

Spec: §8.7.3.2, S. 141 — “When this happens, the Writer can use a Data submessage that does not contain a Data payload (DataFlag=0) and sets FilteredFlag=1, see 8.3.8.2.2.”

Repo: —

Tests: —

Status: open — Teil der optionalen Filterung auf der Writer-Seite (§8.7.3), die ZeroDDS nicht ausführt. Die Data-Submessage hat kein FilteredFlag; das FilteredFlag gehört zu StatusInfo_t (§9.6.4.9).

§8.7.3.3 GAP statt DATA und Filterergebnisse in der Inline-QoS

Spec: §8.7.3.3, S. 142 — “In that case, the Data submessage is replaced by a Gap submessage.” “The sample passes some or all of the filters. In that case, the sample must still be sent and the writer must include information with the Data submessage on what filters were applied and the according result.”

Repo: —

Tests: —

Status: open — Teil der optionalen Filterung auf der Writer-Seite (§8.7.3), die ZeroDDS nicht ausführt.

§8.7.3.3 Table 8.87 filterResult

Spec: §8.7.3.3, S. 142, Table 8.87 — “filterResult: FilterResult_t — For each filter signature, the results indicate whether the sample passed the filter.”

Repo: —

Tests: —

Status: open — Teil der optionalen Filterung auf der Writer-Seite (§8.7.3), die ZeroDDS nicht ausführt; PID_CONTENT_FILTER_INFO wird nicht gesendet.

§8.7.3.3 Table 8.87 filterSignatures

Spec: §8.7.3.3, S. 142, Table 8.87 — “filterSignatures: FilterSignature_t[] — A list of filters that were applied to the sample.”

Repo: —

Tests: —

Status: open — Teil der optionalen Filterung auf der Writer-Seite (§8.7.3), die ZeroDDS nicht ausführt; PID_CONTENT_FILTER_INFO wird nicht gesendet.

§8.7.3.4 Reader filtern, wenn der Writer nicht filtert

Spec: §8.7.3.4, S. 142 — “Samples will always be filtered on the Reader side if: The Writer side did not apply any filtering. The Writer side did not apply the filter expected by the Reader. … The Reader side does not support Writer side filtering”.

Repo: crates/dcps/src/subscriber.rs (Filter je empfangenem Sample)

Tests: crates/dcps/tests/content_filtered_reader.rs::a_reader_on_a_content_filtered_topic_delivers_what_the_filter_accepts, crates/dcps/tests/content_filter.rs::filter_applies_also_to_read_peek

Status: done

§8.7.3.4 Filterklasse DDSSQL

Spec: §8.7.3.4, S. 143 — “If an implementation supports Content-filtered Topics, it must at least recognize the “DDSSQL” filter class, as mandated by the DDS specification.”

Repo: crates/dcps/src/topic.rs (ContentFilteredTopic, SQL-Filter); crates/rtps/src/subscription_data.rs (filter_class::DDSSQL)

Tests: crates/dcps/tests/content_filtered_reader.rs::a_reader_on_a_content_filtered_topic_delivers_what_the_filter_accepts, crates/dcps/tests/content_filtered_reader.rs::a_field_the_type_does_not_answer_delivers_nothing

Status: done

§8.7.3.4 Eigene Filterklassen registrierbar

Spec: §8.7.3.4, S. 143 — “For all other filter classes, both implementations must allow the user to register the same custom filter class.”

Repo: crates/dcps/src/topic.rs (ContentFilter, ContentFilteredTopic); crates/dcps/src/participant.rs (DomainParticipant::register_contentfilter, lookup_contentfilter, unregister_contentfilter, create_contentfilteredtopic_with_class)

Tests: crates/dcps/tests/custom_content_filter.rs::a_registered_filter_class_is_named_announced_and_applied, crates/dcps/tests/custom_content_filter.rs::the_registry_refuses_what_it_cannot_serve

Status: done — die Anwendung registriert eine Filterklasse je Teilnehmer und Typ (register_contentfilter::<T>(name, Arc<dyn ContentFilter<T>>); DDSSQL ist die eigene Klasse der Implementierung und nicht registrierbar; Namen bis 256 Oktette). create_contentfilteredtopic_with_class nennt die Klasse; die Klasse prüft Ausdruck und Parameter (compile, beim Anlegen und bei set_filter_parameters) und filtert die Samples eines DataReaders auf dem Topic (evaluate). Der Klassenname geht als filterClassName in PID_CONTENT_FILTER_PROPERTY des Readers. Eine Klasse, die ein Peer nicht registriert hat, ignoriert er nach §8.7.3.4, und die Samples werden Reader-seitig gefiltert; ZeroDDS filtert auf der Writer-Seite nicht.

§8.7.3.4 Angaben für ALIVE_FILTERED trotz Filterung beim Writer

Spec: §8.7.3.4, S. 143 — “Even if the Writer is performing writer-side filtering, the Writer must provide enough information for the Reader to correctly transition the instance state to ALIVE_FILTERED.”

Repo: —

Tests: —

Status: open — Teil der optionalen Filterung auf der Writer-Seite (§8.7.3), die ZeroDDS nicht ausführt; jedes Sample geht an jeden gematchten Reader.

§8.7.4 Zustandswechsel der Instanz über Data und Inline-QoS

Spec: §8.7.4, S. 143 — “RTPS uses regular Data Submessages and the in-line QoS parameter extension mechanism to communicate instance state changes. The serialized information within the inline QoS contains the new InstanceState”.

Repo: crates/dcps/src/runtime.rs (write_user_lifecycle); crates/rtps/src/reliable_writer.rs (write_lifecycle: PID_STATUS_INFO)

Tests: crates/dcps/tests/lifecycle_wire_e2e.rs::linux::dispose_propagates_over_wire_to_reader, crates/dcps/tests/lifecycle_wire_decode.rs::reader_push_lifecycle_disposed_sets_instance_state

Status: done

§8.7.4 Nur der Schlüssel im SerializedPayload

Spec: §8.7.4, S. 143 — “When RTPS sends a Data Submessage to communicate instance state changes it may include only the Key of the Data-Object within the SerializedPayload submessage element”.

Repo: crates/dcps/src/runtime.rs (write_user_lifecycle: lifecycle_serialized_key)

Tests: crates/dcps/tests/lifecycle_wire_e2e.rs::linux::dispose_marker_carries_the_key_fields_of_a_string_keyed_type

Status: done

§8.7.4 Registrierung erst mit dem ersten Wert

Spec: §8.7.4, S. 143 — “An implementation of RTPS is not required to propagate registration changes until the DDS DataWriter writes the first value for that Data-Object instance.”

Repo: —

Tests: —

Status: n/a (informative) — keine Anforderung.

§8.7.4 Wert, der den Filter nicht passiert

Spec: §8.7.4, S. 143 — “If the previous update to the instance passed the filter, then the Writer must send a Data Submessage that either includes the data value, or else indicates the InstanceState is ALIVE_FILTERED.” “If the previous update to the instance did not pass the filter, then the Writer may omit sending the Data Submessage to the Reader.”

Repo: —

Tests: —

Status: open — Teil der optionalen Filterung auf der Writer-Seite (§8.7.3), die ZeroDDS nicht ausführt; ZeroDDS sendet jeden Wert.

§8.7.4 Dispose- und Unregister-Nachricht

Spec: §8.7.4, S. 143–144 — “This so called “dispose/unregister message” shall be sent if any of the following conditions is met: 1. The Reader does not have a Content Filter. 2. The Writer has previously sent a Data message to the Reader for that same instance. 3. The Reader has OWNERSHIP QosPolicy kind EXCLUSIVE …”

Repo: crates/dcps/src/runtime.rs (write_user_lifecycle: an jeden gematchten Reader)

Tests: crates/dcps/tests/lifecycle_wire_e2e.rs::linux::dispose_propagates_over_wire_to_reader, crates/dcps/tests/lifecycle_wire_e2e.rs::linux::instance_goes_no_writers_when_its_last_writer_disappears

Status: done — ZeroDDS sendet die Nachricht in jedem Fall.

§8.7.5 PID_GROUP_SEQ_NUM und PID_WRITER_GROUP_INFO

Spec: §8.7.5, S. 144 — “In order to support group ordered access, RTPS uses the in-line QoS parameter extension mechanism to include additional information with each CacheChange. … PID_GROUP_SEQ_NUM to contain the group sequence number. PID_WRITER_GROUP_INFO to contain the WriterGroupInfo_t”.

Repo: —

Tests: crates/rtps/src/reliable_writer.rs::tests::a_group_writers_data_carries_its_group_sequence_number, crates/rtps/src/reliable_writer.rs::tests::a_writer_outside_a_group_sends_no_group_parameter, crates/rtps/src/inline_qos.rs::tests::group_seq_num_is_a_cdr_sequence_number_with_pid_0x0064, crates/rtps/src/inline_qos.rs::tests::writer_group_info_carries_the_four_digest_octets_with_pid_0x0065

Status: done

§8.7.5 Table 8.88 WriterGroupInfo_t writerSet

Spec: §8.7.5, S. 144, Table 8.88 — “writerSet: GroupDigest_t — Identifies the set of Writer EntityIds that are announced in the DiscoveredWriterData that belonged to the Publisher at the time the sample was written.”

Repo: —

Tests: crates/rtps/src/inline_qos.rs::tests::writer_group_info_carries_the_four_digest_octets_with_pid_0x0065, crates/rtps/src/writer_group.rs::tests::the_writer_set_follows_the_writers, crates/rtps/src/group_digest.rs::tests::two_writers_digest_as_section_9_3_2_5_computes_it

Status: done

§8.7.5 Gruppen-Sequenznummer auf jedem Data und dem ersten DataFrag

Spec: §8.7.5, S. 144 — “When a Publisher is configured with access scope GROUP, all Data submessages and the first DataFrag submessage from any Writer within the Publisher are accompanied with a GROUP sequence number sent as part of the in-line QoS. The GROUP sequence number is a strictly monotonically increasing sequence number originating from the Publisher.”

Repo: —

Tests: crates/rtps/src/reliable_writer.rs::tests::a_group_writers_data_carries_its_group_sequence_number, crates/rtps/src/reliable_writer.rs::tests::a_dispose_carries_the_set_and_group_parameters_of_its_change, crates/rtps/src/writer_group.rs::tests::group_sequence_numbers_rise_by_one_per_change_from_one, crates/rtps/src/fragment_assembler.rs::tests::the_first_fragments_inline_qos_reaches_the_completed_sample

Status: done

§8.7.5 Subscriber: Übergabe nach Gruppen-Sequenznummer

Spec: §8.7.5, S. 144–145 — “A sample with GROUP sequence number GSN can be committed to the DDS DataReader from the Subscriber’s history cache if any of the following conditions apply: GSN-1 has been already been committed. It has been determined that none of the remote DataWriters that match reliable DataReaders have GSN-1.”

Repo: crates/dcps/src/group_order.rs (GroupOrder), crates/dcps/src/subscriber.rs (SubscriberInner::release_group)

Tests: crates/dcps/src/group_order.rs::tests::samples_of_two_writers_go_out_in_group_sequence_order, crates/dcps/src/group_order.rs::tests::a_number_no_counted_writer_has_is_passed_once_a_heartbeat_announced_it, crates/dcps/src/group_order.rs::tests::a_counted_writer_whose_heartbeat_range_holds_the_number_is_waited_for, crates/dcps/src/group_order.rs::tests::a_gap_rules_the_number_out_for_its_writer, crates/dcps/src/group_order.rs::tests::a_number_waits_for_the_copy_of_every_reader_of_its_writer, crates/dcps/tests/group_access_e2e.rs::a_reader_of_one_topic_gets_its_samples_without_the_others_numbers_over_udp, crates/dcps/tests/group_access_e2e.rs::two_readers_of_one_topic_each_get_every_sample_over_udp

Status: done

§8.7.5 Nur Writer mit Liveliness

Spec: §8.7.5, S. 145 — “The above rules should only take into consideration DataWriters that have not lost their liveliness, see 8.7.2.2.3.”

Repo: crates/dcps/src/runtime.rs (DcpsRuntime::user_reader_counted_writers)

Tests: crates/dcps/src/runtime.rs::tests::a_writer_that_lost_its_liveliness_is_not_counted_for_the_group_order

Status: done

§8.7.6 Publisher- und Subscriber-Coherent-Sets

Spec: §8.7.6, S. 145 — “A “Publisher coherent set” is defined as the set of all CacheChanges performed by all DataWriters in the Publisher delimited by the operations begin_coherent_changes() and end_coherent_changes().” “What constitutes a “Subscriber coherent set” depends on the PRESENTATION access_scope of the Subscriber”.

Repo: —

Tests: crates/dcps/tests/group_access_e2e.rs::a_group_coherent_set_across_two_topics_appears_after_its_end_over_udp, crates/dcps/tests/group_access_e2e.rs::a_group_coherent_set_across_two_topics_appears_after_its_end_same_runtime, crates/dcps/tests/coherent_changes_e2e.rs::group_coherent_reader_sees_the_set_only_after_end_coherent_changes

Status: done

§8.7.6 Unvollständige Coherent-Sets verwerfen

Spec: §8.7.6, S. 145 — “Incomplete coherent sets shall not be added to the history of the RTPS DataReaders and the corresponding CacheChanges shall be discarded by the Subscriber.”

Repo: —

Tests: crates/dcps/src/group_order.rs::tests::a_set_short_of_one_member_is_discarded_and_counted, crates/rtps/src/reliable_reader.rs::tests::a_set_short_of_a_change_ends_incomplete, crates/rtps/src/reliable_reader.rs::tests::a_set_ended_by_a_sample_is_reported_in_front_of_it_when_incomplete, crates/dcps/src/subscriber.rs::tests::an_incomplete_set_is_discarded, crates/dcps/tests/group_access_e2e.rs::a_reader_made_inside_a_set_does_not_get_its_tail_same_runtime

Status: done

§8.7.6 TOPIC-Scope: PID_COHERENT_SET mit der ersten Sequenznummer

Spec: §8.7.6, S. 146 — “a coherent set is uniquely identified by the sequence number of the first sample update belonging to the coherent set. All sample updates belonging to the same coherent set contain an in-line QoS parameter with this same sequence number.” “the same approach is followed for DataFrag Submessages.”

Repo: —

Tests: crates/rtps/src/reliable_writer.rs::tests::coherent_set_member_data_carries_pid_0x0056_with_set_first_sn_octets, crates/rtps/src/inline_qos.rs::tests::coherent_set_param_is_pid_0x0056_with_sequence_number_layout

Status: done

§8.7.6 Ende eines Coherent-Sets des Writers

Spec: §8.7.6, S. 146 — “The end of a Writer’s coherent set is defined by the arrival of one of the following: A Data Submessage from this Writer that belongs to a new coherent set. A Data Submessage from this Writer that does not contain a coherent set in-line QoS parameter or alternatively, contains a coherent set in-line QoS parameter with value SEQUENCENUMBER_UNKNOWN.”

Repo: —

Tests: crates/rtps/src/reliable_writer.rs::tests::end_coherent_set_emits_ecs_data_with_d_and_k_clear, crates/rtps/src/reliable_reader.rs::tests::end_of_coherent_set_data_is_delivered_as_a_terminator, crates/dcps/src/subscriber.rs::tests::every_end_of_coherent_set_form_releases_the_writers_set, crates/dcps/src/subscriber.rs::tests::a_sample_outside_any_set_releases_the_set_ahead_of_itself, crates/dcps/src/subscriber.rs::tests::a_member_of_a_new_set_releases_the_earlier_set, crates/rtps/src/inline_qos.rs::tests::find_coherent_set_reads_sequencenumber_unknown_as_no_set

Status: done

§8.7.6 GROUP-Scope: drei Inline-QoS-Parameter

Spec: §8.7.6, S. 146 — “All Data submessages and the first DataFrag submessage belonging to the same group coherent set shall have three in-line QoS parameters: The PID_GROUP_SEQ_NUM … The PID_COHERENT_SET … The PID_GROUP_COHERENT_SET”.

Repo: —

Tests: crates/rtps/src/reliable_writer.rs::tests::a_group_coherent_set_carries_the_parameters_of_table_9_23, crates/rtps/src/reliable_writer.rs::tests::a_participant_set_to_go_without_it_gets_no_group_coherent_set_pid, crates/rtps/src/reliable_writer.rs::tests::a_participant_set_to_coherent_sets_only_gets_no_group_information

Status: done

§8.7.6 ECS-Data-Submessage von allen Writern

Spec: §8.7.6, S. 146 — “A group’s coherent set is marked as being finished by sending an End Coherent Set (ECS) Data submessage from all Writers within the Publisher.” Eigenschaften: ohne serializedPayload, Gruppen-Sequenznummer der letzten Probe + 1, nicht gefiltert, zählt nicht gegen Resource Limits, Inline-QoS PID_GROUP_SEQ_NUM, PID_GROUP_COHERENT_SET, PID_WRITER_GROUP_INFO.

Repo: —

Tests: crates/rtps/src/reliable_writer.rs::tests::a_group_coherent_set_carries_the_parameters_of_table_9_23, crates/dcps/src/group_order.rs::tests::a_set_waits_for_the_end_of_every_counted_writer

Status: done

§8.7.6 Keine Writer hinzufügen oder entfernen während eines Coherent-Sets

Spec: §8.7.6, S. 146 — “Note that Writers are not allowed to be added or removed from a Publisher from the time that a coherent set begins until after it ends.”

Repo: —

Tests: crates/dcps/tests/group_access_e2e.rs::a_writer_is_not_created_or_deleted_while_a_group_coherent_set_is_open

Status: done

§8.7.6 DataReader: Gruppen-Coherent-Set übergeben

Spec: §8.7.6, S. 147 — “The group coherent set becomes ready to be committed to the DDS DataReader once an ECS sample is committed to the Subscriber and the ECS sample meets the criteria for being committed to the DDS DataReader. Once the group coherent set becomes ready to be committed the Subscriber shall determine if the subscriber-relevant coherent set is complete and if so, make it available to the application.”

Repo: —

Tests: crates/dcps/src/group_order.rs::tests::the_group_coherent_set_of_table_9_23_goes_out_whole_after_its_end, crates/dcps/src/group_order.rs::tests::a_set_is_complete_per_reader_of_each_writer, crates/dcps/tests/group_access_e2e.rs::a_dispose_in_a_group_coherent_set_waits_for_its_end_over_udp

Status: done

§8.7.6 Inline-QoS eines Coherent-Set-Mitglieds auf dem ersten DataFrag

Spec: §8.7.6, S. 146 — “The remainder of the discussion only refers to Data Submessages, but the same approach is followed for DataFrag Submessages.”

Repo: —

Tests: crates/rtps/src/reliable_writer.rs::tests::an_oversized_coherent_set_member_goes_out_as_marked_fragments, crates/rtps/src/fragment_assembler.rs::tests::the_first_fragments_inline_qos_reaches_the_completed_sample

Status: done

§8.7.7 Directed Write: PID_DIRECTED_WRITE

Spec: §8.7.7, S. 147 — “RTPS supports directed writes by using the in-line QoS parameter extension mechanism. The serialized information denotes the GUIDs of the targeted reader(s).”

Repo: crates/rtps/src/inline_qos.rs (directed_write_param, find_directed_write, directed_write_accepts); crates/rtps/src/parameter_list.rs (pid::DIRECTED_WRITE); crates/rtps/src/reliable_reader.rs (addressed_elsewhere)

Tests: crates/rtps/src/inline_qos.rs::tests::directed_write_param_carries_target_guid, crates/rtps/src/inline_qos.rs::tests::find_directed_write_returns_target_when_present, crates/rtps/src/reliable_reader.rs::tests::a_directed_sample_is_absorbed_by_a_reader_it_does_not_name

Status: done — Kodierung und Lesen des Parameters; der Empfangspfad liest jeden PID_DIRECTED_WRITE einer DATA, nicht nur den ersten. Kein Writer von ZeroDDS sendet einen gerichteten Write; die Spec bietet ihn dem Writer an, sie verlangt ihn nicht.

§8.7.7 Directed Write: nur der adressierte Reader übernimmt

Spec: §8.7.7, S. 147 — “When a writer sends a directed sample, only recipients with a matching GUID accept the sample; all other recipients acknowledge but absorb the sample, as if it were a GAP message.”

Repo: crates/rtps/src/reliable_reader.rs (addressed_elsewhere, irrelevant_change_set); crates/rtps/src/inline_qos.rs (directed_write_accepts)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_directed_sample_is_absorbed_by_a_reader_it_does_not_name, crates/rtps/src/inline_qos.rs::tests::directed_write_matches_reader_returns_false_for_other_target

Status: done — ein Reader, den kein PID_DIRECTED_WRITE der DATA nennt, bestätigt die Probe und verwirft sie wie nach einem GAP; ein genannter nimmt sie an. Gemessen: grün auf dem Linux-Testhost.

§8.7.8 Property Lists

Spec: §8.7.8, S. 147 — “The RTPS protocol supports Property Lists as in-line parameters. Properties can then be propagated during Discovery or as in-line QoS.”

Repo: crates/rtps/src/property_list.rs (WirePropertyList); crates/rtps/src/participant_data.rs (properties, PID_PROPERTY_LIST)

Tests: crates/rtps/src/property_list.rs::tests::multi_property_roundtrip_be, crates/rtps/src/participant_data.rs::tests::participant_data_properties_roundtrip

Status: done — ZeroDDS überträgt Property Lists in SPDP; in SEDP und als Inline-QoS nicht.

§8.7.9 Original Writer Info: Weiterleitung kennzeichnen

Spec: §8.7.9, S. 147 — “This service that forwards messages needs to indicate that the forwarded message belongs to the message-stream of another writer, such that if the reader receives the same messages from another source … it can treat them as duplicates.”

Repo: crates/dcps/src/runtime.rs (write_user_sample_on_behalf, write_user_lifecycle_on_behalf, write_user_sample_relayed); crates/durability-service/src/lib.rs (write_replay_sample); crates/routing-service/src/forwarding.rs (Relay-Modus)

Tests: crates/dcps/src/runtime.rs::tests::a_sample_written_on_behalf_of_another_writer_is_that_writers, crates/dcps/src/runtime.rs::tests::a_dispose_written_on_behalf_of_another_writer_is_that_writers, crates/durability-service/src/lib.rs::tests::a_replayed_sample_goes_out_on_behalf_of_its_writer, crates/routing-service/tests/relay_route.rs::a_relay_route_forwards_on_behalf_of_the_writer, crates/rtps/src/reliable_writer.rs::tests::a_lifecycle_marker_keeps_its_own_inline_qos_on_every_send

Status: done — ein Writer sendet eine Probe, ein Dispose oder ein Unregister im Namen eines anderen mit PID_ORIGINAL_WRITER_INFO, beim ersten Senden und bei jeder Reparatur. Der Durability-Service sendet gespeicherte Proben so, der Routing-Service im Relay-Modus (Route::relay) jede Probe und jede Lebenszyklus-Marke. Gemessen: grün auf dem Linux-Testhost.

§8.7.9 Original Writer Info: Übergabe an den Reader des Originals

Spec: §8.7.9, S. 147 — “When a RTPS Reader receives this information, it will treat it as a normal CacheChange, but once the CacheChange is ready to be committed to the DDS DataReader, it will not commit it. Instead, it will hand if off to the HistoryCache of the RTPS Reader that is communicating with the RTPS Writer indicated in the ORIGINAL_WRITER_INFO in-line QoS”.

Repo: crates/rtps/src/reliable_reader.rs (original_writer_of, commit_released, commit_forwarded, set_forwarder_trusted)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_forwarded_change_is_the_originals_and_its_direct_copy_a_duplicate, crates/rtps/src/reliable_reader.rs::tests::a_change_from_the_original_is_not_handed_out_again_when_forwarded, crates/rtps/src/reliable_reader.rs::tests::a_forwarded_change_waiting_in_the_originals_cache_is_a_duplicate, crates/rtps/src/reliable_reader.rs::tests::a_forwarded_change_the_original_gapped_is_handed_out, crates/rtps/src/reliable_reader.rs::tests::changes_forwarded_before_the_original_matched_are_not_delivered_again, crates/rtps/src/reliable_reader.rs::tests::an_untrusted_forwarder_delivers_as_itself, crates/rtps/src/reliable_reader.rs::tests::a_writer_that_comes_back_starts_a_new_stream

Status: done — eine Änderung mit PID_ORIGINAL_WRITER_INFO geht als die des Original-Writers hinaus, mit dessen Sequenznummer, auch wenn der Reader zum Original keinen Proxy hat; eine, die der Reader vom Original oder einem anderen Weiterleiter schon hat, ist ein Duplikat. Ein Writer, dem der Reader nicht als Weiterleiter traut, liefert als er selbst (unter DDS-Security nur mit <relay> im Grant, dds-security-1.2 §7.1.1.4). Gemessen: grün auf dem Linux-Testhost.

§8.7.9 Table 8.89 originalWriterGUID

Spec: §8.7.9, S. 147, Table 8.89 — “originalWriterGUID: GUID_t — The GUID of the RTPS Writer that first generated the message.”

Repo: crates/rtps/src/inline_qos.rs (original_writer_info_param)

Tests: crates/rtps/src/inline_qos.rs::tests::original_writer_info_param_24_byte_layout_le, crates/rtps/src/inline_qos.rs::tests::original_writer_info_roundtrip_be

Status: done — kodiert, gesendet und beim Empfang ausgewertet (Items unter §8.7.9).

§8.7.9 Table 8.89 originalWriterSN

Spec: §8.7.9, S. 147, Table 8.89 — “originalWriterSN: SequenceNumber_t — The Sequence Number of the CacheChange as sent from the original writer.”

Repo: crates/rtps/src/inline_qos.rs (original_writer_info_param)

Tests: crates/rtps/src/inline_qos.rs::tests::original_writer_info_roundtrip_le

Status: done — kodiert, gesendet und beim Empfang ausgewertet (Items unter §8.7.9).

§8.7.10 KeyHash aus den Daten berechnen

Spec: §8.7.10, S. 148 — “When the key hash is not received by a DataReader, it should be computed from the data itself. If there is no data in the submessage, then a default zero-valued key hash should be used by the DataReader.”

Repo: crates/dcps/src/runtime.rs (reader_key_hash_context); crates/dcps/src/key_hash.rs

Tests: crates/dcps/src/runtime.rs::tests::alive_sample_without_key_hash_gets_the_types_computed_hash, crates/dcps/src/runtime.rs::tests::lifecycle_marker_without_key_hash_gets_the_alive_instances_hash_and_holder

Status: done

§8.7.10 KeyHash nach §9.6.4.8 berechnen

Spec: §8.7.10, S. 148 — “A Key Hash, if present, shall be computed as described in 9.6.4.3.”

Repo: crates/dcps/src/key_hash.rs

Tests: crates/dcps/src/key_hash.rs::tests::a_holder_over_sixteen_is_hashed, crates/dcps/src/key_hash.rs::tests::a_u32_goes_out_big_endian

Status: done — der Verweis auf §9.6.4.3 ist in der Spec falsch; die Berechnung steht in §9.6.4.8.

§9 Platform Specific Model (PSM): UDP/IP

§9.1 PSM UDP/IP: Einleitung

Spec: §9.1, S. 149 — “This clause defines the Platform Specific Model (PSM) that maps the Protocol PIM to UDP/IP.”

Repo: —

Tests: —

Status: n/a (informative) — Begründung der Wahl von UDP/IP, keine Anforderung.

§9.2.1 Namensraum

Spec: §9.2.1, S. 149 — “All the definitions in this document are part of the “RTPS” name-space.”

Repo: —

Tests: —

Status: n/a (informative) — Konvention des Dokuments.

§9.2.2 IDL-Darstellung und CDR-Leitungsform

Spec: §9.2.2, S. 149 — “These definitions use the OMG IDL … When these structures are sent on the wire, they are encoded using the corresponding CDR representation.”

Repo: —

Tests: —

Status: n/a (informative) — Konvention; die einzelnen Abbildungen sind unter §9.3 und §9.4 geführt.

§9.2.3 Darstellung von Bits und Bytes

Spec: §9.2.3, S. 149–150 — “the leftmost bit (bit 7) is the most significant bit”; Bytes in Zeilen zu vier.

Repo: —

Tests: —

Status: n/a (informative) — Notation des Dokuments.

§9.3.1 GUID aus GuidPrefix und EntityId

Spec: §9.3.1, S. 150 — “The PIM defines the GUID as composed of a GuidPrefix_t prefix capable of holding 12 bytes, and an EntityId_t entityId capable of holding 4 bytes.”

Repo: crates/rtps/src/wire_types.rs (Guid, Guid::to_bytes)

Tests: crates/rtps/src/wire_types.rs::tests::guid_layout_is_prefix_then_entity_id, crates/rtps/src/wire_types.rs::tests::guid_roundtrip

Status: done

§9.3.1.1 GuidPrefix_t

Spec: §9.3.1.1, S. 150 — “typedef octet GuidPrefix_t[12];”

Repo: crates/rtps/src/wire_types.rs (GuidPrefix)

Tests: crates/rtps/src/wire_types.rs::tests::guid_prefix_roundtrip

Status: done

§9.3.1.1 GUIDPREFIX_UNKNOWN

Spec: §9.3.1.1, S. 150 — “#define GUIDPREFIX_UNKNOWN {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}”.

Repo: crates/rtps/src/wire_types.rs (GuidPrefix::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::guid_prefix_unknown_is_zero

Status: done

§9.3.1.2 EntityId_t

Spec: §9.3.1.2, S. 150 — “struct EntityId_t { OctetArray3 entityKey; octet entityKind; };”

Repo: crates/rtps/src/wire_types.rs (EntityId)

Tests: crates/rtps/src/wire_types.rs::tests::entity_id_roundtrip, crates/rtps/src/wire_types.rs::tests::entity_id_user_writer_with_key_layout

Status: done

§9.3.1.2 ENTITYID_UNKNOWN

Spec: §9.3.1.2, S. 150 — “#define ENTITYID_UNKNOWN {{0x00, 0x00, 0x00}, 0x00}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::entity_id_unknown_is_four_zero_octets

Status: done

§9.3.1.2 entityKey eindeutig im Participant

Spec: §9.3.1.2, S. 150 — “When not pre-defined (see below), the entityKey field within the EntityId_t can be chosen arbitrarily by the middleware implementation as long as the resulting EntityId_t is unique within the Participant.”

Repo: crates/dcps/src/runtime.rs (DcpsRuntime::next_entity_key, entity_key_in_use, pinned_entity_keys, new_group_entity_id, reserve_user_writer_id, reserve_user_reader_id)

Tests: crates/dcps/src/runtime.rs::tests::entity_keys_are_unique_across_groups_reserved_and_registered_endpoints, crates/dcps/src/runtime.rs::tests::a_wrapped_entity_key_counter_skips_the_key_of_a_live_writer

Status: done — der Zähler (24 Bit) vergibt jeden Schlüssel einmal; nach dem Umlauf überspringt er die Schlüssel registrierter Writer, Reader und angekündigter Topics sowie die der Publisher, Subscriber und reservierten, noch nicht registrierten Endpunkte. Ein Schlüssel eines gelöschten Endpunkts wird wieder vergeben; ein reservierter, nie registrierter Schlüssel bleibt belegt.

§9.3.1.2 entityKind: Art der Entität in den oberen zwei Bits

Spec: §9.3.1.2, S. 150 — “The information on whether the object is a built-in entity, a vendor-specific entity, or a user-defined entity is encoded in the two most-significant bits of the entityKind.” “a vendor-specific Entity … can therefore be ignored by another vendor’s implementation”.

Repo: crates/rtps/src/wire_types.rs (EntityKind::from_byte, EntityKind::Other)

Tests: crates/rtps/src/wire_types.rs::tests::entity_kind_octet_round_trips, crates/rtps/src/wire_types.rs::tests::entity_id_unnamed_kind_byte_is_kept

Status: done

§9.3.1.2 Table 9.1 unknown

Spec: §9.3.1.2, S. 151, Table 9.1 — “unknown — 0x00 — 0xc0”.

Repo: crates/rtps/src/wire_types.rs (EntityKind::Unknown, EntityKind::Other(0xC0))

Tests: crates/rtps/src/wire_types.rs::tests::topic_kind_follows_entity_kind_octet_of_table_9_1, crates/rtps/src/wire_types.rs::tests::entity_kind_octet_round_trips

Status: done

§9.3.1.2 Table 9.1 Participant

Spec: §9.3.1.2, S. 151, Table 9.1 — “Participant — N/A — 0xc1”.

Repo: crates/rtps/src/wire_types.rs (EntityKind::Participant)

Tests: crates/rtps/src/wire_types.rs::tests::entity_id_participant_constant

Status: done

§9.3.1.2 Table 9.1 Writer (with Key)

Spec: §9.3.1.2, S. 151, Table 9.1 — “Writer (with Key) — 0x02 — 0xc2”.

Repo: crates/rtps/src/wire_types.rs (UserWriterWithKey, BuiltinWriterWithKey)

Tests: crates/rtps/src/wire_types.rs::tests::topic_kind_follows_entity_kind_octet_of_table_9_1

Status: done

§9.3.1.2 Table 9.1 Writer (no Key)

Spec: §9.3.1.2, S. 151, Table 9.1 — “Writer (no Key) — 0x03 — 0xc3”.

Repo: crates/rtps/src/wire_types.rs (UserWriterNoKey, BuiltinWriterNoKey)

Tests: crates/rtps/src/wire_types.rs::tests::topic_kind_follows_entity_kind_octet_of_table_9_1

Status: done

§9.3.1.2 Table 9.1 Reader (no Key)

Spec: §9.3.1.2, S. 151, Table 9.1 — “Reader (no Key) — 0x04 — 0xc4”.

Repo: crates/rtps/src/wire_types.rs (UserReaderNoKey, BuiltinReaderNoKey)

Tests: crates/rtps/src/wire_types.rs::tests::topic_kind_follows_entity_kind_octet_of_table_9_1

Status: done

§9.3.1.2 Table 9.1 Reader (with Key)

Spec: §9.3.1.2, S. 151, Table 9.1 — “Reader (with Key) — 0x07 — 0xc7”.

Repo: crates/rtps/src/wire_types.rs (UserReaderWithKey, BuiltinReaderWithKey)

Tests: crates/rtps/src/wire_types.rs::tests::topic_kind_follows_entity_kind_octet_of_table_9_1

Status: done

§9.3.1.2 Table 9.1 Writer Group

Spec: §9.3.1.2, S. 151, Table 9.1 — “Writer Group — 0x08 — 0xc8”.

Repo: crates/rtps/src/wire_types.rs (EntityKind::Other, Oktett unverändert)

Tests: crates/rtps/src/wire_types.rs::tests::topic_kind_follows_entity_kind_octet_of_table_9_1, crates/rtps/src/wire_types.rs::tests::entity_kind_octet_round_trips

Status: done

§9.3.1.2 Table 9.1 Reader Group

Spec: §9.3.1.2, S. 151, Table 9.1 — “Reader Group — 0x09 — 0xc9”.

Repo: crates/rtps/src/wire_types.rs (EntityKind::Other, Oktett unverändert)

Tests: crates/rtps/src/wire_types.rs::tests::topic_kind_follows_entity_kind_octet_of_table_9_1, crates/rtps/src/wire_types.rs::tests::entity_kind_octet_round_trips

Status: done

§9.3.1.3 Bedeutung der vordefinierten EntityIds

Spec: §9.3.1.3, S. 151 — “The meaning of these Entity IDs cannot change in this major version (2) of the protocol, but future minor versions may add additional reserved Entity IDs.”

Repo: —

Tests: —

Status: n/a (informative) — Anforderung an künftige Fassungen der Spezifikation.

§9.3.1.3 Table 9.2 ENTITYID_PARTICIPANT

Spec: §9.3.1.3, S. 151, Table 9.2 — “ENTITYID_PARTICIPANT = {{00,00,01},c1}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::PARTICIPANT)

Tests: crates/rtps/src/wire_types.rs::tests::entity_id_participant_constant

Status: done

§9.3.1.3 Table 9.2 ENTITYID_SEDP_BUILTIN_TOPICS_ANNOUNCER

Spec: §9.3.1.3, S. 151, Table 9.2 — “ENTITYID_SEDP_BUILTIN_TOPICS_ANNOUNCER = {{00,00,02},c2}”.

Repo: EntityId::SEDP_BUILTIN_TOPICS_WRITER (crates/rtps/src/wire_types.rs)

Tests: crates/rtps/src/wire_types.rs::tests::the_entity_ids_of_table_9_2_are_those_of_the_table

Status: done — die Konstante trägt {{00,00,02},c2}; der Test prüft alle Werte der Table 9.2.

§9.3.1.3 Table 9.2 ENTITYID_SEDP_BUILTIN_TOPICS_DETECTOR

Spec: §9.3.1.3, S. 151, Table 9.2 — “ENTITYID_SEDP_BUILTIN_TOPICS_DETECTOR = {{00,00,02},c7}”.

Repo: EntityId::SEDP_BUILTIN_TOPICS_READER (crates/rtps/src/wire_types.rs)

Tests: crates/rtps/src/wire_types.rs::tests::the_entity_ids_of_table_9_2_are_those_of_the_table

Status: done — die Konstante trägt {{00,00,02},c7}; der Test prüft alle Werte der Table 9.2.

§9.3.1.3 Table 9.2 ENTITYID_SEDP_BUILTIN_PUBLICATIONS_ANNOUNCER

Spec: §9.3.1.3, S. 151, Table 9.2 — “ENTITYID_SEDP_BUILTIN_PUBLICATIONS_ANNOUNCER = {{00,00,03},c2}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::SEDP_BUILTIN_PUBLICATIONS_WRITER)

Tests: crates/rtps/src/wire_types.rs::tests::sedp_publications_writer_layout

Status: done

§9.3.1.3 Table 9.2 ENTITYID_SEDP_BUILTIN_PUBLICATIONS_DETECTOR

Spec: §9.3.1.3, S. 151, Table 9.2 — “ENTITYID_SEDP_BUILTIN_PUBLICATIONS_DETECTOR = {{00,00,03},c7}”.

Repo: EntityId::SEDP_BUILTIN_PUBLICATIONS_READER (crates/rtps/src/wire_types.rs)

Tests: crates/rtps/src/wire_types.rs::tests::the_entity_ids_of_table_9_2_are_those_of_the_table

Status: done — die Konstante trägt {{00,00,03},c7}; der Test prüft alle Werte der Table 9.2.

§9.3.1.3 Table 9.2 ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_ANNOUNCER

Spec: §9.3.1.3, S. 151, Table 9.2 — “ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_ANNOUNCER = {{00,00,04},c2}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::SEDP_BUILTIN_SUBSCRIPTIONS_WRITER)

Tests: crates/discovery/tests/vendor_discovery_frames.rs::fastdds_announcements_read_and_write_back

Status: done — der Test ordnet mitgeschnittene Ankündigungen nach dieser EntityId zu.

§9.3.1.3 Table 9.2 ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_DETECTOR

Spec: §9.3.1.3, S. 151, Table 9.2 — “ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_DETECTOR = {{00,00,04},c7}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::SEDP_BUILTIN_SUBSCRIPTIONS_READER)

Tests: crates/rtps/src/wire_types.rs::tests::sedp_subscriptions_reader_layout

Status: done

§9.3.1.3 Table 9.2 ENTITYID_SPDP_BUILTIN_PARTICIPANT_ANNOUNCER

Spec: §9.3.1.3, S. 151, Table 9.2 — “ENTITYID_SPDP_BUILTIN_PARTICIPANT_ANNOUNCER = {{00,01,00},c2}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::SPDP_BUILTIN_PARTICIPANT_WRITER)

Tests: crates/rtps/src/wire_types.rs::tests::spdp_builtin_participant_writer_layout

Status: done

§9.3.1.3 Table 9.2 ENTITYID_SPDP_BUILTIN_PARTICIPANT_DETECTOR

Spec: §9.3.1.3, S. 151, Table 9.2 — “ENTITYID_SPDP_BUILTIN_PARTICIPANT_DETECTOR = {{00,01,00},c7}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::SPDP_BUILTIN_PARTICIPANT_READER)

Tests: crates/rtps/src/wire_types.rs::tests::spdp_builtin_participant_reader_layout

Status: done

§9.3.1.3 Table 9.2 ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER

Spec: §9.3.1.3, S. 151, Table 9.2 — “ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER = {{00,02,00},c2}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::BUILTIN_PARTICIPANT_MESSAGE_WRITER)

Tests: crates/dcps/tests/cyclone_live_wlp.rs::cyclone_live_wlp_handshake

Status: done — der Test läuft nur mit --ignored und einem Cyclone-ddsperf.

§9.3.1.3 Table 9.2 ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER

Spec: §9.3.1.3, S. 151, Table 9.2 — “ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER = {{00,02,00},c7}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::BUILTIN_PARTICIPANT_MESSAGE_READER)

Tests: crates/dcps/tests/cyclone_live_wlp.rs::cyclone_live_wlp_handshake

Status: done — der Test läuft nur mit --ignored und einem Cyclone-ddsperf.

§9.3.1.3 Table 9.3 DDS-Security: Bereich {ff,00,00}–{ff,ff,ff}

Spec: §9.3.1.3, S. 152, Table 9.3 — “EntityIds that have both an entityKey in the range {ff, 00, 00} – {ff, ff, ff} and an entityKind in the range 0xc0-0xff (inclusive).”

Repo: crates/rtps/src/wire_types.rs (EntityId::SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER und die übrigen sicheren Builtin-EntityIds)

Tests: crates/rtps/src/wire_types.rs::tests::all_12_secure_entityids_roundtrip, crates/rtps/src/wire_types.rs::tests::secure_publications_writer_layout

Status: done

§9.3.1.3 Table 9.3 DDS-Security: {{00,02,01},c3} und {{00,02,01},c4}

Spec: §9.3.1.3, S. 152, Table 9.3 — “DDS-Security 1.1 — {{00, 02, 01}, c3} and {{00, 02, 01}, c4}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER, EntityId::BUILTIN_PARTICIPANT_STATELESS_MESSAGE_READER)

Tests: crates/discovery/src/security/stateless.rs::tests::writer_has_expected_entity_id, crates/discovery/src/security/stateless.rs::tests::reader_has_expected_entity_id

Status: done

§9.3.1.3 Table 9.3 DDS-XTypes: TypeLookup-EntityIds

Spec: §9.3.1.3, S. 152, Table 9.3 — “DDS-XTypes 1.2 — {{00, 03, 00}, c3}, {{00, 03, 00}, c4}, {{00, 03, 01}, c3}, {{00, 03, 01}, c4}”.

Repo: crates/rtps/src/wire_types.rs (EntityId::TL_SVC_REQ_WRITER, TL_SVC_REQ_READER, TL_SVC_REPLY_WRITER, TL_SVC_REPLY_READER)

Tests: crates/discovery/src/type_lookup/endpoints.rs::tests::entity_ids_match_spec_constants

Status: done

§9.3.1.4 Table 9.4 Client (0x05)

Spec: §9.3.1.4, S. 152, Table 9.4 — “Client — 0x05”; “These EntityIds should not be used by future versions of the protocol unless they are used with the same meaning as in versions prior to 2.2.”

Repo: —

Tests: —

Status: n/a (informative) — veraltete Kennung; ZeroDDS verwendet sie nicht.

§9.3.1.4 Table 9.4 Server (0x06)

Spec: §9.3.1.4, S. 152, Table 9.4 — “Server — 0x06”.

Repo: —

Tests: —

Status: n/a (informative) — veraltete Kennung; ZeroDDS verwendet sie nicht.

§9.3.1.4 Table 9.4 writerApplications

Spec: §9.3.1.4, S. 152, Table 9.4 — “writerApplications — {{00,00,01},c2}”.

Repo: —

Tests: —

Status: n/a (informative) — veraltete Kennung; ZeroDDS verwendet sie nicht.

§9.3.1.4 Table 9.4 readerApplications

Spec: §9.3.1.4, S. 152, Table 9.4 — “readerApplications — {{00,00,01},c7}”.

Repo: —

Tests: —

Status: n/a (informative) — veraltete Kennung; ZeroDDS verwendet sie nicht.

§9.3.1.4 Table 9.4 writerClients

Spec: §9.3.1.4, S. 152, Table 9.4 — “writerClients — {{00,00,05},c2}”.

Repo: —

Tests: —

Status: n/a (informative) — veraltete Kennung; ZeroDDS verwendet sie nicht.

§9.3.1.4 Table 9.4 readerClients

Spec: §9.3.1.4, S. 152, Table 9.4 — “readerClients — {{00,00,05},c7}”.

Repo: —

Tests: —

Status: n/a (informative) — veraltete Kennung; ZeroDDS verwendet sie nicht.

§9.3.1.4 Table 9.4 writerServices

Spec: §9.3.1.4, S. 152, Table 9.4 — “writerServices — {{00,00,06},c2}”.

Repo: —

Tests: —

Status: n/a (informative) — veraltete Kennung; ZeroDDS verwendet sie nicht.

§9.3.1.4 Table 9.4 readerServices

Spec: §9.3.1.4, S. 152, Table 9.4 — “readerServices — {{00,00,06},c7}”.

Repo: —

Tests: —

Status: n/a (informative) — veraltete Kennung; ZeroDDS verwendet sie nicht.

§9.3.1.4 Table 9.4 writerManagers

Spec: §9.3.1.4, S. 152, Table 9.4 — “writerManagers — {{00,00,07},c2}”.

Repo: —

Tests: —

Status: n/a (informative) — veraltete Kennung; ZeroDDS verwendet sie nicht.

§9.3.1.4 Table 9.4 readerManagers

Spec: §9.3.1.4, S. 152, Table 9.4 — “readerManagers — {{00,00,07},c7}”.

Repo: —

Tests: —

Status: n/a (informative) — veraltete Kennung; ZeroDDS verwendet sie nicht.

§9.3.1.4 Table 9.4 writerApplicationsSelf

Spec: §9.3.1.4, S. 152, Table 9.4 — “writerApplicationsSelf — {{00,00,08},c2}”.

Repo: —

Tests: —

Status: n/a (informative) — veraltete Kennung; ZeroDDS verwendet sie nicht.

§9.3.1.5 GUID_t

Spec: §9.3.1.5, S. 152 — “struct GUID_t { GuidPrefix_t guidPrefix; EntityId_t entityId; } ;”

Repo: crates/rtps/src/wire_types.rs (Guid)

Tests: crates/rtps/src/wire_types.rs::tests::guid_layout_is_prefix_then_entity_id

Status: done

§9.3.1.5 Erste zwei Oktette des guidPrefix = vendorId

Spec: §9.3.1.5, S. 152–153 — “implementations of the RTPS protocol shall set the first two bytes of the guidPrefix to match their assigned vendorId … guidPrefix[0] = vendorId[0] guidPrefix[1] = vendorId[1]”.

Repo: crates/rtps/src/wire_types.rs (GuidPrefix::zerodds); crates/dcps/src/participant.rs (random_guid_prefix)

Tests: crates/rtps/src/wire_types.rs::tests::guid_prefix_host_id_follows_the_vendor_id

Status: partial — die ersten zwei Oktette sind 01 F0, kein von der OMG zugewiesener Wert (blocked-Item unter §8.3.5.2). DcpsRuntime::start nimmt auch einen frei gewählten Prefix an; unter DDS-Security ersetzt der aus der Identität abgeleitete Prefix den gebildeten. Dessen erste 48 Bit legt DDS-Security 1.2 §10.3.3 Table 59 (validate_local_identity) fest: erstes Bit 1, dann 47 Bit aus dem SHA-256 des SubjectName; die VendorId steht dort nach der spezielleren Spec nicht (crates/security-pki/src/guid_adjust.rs, Test adjusted_prefix_sets_high_bit_and_is_deterministic_per_identity).

§9.3.1.5 GUID_UNKNOWN

Spec: §9.3.1.5, S. 153 — “#define GUID_UNKNOWN{ GUIDPREFIX_UNKNOWN, ENTITYID_UNKNOWN }”.

Repo: crates/rtps/src/wire_types.rs (Guid::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::guid_prefix_unknown_is_zero, crates/rtps/src/wire_types.rs::tests::entity_id_unknown_is_four_zero_octets

Status: done

§9.3.2.1 DomainId_t

Spec: §9.3.2.1, S. 153 — “typedef unsigned long DomainId_t;”

Repo: crates/rtps/src/participant_data.rs (domain_id: Option<u32>, PID_DOMAIN_ID mit 4 Oktetten)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§9.3.2.1 Time_t-Struktur

Spec: §9.3.2.1, S. 153 — “struct Time_t { unsigned long seconds; // time in seconds unsigned long fraction; // time in sec/2^32 };”

Repo: crates/rtps/src/header_extension.rs (HeTimestamp); crates/rtps/src/submessages.rs (InfoTimestampSubmessage)

Tests: crates/rtps/src/submessages.rs::tests::info_timestamp_roundtrip_le, crates/rtps/src/submessages.rs::tests::info_timestamp_roundtrip_be, crates/rtps/src/header_extension.rs::tests::roundtrip_all_fields_set_be

Status: done — seconds und fraction sind je ein unsigned long (HeTimestamp::seconds: u32), 4 + 4 Oktette in der Byte-Reihenfolge der Submessage; Sekundenwerte ab 2^31 bleiben positiv (der Test roundtrip_all_fields_set_be nutzt 0xFFFF_FFFD). §9.4.2.9 zeigt long seconds; es gilt die Struktur aus §9.3.2.1.

§9.3.2.1 Time_t: reservierte Werte und vorzeichenlose Sekunden

Spec: §9.3.2.1, S. 153 — “TIME_ZERO: seconds = 0, fraction = 0; TIME_INVALID: seconds = 0xffffffff, fraction = 0xffffffff; TIME_INFINITE: seconds = 0xffffffff, fraction = 0xfffffffe”.

Repo: crates/dcps/src/time.rs (time_to_he_timestamp, he_timestamp_to_time); crates/rtps/src/header_extension.rs (HeTimestamp, TIME_INVALID)

Tests: crates/dcps/src/time.rs::tests::the_reserved_time_t_values_cross_the_wire_as_the_spec_gives_them, crates/rtps/src/receiver_state.rs::tests::the_initial_state_is_the_one_of_table_8_17, crates/rtps/src/header_extension.rs::tests::roundtrip_all_fields_set_be

Status: done — Time::INVALID geht als {0xffffffff, 0xffffffff} und Time::INFINITE als {0xffffffff, 0xfffffffe} auf die Leitung und wird so zurückgelesen; HeTimestamp::seconds ist u32, TIME_INVALID hat Sekunden 0xFFFFFFFF. Die Aufrufer in dcps, xrce-agent und opcua-bridge sind angepasst (cargo check --tests und clippy grün). Ob ein anderer Hersteller die Sonderwerte als Quellzeitstempel sendet, ist nicht geprüft.

§9.3.2.1 Duration_t, DURATION_ZERO, DURATION_INFINITE

Spec: §9.3.2.1, S. 153 — “DURATION_ZERO: seconds = 0, fraction = 0; DURATION_INFINITE: seconds = 0x7fffffff, fraction = 0xffffffff; struct Duration_t { long seconds; unsigned long fraction; };”

Repo: crates/qos/src/duration.rs (Duration::INFINITE, Duration::ZERO)

Tests: crates/qos/src/duration.rs::tests::infinite_constant_matches_spec, crates/qos/src/duration.rs::tests::zero_is_default_and_zero

Status: done

§9.3.2.1 VendorId_t und VENDORID_UNKNOWN

Spec: §9.3.2.1, S. 153 — “VENDORID_UNKNOWN: VendorId_t[0] = 0, VendorId_t[1] = 0; typedef octet VendorId_t[2];”

Repo: crates/rtps/src/wire_types.rs (VendorId, VendorId::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::vendor_id_unknown_is_two_zero_octets, crates/rtps/src/wire_types.rs::tests::vendor_id_roundtrip

Status: done

§9.3.2.1 SEQUENCENUMBER_UNKNOWN

Spec: §9.3.2.1, S. 153 — “SEQUENCENUMBER_UNKNOWN: high = -1, low = 0”.

Repo: crates/rtps/src/wire_types.rs (SequenceNumber::UNKNOWN)

Tests: crates/rtps/src/wire_types.rs::tests::sequence_number_unknown_high_minus_one_low_zero

Status: done

§9.3.2.1 FragmentNumber_t

Spec: §9.3.2.1, S. 153 — “typedef unsigned long FragmentNumber_t;”

Repo: crates/rtps/src/wire_types.rs (FragmentNumber(u32))

Tests: crates/rtps/src/wire_types.rs::tests::fragment_number_roundtrip_le_be, crates/rtps/src/wire_types.rs::tests::fragment_number_wire_size_is_four

Status: done

§9.3.2.1 LOCATOR_KIND_INVALID, _RESERVED, _UDPv4, _UDPv6

Spec: §9.3.2.1, S. 153–154 — “const long LOCATOR_KIND_INVALID = -1; const long LOCATOR_KIND_RESERVED = 0; const long LOCATOR_KIND_UDPv4 = 1; const long LOCATOR_KIND_UDPv6 = 2;”

Repo: crates/rtps/src/wire_types.rs (LocatorKind::Invalid, Reserved, UdpV4, UdpV6)

Tests: crates/rtps/src/wire_types.rs::tests::locator_reserved_constant_kind_is_zero, crates/rtps/src/wire_types.rs::tests::locator_udp_v4_any_kind_is_one, crates/rtps/src/wire_types.rs::tests::locator_udp_v6_any_kind_is_two

Status: done

§9.3.2.1 LOCATOR_PORT_INVALID, LOCATOR_ADDRESS_INVALID, LOCATOR_INVALID

Spec: §9.3.2.1, S. 154 — “const unsigned long LOCATOR_PORT_INVALID = 0; LOCATOR_ADDRESS_INVALID: {0,…,0}; LOCATOR_INVALID: kind = LOCATOR_KIND_INVALID, port = LOCATOR_PORT_INVALID, address = LOCATOR_ADDRESS_INVALID”.

Repo: crates/rtps/src/wire_types.rs (Locator::INVALID)

Tests: crates/rtps/src/wire_types.rs::tests::locator_invalid_constant_matches_spec, crates/rtps/src/wire_types.rs::tests::locator_invalid_kind_decoded

Status: done

§9.3.2.1 Locator_t

Spec: §9.3.2.1, S. 154 — “struct Locator_t { long kind; unsigned long port; octet address[16]; };”

Repo: crates/rtps/src/wire_types.rs (Locator, Locator::to_bytes_le)

Tests: crates/rtps/src/wire_types.rs::tests::locator_udp_v4_layout, crates/rtps/src/wire_types.rs::tests::locator_roundtrip_le

Status: done

§9.3.2.1 BEST_EFFORT = 1, RELIABLE = 2

Spec: §9.3.2.1, S. 154 — “The values of the following constants as defined in the DDS Specification should be mapped to the below values before being sent on the wire. const long BEST_EFFORT = 1; const long RELIABLE = 2;”

Repo: crates/qos/src/policies/reliability.rs (ReliabilityKind::BestEffort = 1, Reliable = 2); crates/rtps/src/publication_data.rs

Tests: crates/rtps/src/publication_data.rs::tests::reliability_try_from_u32_rejects_unknown, crates/qos/src/policies/reliability.rs::tests::best_effort_lt_reliable

Status: done

§9.3.2.1 Count_t

Spec: §9.3.2.1, S. 154 — “typedef long Count_t;”

Repo: crates/rtps/src/submessages.rs (count: i32 in ACKNACK, HEARTBEAT, HEARTBEAT_FRAG, NACK_FRAG)

Tests: crates/rtps/src/submessages.rs::tests::acknack_submessage_roundtrip_le, crates/rtps/src/submessages.rs::tests::heartbeat_submessage_roundtrip_le

Status: done

§9.3.2.1 ProtocolVersion_t

Spec: §9.3.2.1, S. 154 — “struct ProtocolVersion_t { octet major; octet minor; };”

Repo: crates/rtps/src/wire_types.rs (ProtocolVersion)

Tests: crates/rtps/src/wire_types.rs::tests::protocol_version_roundtrip, crates/rtps/src/wire_types.rs::tests::protocol_version_aliases_match_spec

Status: done

§9.3.2.1 KeyHash_t, StatusInfo_t, ParameterId_t

Spec: §9.3.2.1, S. 154 — “typedef octet KeyHash_t[16]; typedef octet StatusInfo_t[4]; typedef short ParameterId_t;”

Repo: crates/rtps/src/inline_qos.rs (PID_KEY_HASH mit 16 Oktetten, PID_STATUS_INFO mit 4 Oktetten); crates/rtps/src/parameter_list.rs (Parameter::id: u16)

Tests: crates/rtps/src/submessages.rs::tests::data_frag_key_hash_roundtrips_both_byte_orders, crates/dcps/tests/lifecycle_wire_decode.rs::reader_push_lifecycle_disposed_sets_instance_state

Status: done — ParameterId_t ist als u16 geführt; die Bits 0x8000 und 0x4000 werden als Bitfelder ausgewertet (§9.4.2.11.2).

§9.3.2.1 ContentFilterProperty_t

Spec: §9.3.2.1, S. 154 — “struct ContentFilterProperty_t { string<256> contentFilteredTopicName; string<256> relatedTopicName; string<256> filterClassName; string filterExpression; sequence expressionParameters; };”

Repo: crates/rtps/src/subscription_data.rs (ContentFilterProperty)

Tests: crates/rtps/src/subscription_data.rs::tests::content_filter_property_roundtrip_le, crates/rtps/src/subscription_data.rs::tests::content_filter_names_are_bounded_by_string_256

Status: done — Reihenfolge, Kodierung und die Grenze von 256 Oktetten für die drei Namen.

§9.3.2.1 ContentFilterProperty_t: string<256>

Spec: §9.3.2.1, S. 154 — “string<256> contentFilteredTopicName; string<256> relatedTopicName; string<256> filterClassName;”

Repo: crates/rtps/src/subscription_data.rs (encode_content_filter_property_le, decode_content_filter_property); crates/dcps/src/participant.rs (create_contentfilteredtopic)

Tests: crates/rtps/src/subscription_data.rs::tests::content_filter_names_are_bounded_by_string_256

Status: done — Senden und Lesen begrenzen die drei Namen auf 256 Oktette; create_contentfilteredtopic lehnt einen längeren Namen ab. Ein ContentFilterProperty mit zu langem oder sonst unlesbarem Namen gilt als nicht vorhanden: der Reader wird ohne Filter angenommen (er filtert selbst), gezählt in DcpsRuntime::unreadable_content_filters und als sedp.content_filter.unreadable protokolliert.

§9.3.2.1 ContentFilterInfo_t, FilterResult_t, FilterSignature_t

Spec: §9.3.2.1, S. 154 — “typedef sequence FilterResult_t; typedef long FilterSignature_t[4]; … struct ContentFilterInfo_t { FilterResult_t filterResult; FilterSignatureSequence filterSignatures; };”

Repo: —

Tests: —

Status: open — die Typen fehlen im Code; Teil der optionalen Filterung auf der Writer-Seite (§8.7.3), die ZeroDDS nicht ausführt.

§9.3.2.1 Property_t und EntityName_t

Spec: §9.3.2.1, S. 154 — “struct Property_t { string name; string value; }; typedef string EntityName_t;”

Repo: crates/rtps/src/property_list.rs (WirePropertyList)

Tests: crates/rtps/src/property_list.rs::tests::single_property_roundtrip_le, crates/rtps/src/property_list.rs::tests::multi_property_roundtrip_be

Status: done — EntityName_t (PID_ENTITY_NAME) ist unter §9.6.3.2 geführt.

§9.3.2.1 OriginalWriterInfo_t

Spec: §9.3.2.1, S. 154 — “struct OriginalWriterInfo_t { GUID_t originalWriterGUID; SequenceNumber_t originalWriterSN; ParameterList originalWriterQos; };”

Repo: crates/rtps/src/inline_qos.rs (original_writer_info_param, find_original_writer_info)

Tests: crates/rtps/src/inline_qos.rs::tests::original_writer_info_param_24_byte_layout_le, crates/rtps/src/inline_qos.rs::tests::original_writer_info_roundtrip_le, crates/rtps/src/inline_qos.rs::tests::table_9_20_directed_write_original_writer_info_and_secure_group_info

Status: done — das Leitungsbild des Parameters sind originalWriterGUID und originalWriterSN, 24 Oktette (§9.6.4.7, Table 8.89 nennt dieselben zwei Attribute); originalWriterQos aus der IDL-Struktur hat in Leitungsbild und Table 8.89 keine Entsprechung. Sende- und Empfangspfad sind unter §8.7.9 done.

§9.3.2.1 GroupDigest_t

Spec: §9.3.2.1, S. 155 — “typedef octet GroupDigest_t[4];”

Repo: crates/rtps/src/group_digest.rs (GroupDigest, GroupDigest::of_entities)

Tests: crates/rtps/src/group_digest.rs::tests::two_writers_digest_as_section_9_3_2_5_computes_it, crates/rtps/src/group_digest.rs::tests::the_digest_does_not_depend_on_the_order_given, crates/rtps/src/group_digest.rs::tests::the_empty_group_is_zero_and_not_the_hash_of_an_empty_sequence

Status: done

§9.3.2.1 BuiltinEndpointSet_t (IDL)

Spec: §9.3.2.1, S. 155 — “bitmask BuiltinEndpointSet_t { @position(0) DISC_BUILTIN_ENDPOINT_PARTICIPANT_ANNOUNCER, … @position(29) DISC_BUILTIN_ENDPOINT_TOPICS_DETECTOR };”

Repo: crates/rtps/src/participant_data.rs (endpoint_flag)

Tests: crates/rtps/src/participant_data.rs::tests::endpoint_flag_bit_positions_match_spec

Status: done — die Positionen sind unter §9.3.2.12 einzeln geführt.

§9.3.2.1 BuiltinEndpointQos_t

Spec: §9.3.2.1, S. 155 — “bitmask BuiltinEndpointQos_t { @position(0) BEST_EFFORT_PARTICIPANT_MESSAGE_DATA_READER };”

Repo: crates/rtps/src/participant_data.rs (builtin_endpoint_qos::BEST_EFFORT_PARTICIPANT_MESSAGE_DATA_READER)

Tests: crates/rtps/src/participant_data.rs::tests::manual_liveliness_count_and_builtin_endpoint_qos_go_out_and_read_back, crates/dcps/src/wlp.rs::tests::the_reader_is_treated_as_builtin_endpoint_qos_says

Status: done — Bitmaske mit @position(0) BEST_EFFORT_PARTICIPANT_MESSAGE_DATA_READER.

§9.3.2.1 ProtocolId_t (PROTOCOL_RTPS)

Spec: §9.3.2.1, S. 155 — “PROTOCOL_RTPS: ProtocolId_t[0] = ‘R’ … ProtocolId_t[3] = ‘S’; typedef octet ProtocolId_t[4];”

Repo: crates/rtps/src/header.rs (RTPS_MAGIC)

Tests: crates/rtps/src/header.rs::tests::header_layout_first_four_bytes_are_rtps_magic

Status: done

§9.3.2.1 MessageLength_t und MESSAGE_LENGTH_INVALID

Spec: §9.3.2.1, S. 155 — “typedef unsigned long MessageLength_t; const MessageLength_t MESSAGE_LENGTH_INVALID = 0;”

Repo: crates/rtps/src/header_extension.rs (message_length: Option<u32>, MESSAGE_LENGTH_INVALID)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_message_length_only_le, crates/rtps/src/datagram.rs::tests::a_header_extension_announcing_message_length_invalid_refuses_the_message

Status: done — u32, 32 Bit ohne Vorzeichen; MESSAGE_LENGTH_INVALID ist 0 und der Anfangswert des Receivers (None). Eine HeaderExtension mit diesem Wert ist ungültig (messageLength kleiner als RTPS Header und HeaderExtension, §8.3.7.3), die ganze Nachricht wird abgewiesen.

§9.3.2.1 UExtension4_t, WExtension8_t, Checksum32_t, Checksum64_t, Checksum128_t

Spec: §9.3.2.1, S. 155 — “typedef octet UExtension4_t[4]; typedef octet WExtension8_t[8]; typedef octet Checksum32_t[4]; typedef octet Checksum64_t[8]; typedef octet Checksum128_t[16];”

Repo: crates/rtps/src/header_extension.rs (uextension4: [u8; 4], wextension8: [u8; 8], ChecksumValue)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_all_fields_set_le, crates/rtps/src/header_extension.rs::tests::checksum_kind_wire_size

Status: done — die Byte-Reihenfolge der Prüfsummen ist unter §9.4.2.15 geführt.

§9.3.2.2 Time_t im NTP-Format

Spec: §9.3.2.2, S. 156 — “time = seconds + (fraction / 2^(32))”.

Repo: crates/dcps/src/time.rs (time_to_he_timestamp, he_timestamp_to_time); crates/qos/src/duration.rs (fraction_of_nanosec)

Tests: crates/qos/src/duration.rs::tests::a_whole_nanosecond_survives_the_way_there_and_back, crates/rtps/tests/reliable_e2e.rs::e2e_source_timestamp_round_trips

Status: done

§9.3.2.3 Duration_t im NTP-Format

Spec: §9.3.2.3, S. 156 — “time = seconds + (fraction / 2^(32))”. “Versions of the RTPS specification previous to version 2.4 did not specify the representation of Duration_t, therefore implementations should take into account the vendor and protocol version when interpreting these fields.”

Repo: crates/qos/src/duration.rs (Duration, to_bytes_le, from_bytes_le)

Tests: crates/qos/src/duration.rs::tests::from_millis_splits_correctly, crates/qos/src/duration.rs::tests::to_from_bytes_le_roundtrip

Status: done — eine Unterscheidung nach Hersteller und Protokollversion vor 2.4 gibt es nicht.

§9.3.2.4 Locator_t: IPv4-Adresse

Spec: §9.3.2.4, S. 156 — “If the Locator_t kind is LOCATOR_KIND_UPDv4, the address contains an IPv4 address. In this case, the leading 12 octets of the address must be zero.”

Repo: crates/rtps/src/wire_types.rs (Locator::udp_v4)

Tests: crates/rtps/src/wire_types.rs::tests::locator_udp_v4_layout

Status: done

§9.3.2.4 Locator_t: IPv6-Adresse

Spec: §9.3.2.4, S. 156 — “If the Locator_t kind is LOCATOR_KIND_UPDv6, the address contains an IPv6 address.”

Repo: crates/rtps/src/wire_types.rs (Locator::udp_v6)

Tests: crates/rtps/src/wire_types.rs::tests::locator_udp_v6_constructor_keeps_full_address, crates/rtps/src/wire_types.rs::tests::locator_udp_v6_roundtrip_le

Status: done

§9.3.2.4 Bereiche der Locator-Arten

Spec: §9.3.2.4, S. 156 — “0x00000003 - 0x01ffffff (inclusive) are reserved for vendor-specific Locator_t kinds … 0x02000000 - 0x02ffffff (inclusive) are reserved for future use by the RTPS specification … 0x03000000 and greater are reserved for Locator_t kinds that identify a transport developed by a third-party”.

Repo: crates/rtps/src/wire_types.rs (LocatorKind, LocatorKind::from_i32, set_tcp_kinds_fast_dds); crates/dcps/src/runtime.rs (RuntimeConfig::tcp_locator_kinds_fast_dds, Schlüssel transport.tcp_locator_kinds)

Tests: crates/rtps/src/wire_types.rs::tests::the_zerodds_locator_kinds_are_in_the_vendor_specific_range, crates/rtps/src/wire_types.rs::tests::the_tcp_kinds_are_vendor_range_by_default_and_fast_dds_by_setting, crates/rtps/src/wire_types.rs::tests::locator_kind_rejects_unknown, crates/transport-tcp/src/tcp_transport.rs::tests::locator_kinds_are_zerodds_vendor_range_values, crates/dcps/tests/runtime_config_layering.rs::the_tcp_locator_kinds_are_a_setting, crates/transport-shm/src/posix.rs::tests::locator_kind_is_the_vendor_reserved_shm_value, crates/transport-uds/src/lib.rs::tests::locator_kind_is_the_vendor_reserved_uds_value, crates/rtps/src/submessages.rs::tests::info_reply_leaves_out_a_locator_of_a_kind_it_does_not_know

Status: done — alle Arten außer UDPv4 (1) und UDPv6 (2) liegen im Herstellerbereich 3 bis 0x01ffffff: Shm, Uds, Tsn (0x01F0_0001 bis 0x01F0_0003) und jetzt auch Tcpv4 (0x01F0_0004) und Tcpv6 (0x01F0_0005). Die Werte 4 und 8 von Fast DDS (und der DDS-TCP-PSM) sendet ZeroDDS nur mit der benannten Einstellung transport.tcp_locator_kinds: fast-dds (Umgebung ZERODDS_TCP_LOCATOR_KINDS, Man-Seite, Beispielkonfiguration); gelesen werden beide Werte. Eine Art, die der Empfänger nicht kennt, macht eine INFO_REPLY nicht ungültig, der Locator entfällt. Erwartetes Verhalten von Fast DDS: mit fast-dds erkennt es die TCP-Locatoren von ZeroDDS (Art 4 und 8); ohne die Einstellung ignoriert es die Arten im Herstellerbereich und baut keine TCP-Verbindung zu ZeroDDS auf. Nicht gemessen.

§9.3.2.5 GroupDigest_t

Spec: §9.3.2.5, S. 156 — “The GroupDigest_t is computed from an EntityIdSet_t by first computing a 128 bit MD5 Digest (IETF RFC 1321) applied to the CDR Big-Endian serialization of the structure EntityIdSet_t. The GroupDigest_t is the leading 4 octets of the MD5 Digest. The empty group is represented by a zero value of the GroupDigest_t.”

Repo: crates/rtps/src/group_digest.rs (GroupDigest, GroupDigest::of_entities)

Tests: crates/rtps/src/group_digest.rs::tests::two_writers_digest_as_section_9_3_2_5_computes_it, crates/rtps/src/group_digest.rs::tests::the_digest_does_not_depend_on_the_order_given, crates/rtps/src/group_digest.rs::tests::the_empty_group_is_zero_and_not_the_hash_of_an_empty_sequence

Status: done

§9.3.2.6 Checksum32_t, Checksum64_t, Checksum128_t

Spec: §9.3.2.6, S. 157 — “Checksum32_t represents a 32-bit checksum. Checksum64_t, and Checksum128_t represent a 64-bit, and 128-bit checksum, respectively.”

Repo: crates/rtps/src/header_extension.rs (ChecksumValue::Crc32c, Crc64, Md5)

Tests: crates/rtps/src/header_extension.rs::tests::checksum_kind_wire_size, crates/rtps/src/header_extension.rs::tests::checksum_value_kind_matches

Status: done

§9.3.2.7 MessageLength_t

Spec: §9.3.2.7, S. 157 — “This type is used to represent the length of an RTPS message. The representation uses a 32-bit unsigned integer.”

Repo: crates/rtps/src/header_extension.rs (message_length: Option<u32>)

Tests: crates/rtps/src/header_extension.rs::tests::wire_layout_le_message_length_correct, crates/rtps/src/header_extension.rs::tests::wire_layout_be_message_length_correct

Status: done

§9.3.2.8 UExtension4_t

Spec: §9.3.2.8, S. 157 — “This type is used to represent an undefined 4-byte value.”

Repo: crates/rtps/src/header_extension.rs (uextension4: [u8; 4])

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_uextension4_be

Status: done

§9.3.2.9 WExtension8_t

Spec: §9.3.2.9, S. 157 — “This type is used to represent an undefined 8-byte value.”

Repo: crates/rtps/src/header_extension.rs (wextension8: [u8; 8])

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_wextension8_le

Status: done

§9.3.2.10 SequenceNumber_t

Spec: §9.3.2.10, S. 157 — “struct SequenceNumber_t { long high; unsigned long low; }; … sequence_number = low + high * 2^(32)”.

Repo: crates/rtps/src/wire_types.rs (SequenceNumber::to_bytes_le, from_bytes_le, to_bytes_be, from_bytes_be)

Tests: crates/rtps/src/wire_types.rs::tests::sequence_number_split_high_low, crates/rtps/src/wire_types.rs::tests::sequence_number_roundtrip_be

Status: done

§9.3.2.11 ChangeCount_t

Spec: §9.3.2.11, S. 157 — “This type is used to represent a 64-bit count. … struct ChangeCount_t { long high; unsigned long low; }; … change_count = low + high * 2^(32)”.

Repo: crates/rtps/src/submessages.rs (GapSubmessage::filtered_count: Option<u64>, write_body, read_body)

Tests: crates/rtps/src/submessages.rs::tests::gap_filtered_count_is_eight_octets_high_then_low, crates/rtps/src/submessages.rs::tests::gap_with_filtered_count_roundtrip_le

Status: done — ChangeCount_t ist als u64 geführt: high (long) und low (unsigned long) sind acht Oktette in der Byte-Reihenfolge der Submessage, change_count = low + high * 2^32; ein negatives high ist kein Zähler und wird abgewiesen.

§9.3.2.12 BuiltinEndpointSet_t: Positionen 0 bis 5

Spec: §9.3.2.12, S. 157–158 — “@position(0) DISC_BUILTIN_ENDPOINT_PARTICIPANT_ANNOUNCER, @position(1) …_PARTICIPANT_DETECTOR, @position(2) …_PUBLICATIONS_ANNOUNCER, @position(3) …_PUBLICATIONS_DETECTOR, @position(4) …_SUBSCRIPTIONS_ANNOUNCER, @position(5) …_SUBSCRIPTIONS_DETECTOR”.

Repo: crates/rtps/src/participant_data.rs (endpoint_flag::PARTICIPANT_ANNOUNCER bis SUBSCRIPTIONS_DETECTOR)

Tests: crates/rtps/src/participant_data.rs::tests::endpoint_flag_bit_positions_match_spec

Status: done

§9.3.2.12 BuiltinEndpointSet_t: Positionen 6 bis 9 veraltet

Spec: §9.3.2.12, S. 158 — “/* Positions 6-9 were deprecated in version 2.4 */“; §9.3.2.1:”These bits should not be used by versions of the protocol equal to or newer than the deprecated version”.

Repo: crates/rtps/src/participant_data.rs (ALL_STANDARD ohne die Bits 6 bis 9)

Tests: crates/rtps/src/participant_data.rs::tests::endpoint_flag_all_standard_excludes_secure_bits, crates/dcps/src/runtime.rs::tests::spdp_announces_standard_bits_by_default

Status: done

§9.3.2.12 BuiltinEndpointSet_t: Positionen 10 und 11

Spec: §9.3.2.12, S. 158 — “@position(10) BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER, @position(11) BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_READER”.

Repo: crates/rtps/src/participant_data.rs (endpoint_flag::PARTICIPANT_MESSAGE_DATA_WRITER, …_READER)

Tests: crates/rtps/src/participant_data.rs::tests::endpoint_flag_bit_positions_match_spec

Status: done

§9.3.2.12 BuiltinEndpointSet_t: Positionen 12 bis 15 (XTypes)

Spec: §9.3.2.12, S. 158 — “Positions 12-15 are reserved by DDS-XTypes 1.2 and its revisions thereof”.

Repo: crates/rtps/src/participant_data.rs (endpoint_flag::TYPE_LOOKUP_REQUEST, TYPE_LOOKUP_REPLY)

Tests: crates/dcps/tests/type_lookup_e2e.rs::announces_type_lookup_endpoints_in_spdp, crates/discovery/src/capabilities.rs::tests::type_lookup_capabilities_require_the_four_distinct_vendor_bits

Status: done

§9.3.2.12 BuiltinEndpointSet_t: Positionen 16 bis 27 (DDS-Security)

Spec: §9.3.2.12, S. 158 — “Positions 16-27 are reserved by DDS-Security 1.1 and revisions thereof”.

Repo: crates/rtps/src/participant_data.rs (endpoint_flag::ALL_SECURE)

Tests: crates/rtps/src/participant_data.rs::tests::endpoint_flag_all_secure_covers_bits_16_to_27

Status: done

§9.3.2.12 BuiltinEndpointSet_t: Positionen 28 und 29

Spec: §9.3.2.12, S. 158 — “@position(28) DISC_BUILTIN_ENDPOINT_TOPICS_ANNOUNCER, @position(29) DISC_BUILTIN_ENDPOINT_TOPICS_DETECTOR”.

Repo: crates/rtps/src/participant_data.rs (endpoint_flag::TOPICS_ANNOUNCER, TOPICS_DETECTOR)

Tests: crates/rtps/src/participant_data.rs::tests::endpoint_flag_bit_positions_match_spec, crates/discovery/src/sedp/stack.rs::tests::the_topics_bits_wire_the_topics_writer_and_reader

Status: done

§9.4.1 Submessages auf 32-Bit-Grenzen

Spec: §9.4.1, S. 158 — “The PSM aligns each Submessage on a 32-bit boundary with respect to the start of the Message.”

Repo: crates/rtps/src/message_builder.rs (MessageBuilder::check_aligned)

Tests: crates/rtps/src/message_builder.rs::tests::nothing_is_appended_after_an_unaligned_submessage, crates/rtps/src/message_builder.rs::tests::four_small_datas_aggregate_into_one_datagram

Status: done — der Decoder verlangt die Ausrichtung beim Empfang nicht.

§9.4.1 Länge der Nachricht aus dem Transport

Spec: §9.4.1, S. 158 — “A Message has a well-known length. This length is not sent explicitly by the RTPS protocol but is part of the underlying transport with which Messages are sent. In the case of UDP/IP, the length of the Message is the length of the UDP payload.”

Repo: crates/rtps/src/datagram.rs (decode_datagram: Länge des übergebenen Datagramms)

Tests: crates/rtps/src/datagram.rs::tests::decode_handles_last_submessage_zero_length, crates/transport-udp/src/udp_transport.rs::tests::loopback_send_and_recv_delivers_datagram

Status: done

§9.4.2 Abbildung der Submessage-Elemente

Spec: §9.4.2, S. 158 — “This sub clause describes the PSM mapping for each of the SubmessageElements defined by the PIM.”

Repo: —

Tests: —

Status: n/a (informative) — Einleitung; die Elemente folgen einzeln.

§9.4.2.1 EntityId

Spec: §9.4.2.1, S. 159 — “typedef EntityId_t EntityId;” Leitungsbild octet value[4].

Repo: crates/rtps/src/wire_types.rs (EntityId::to_bytes, EntityId::from_bytes)

Tests: crates/rtps/src/wire_types.rs::tests::entity_id_roundtrip

Status: done

§9.4.2.2 GuidPrefix

Spec: §9.4.2.2, S. 159 — “typedef GuidPrefix_t GuidPrefix;” Leitungsbild octet value[12].

Repo: crates/rtps/src/wire_types.rs (GuidPrefix::to_bytes)

Tests: crates/rtps/src/wire_types.rs::tests::guid_prefix_roundtrip, crates/rtps/src/header.rs::tests::header_guid_prefix_at_bytes_8_to_19

Status: done

§9.4.2.3 VendorId

Spec: §9.4.2.3, S. 159 — “typedef VendorId_t VendorId;” Leitungsbild octet vendorId[2].

Repo: crates/rtps/src/wire_types.rs (VendorId::to_bytes)

Tests: crates/rtps/src/wire_types.rs::tests::vendor_id_roundtrip, crates/rtps/src/header.rs::tests::header_vendor_id_at_bytes_6_7

Status: done

§9.4.2.4 ProtocolVersion

Spec: §9.4.2.4, S. 159–160 — “typedef ProtocolVersion_t ProtocolVersion;” Leitungsbild octet major | octet minor.

Repo: crates/rtps/src/wire_types.rs (ProtocolVersion::to_bytes)

Tests: crates/rtps/src/wire_types.rs::tests::protocol_version_roundtrip, crates/rtps/src/header.rs::tests::header_protocol_version_at_bytes_4_5

Status: done

§9.4.2.5 SequenceNumber

Spec: §9.4.2.5, S. 160 — Leitungsbild long high, unsigned long low.

Repo: crates/rtps/src/wire_types.rs (SequenceNumber::to_bytes_le, to_bytes_be)

Tests: crates/rtps/src/wire_types.rs::tests::sequence_number_roundtrip_le, crates/rtps/src/wire_types.rs::tests::sequence_number_roundtrip_be

Status: done

§9.4.2.6 SequenceNumberSet: Struktur und Leitungsbild

Spec: §9.4.2.6, S. 160–161 — “struct SequenceNumberSet { SequenceNumber_t bitmapBase; LongSeq8 bitmap; };” Leitungsbild: bitmapBase, unsigned long numBits, long bitmap[M] mit “M = (numBits+31)/32”. “The numBits field encodes both the number of significant bits and the number of bitmap elements.”

Repo: crates/rtps/src/submessages.rs (SequenceNumberSet::write_to, read_from)

Tests: crates/rtps/src/submessages.rs::tests::snset_wire_size_zero_bits_is_12_bytes, crates/rtps/src/submessages.rs::tests::snset_wire_size_33_bits_is_20_bytes, crates/rtps/src/submessages.rs::tests::snset_roundtrip_be

Status: done

§9.4.2.6 SequenceNumberSet: Zugehörigkeit nach Bitposition

Spec: §9.4.2.6, S. 160 — “(bitmap[deltaN/ 32] & (1 << (31 - deltaN%32))) == (1 << (31 - deltaN%32)) where deltaN = seqNum - seqNumSet.bitmapBase”; “In the bitmap, the bit corresponding to sequence number bitmapBase is on the left.”

Repo: crates/rtps/src/submessages.rs (SequenceNumberSet::from_missing, iter_set: Bit 31 - offset % 32)

Tests: crates/rtps/tests/proptest_roundtrip.rs::seqnum_set_iter_matches_missing, crates/rtps/src/submessages.rs::tests::snset_roundtrip_le

Status: done

§9.4.2.6 SequenceNumberSet: Gültigkeit

Spec: §9.4.2.6, S. 160 — “A valid SequenceNumberSet must satisfy the following conditions: bitmapBase >= 1; 0 <= numBits <= 256; there are M=(numBits+31)/32 longs containing the pertinent bits”.

Repo: crates/rtps/src/submessages.rs (SequenceNumberSet::read_from)

Tests: crates/rtps/src/submessages.rs::validity_tests::gap_and_sequence_number_set_validity_rules, crates/rtps/src/submessages.rs::tests::seqnumset_rejects_num_bits_above_256, crates/rtps/src/submessages.rs::tests::snset_decode_rejects_truncated_bitmap, crates/rtps/tests/vendor_frames.rs::the_empty_acknack_of_opendds_and_rti_is_invalid_by_default, crates/rtps/tests/vendor_frames.rs::opendds_session_re_encodes_byte_for_byte, crates/rtps/tests/vendor_frames.rs::rti_session_re_encodes_byte_for_byte, crates/rtps/src/submessages.rs::validity_tests::the_empty_set_with_base_zero_is_accepted_only_on_request

Status: done — bitmapBase >= 1, numBits <= 256 und die Zahl der Bitmap-Wörter werden geprüft. Vendor-Form: OpenDDS 3.34.0 und RTI Connext 7.7.0 senden als ACKNACK eines Readers ohne Samples readerSNState 0/0: (bitmapBase 0, numBits 0; gemessen in tools/wire-capture/rtps-sessions: 40 und 8 ACKNACK). Standard: ungültig. Die Einstellung wire.accept_empty_acknack_base_zero (Env ZERODDS_WIRE_ACCEPT_EMPTY_ACKNACK_BASE_ZERO, Standard false) nimmt genau diese leere Menge in einem ACKNACK an, prozessweit.

§9.4.2.6 Table 9.5 Beispiel 1234/12:00110

Spec: §9.4.2.6, S. 161, Table 9.5 — “Example of bitmap: meaning of “1234/12:00110””.

Repo: crates/rtps/src/submessages.rs (SequenceNumberSet: iter_set, write_to, read_from)

Tests: crates/rtps/src/submessages.rs::tests::the_bitmap_1234_12_00110_of_table_9_5_names_1236_and_1237

Status: done — bitmapBase 1234, numBits 12, Bits 00110: die Nummern 1236 und 1237 sind gesetzt, 1234, 1235 und 1238 bis 1245 nicht; das Bit für bitmapBase steht links (höchstwertiges Bit des ersten Worts). Der Test schreibt und liest das Beispiel in beiden Byte-Reihenfolgen.

§9.4.2.7 FragmentNumber

Spec: §9.4.2.7, S. 161 — “typedef FragmentNumber_t FragmentNumber;” Leitungsbild unsigned long value.

Repo: crates/rtps/src/wire_types.rs (FragmentNumber::to_bytes_le)

Tests: crates/rtps/src/wire_types.rs::tests::fragment_number_roundtrip_le_be

Status: done

§9.4.2.8 FragmentNumberSet: Struktur und Leitungsbild

Spec: §9.4.2.8, S. 161–162 — “struct FragmentNumberSet { FragmentNumber_t bitmapBase; LongSeq8 bitmap; };” “The interpretation matches that of a SequenceNumberSet.” Leitungsbild: bitmapBase, numBits, long bitmap[M].

Repo: crates/rtps/src/submessages.rs (FragmentNumberSet::write_to, read_from)

Tests: crates/rtps/src/submessages.rs::tests::fnset_wire_size_formula, crates/rtps/src/submessages.rs::tests::fnset_roundtrip_be, crates/rtps/src/submessages.rs::tests::fnset_rejects_num_bits_above_256

Status: done

§9.4.2.8 FragmentNumberSet: Gültigkeit

Spec: §9.4.2.8, S. 162 — “The interpretation matches that of a SequenceNumberSet.” (§9.4.2.6: “bitmapBase >= 1”, “0 <= numBits <= 256”).

Repo: crates/rtps/src/submessages.rs (FragmentNumberSet::read_from)

Tests: crates/rtps/src/submessages.rs::validity_tests::fragment_submessages_validity_rules, crates/rtps/src/submessages.rs::tests::fnset_rejects_num_bits_above_256

Status: done — bitmapBase >= 1 und numBits <= 256 werden geprüft.

§9.4.2.9 Timestamp

Spec: §9.4.2.9, S. 162 — “typedef Time_t Timestamp;” Leitungsbild long seconds, unsigned long fraction.

Repo: crates/rtps/src/submessages.rs (InfoTimestampSubmessage, timestamp_body)

Tests: crates/rtps/src/submessages.rs::tests::info_timestamp_roundtrip_le, crates/rtps/src/submessages.rs::tests::info_timestamp_roundtrip_be

Status: done — HeTimestamp::seconds ist i32 wie im Leitungsbild; §9.3.2.1 nennt unsigned long seconds (open-Item unter §9.3.2.1 Time_t).

§9.4.2.10 LocatorList

Spec: §9.4.2.10, S. 162–163 — “typedef sequence<Locator_t, 8> LocatorList;” Leitungsbild unsigned long numLocators, dann die Locatoren mit long kind, unsigned long port, octet address[16].

Repo: crates/rtps/src/submessages.rs (InfoReplySubmessage, read_locator_list)

Tests: crates/rtps/src/submessages.rs::tests::info_reply_with_multicast_roundtrip_be, crates/rtps/src/submessages.rs::tests::info_reply_empty_unicast_list_is_valid, crates/rtps/src/submessages.rs::validity_tests::info_reply_locator_list_holds_at_most_8_locators

Status: done — Leitungsbild und die Grenze von 8 Locatoren stimmen.

§9.4.2.10 LocatorList höchstens 8 Locatoren

Spec: §9.4.2.10, S. 162 — “typedef sequence<Locator_t, 8> LocatorList;”

Repo: crates/rtps/src/submessages.rs (InfoReplySubmessage::read_locator_list)

Tests: crates/rtps/src/submessages.rs::validity_tests::info_reply_locator_list_holds_at_most_8_locators

Status: done — eine Liste mit mehr als 8 Locatoren wird abgewiesen.

§9.4.2.11 Parameter: Ausrichtung und Länge

Spec: §9.4.2.11, S. 163 — “Each Parameter within the ParameterList starts aligned on a 4-byte boundary with respect to the start of the ParameterList.” “The length encodes the number of octets following the length to reach the ID of the next parameter … the length is always a multiple of four.”

Repo: crates/rtps/src/parameter_list.rs (ParameterList::to_bytes, from_bytes_with_consumed: length % 4 != 0 wird abgewiesen)

Tests: crates/rtps/src/parameter_list.rs::tests::decode_rejects_non_aligned_length, crates/rtps/src/parameter_list.rs::tests::parameter_value_is_padded_to_4_bytes

Status: done

§9.4.2.11 Parameter: CDR je Wert neu ausgerichtet

Spec: §9.4.2.11, S. 163 — “The value contains the CDR representation of the Parameter type that corresponds to the specified parameterId. For alignment purposes, the CDR stream is logically reset for each parameter value”.

Repo: crates/rtps/src/publication_data.rs, crates/rtps/src/participant_data.rs (jeder Wert wird ab Offset 0 kodiert)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full, crates/discovery/tests/vendor_discovery_frames.rs::cyclone_announcements_read_and_write_back

Status: done

§9.4.2.11 Mehrere Parameter mit derselben ParameterId

Spec: §9.4.2.11, S. 163 — “The ParameterList may contain multiple Parameters with the same value for the parameterId. This is used to provide a collection of values for that kind of Parameter.”

Repo: crates/rtps/src/parameter_list.rs (ParameterList::find_all)

Tests: crates/rtps/src/participant_data.rs::tests::decode_retains_all_repeated_unicast_locators_in_order_le_and_be, crates/rtps/src/parameter_list.rs::tests::roundtrip_multiple_parameters

Status: done

§9.4.2.11 PID_SENTINEL

Spec: §9.4.2.11, S. 164 — “#define PID_SENTINEL (1)”; “The PID_SENTINEL is used to terminate the parameter list and its length is ignored.”

Repo: crates/rtps/src/parameter_list.rs (pid::SENTINEL; from_bytes_with_consumed endet beim Sentinel ohne Auswertung der Länge)

Tests: crates/rtps/src/parameter_list.rs::tests::empty_parameter_list_is_just_sentinel, crates/rtps/src/parameter_list.rs::tests::decode_rejects_missing_sentinel

Status: done

§9.4.2.11 PID_PAD

Spec: §9.4.2.11, S. 164 — “#define PID_PAD (0)”; “The PID_PAD is used to enforce alignment of the parameter that follows and its length can be anything (as long as it is a multiple of 4).”

Repo: crates/rtps/src/parameter_list.rs (pid::PAD, ParameterList::from_bytes_with_consumed)

Tests: crates/rtps/src/parameter_list.rs::tests::pid_pad_is_skipped

Status: done

§9.4.2.11 Sentinel in der HeaderExtension nicht verlangt

Spec: §9.4.2.11, S. 164 — “The presence of the PID_SENTINEL is not required in the ParameterList that appears in the HeaderExtension. See 9.4.5.2. The presence of the PID_SENTINEL is required in all other cases.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::decode_body, ParameterList::from_bytes_sentinel_optional)

Tests: crates/rtps/src/header_extension.rs::tests::decode_takes_a_parameter_list_without_sentinel, crates/rtps/src/parameter_list.rs::tests::decode_rejects_missing_sentinel

Status: done — die Parameter der HeaderExtension werden ohne PID_SENTINEL gelesen; in allen anderen Fällen wird der Sentinel verlangt (decode_rejects_missing_sentinel).

§9.4.2.11 Table 9.6 Bit 0x8000: herstellerspezifisch

Spec: §9.4.2.11, S. 165, Table 9.6 — “ParameterId & 8000 — 0 — Reserved ParameterId. — 1 — Vendor-specific ParameterId. Will not be recognized by other vendors’ implementations.”

Repo: crates/rtps/src/parameter_list.rs (VENDOR_SPECIFIC_BIT); crates/rtps/src/publication_data.rs (Herstellerparameter nach VendorId)

Tests: crates/discovery/tests/vendor_discovery_frames.rs::rti_announcements_read_and_write_back, crates/rtps/src/parameter_list.rs::tests::a_vendor_specific_must_understand_pid_of_another_vendor_is_an_error

Status: done

§9.4.2.11 Table 9.6 Bit 0x4000 = 0: unbekannt überspringen

Spec: §9.4.2.11, S. 165, Table 9.6 — “ParameterId & 4000 — 0 — If the ParameterId is not recognized, skip and ignore the parameter.”

Repo: crates/rtps/src/parameter_list.rs (validate_must_understand_in_data_pipeline); Decoder in crates/rtps/src/publication_data.rs

Tests: crates/rtps/src/publication_data.rs::tests::unknown_pids_are_skipped, crates/rtps/src/parameter_list.rs::tests::validate_must_understand_in_data_pipeline_optional_unknown_pid_passes

Status: done

§9.4.2.11 Table 9.6 Bit 0x4000 = 1: unbekannt als Fehler

Spec: §9.4.2.11, S. 165, Table 9.6 — “1 — If the ParameterId is not recognized, treat it as an error. If the ParameterId appears in the HeaderExtension, ignore the entire RTPS message. If the ParameterId appears in any other Submessage, ignore the Submessage and continue with the next Submessage in the RTPS message, if any.”

Repo: crates/rtps/src/datagram.rs (decode_submessage); crates/rtps/src/parameter_list.rs (validate_must_understand_in_data_pipeline, is_known_vendor_pid)

Tests: crates/rtps/src/datagram.rs::tests::a_data_with_an_unknown_must_understand_pid_is_skipped, crates/rtps/src/datagram.rs::tests::a_data_with_a_vendor_specific_must_understand_pid_is_skipped, crates/rtps/src/parameter_list.rs::tests::a_vendor_specific_must_understand_pid_of_another_vendor_is_an_error

Status: done — in der HeaderExtension wird die ganze Nachricht verworfen; eine DATA oder DATA_FRAG mit einem nicht erkannten PID mit Bit 0x4000 wird übersprungen und die nächste Submessage gelesen. Das gilt auch im herstellerspezifischen Bereich (Bit 0x8000): erkannt werden dort nur die PIDs von ZeroDDS (0x8001, 0x8002) von einem ZeroDDS-Sender.

§9.4.2.11 Table 9.7 DDS-Security: 0x1000–0x10ff, 0x5000–0x50ff

Spec: §9.4.2.11, S. 165, Table 9.7 — “DDS-Security 1.1 — 0x1000-0x10ff and 0x5000-0x50ff”.

Repo: crates/rtps/src/parameter_list.rs (pid::IDENTITY_TOKEN, PERMISSIONS_TOKEN, PARTICIPANT_SECURITY_INFO u. a.)

Tests: crates/rtps/src/parameter_list.rs::tests::is_standard_pid_recognises_dds_security_pids

Status: done

§9.4.2.11 Table 9.7 DDS-XTypes: 0x0069, 0x0072–0x0075, 0x3f01–0x3fff, 0x7f01–0x7fff

Spec: §9.4.2.11, S. 165, Table 9.7 — “DDS-XTypes 1.2 — 0x0069; 0x0072-0x0075; 0x3f01-0x3fff; 0x7f01-0x7fff”.

Repo: crates/rtps/src/parameter_list.rs (pid::IGNORE = 0x3F03, PID_DATA_REPRESENTATION, PID_TYPE_CONSISTENCY, PID_TYPE_INFORMATION)

Tests: crates/rtps/src/parameter_list.rs::tests::pid_ignore_skipped_in_pl_cdr_decode, crates/discovery/tests/vendor_discovery_frames.rs::cyclone_announcements_read_and_write_back

Status: done

§9.4.2.11 Fehlender PID: Vorgabewert; unbekannter PID nach Table 9.6

Spec: §9.4.2.11, S. 165 — “If a ParameterId is expected, but not present, the protocol will assume the default value. Similarly, if a ParameterId is present but not recognized, the protocol will either skip and ignore the parameter or treat the parameter as an incompatible QoS.”

Repo: crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs, crates/rtps/src/participant_data.rs

Tests: crates/rtps/src/publication_data.rs::tests::an_absent_reliability_parameter_reads_as_reliable_on_a_publication, crates/rtps/src/publication_data.rs::tests::the_infinite_defaults_are_left_out_and_read_back, crates/rtps/src/subscription_data.rs::tests::the_readers_infinite_defaults_are_left_out_and_read_back, crates/rtps/src/publication_data.rs::tests::unknown_pids_are_skipped

Status: done — die Vorgabe je PID ist unter §9.6.3.2 geführt, das Must-Understand-Verhalten unter Table 9.6.

§9.4.2.12 SerializedPayload

Spec: §9.4.2.12, S. 165 — “For the purpose of interoperability, all implementations must however use a consistent representation (See, 10 Serialized Payload Representation).”

Repo: —

Tests: —

Status: n/a (informative) — Verweis; die Darstellung ist unter §10 geführt.

§9.4.2.13 Count

Spec: §9.4.2.13, S. 166 — “typedef Count_t Count;” Leitungsbild long value.

Repo: crates/rtps/src/submessages.rs (count: i32)

Tests: crates/rtps/src/submessages.rs::tests::acknack_submessage_roundtrip_le, crates/rtps/src/submessages.rs::tests::nack_frag_roundtrip_be

Status: done

§9.4.2.14 ChangeCount

Spec: §9.4.2.14, S. 166 — “typedef ChangeCount_t ChangeCount;” Leitungsbild long high, unsigned long low (8 Oktette).

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::gap_filtered_count_is_eight_octets_high_then_low, crates/rtps/src/submessages.rs::tests::gap_with_filtered_count_roundtrip_le

Status: done

§9.4.2.15 Table 9.8 ChecksumFlags (0,0)

Spec: §9.4.2.15, S. 166, Table 9.8 — “0, 0 — N/A — The messageChecksum is not included in the HeaderExtension”.

Repo: crates/rtps/src/header_extension.rs (ChecksumKind::None)

Tests: crates/rtps/src/header_extension.rs::tests::checksum_kind_roundtrip, crates/rtps/src/header_extension.rs::tests::empty_he_le_roundtrip

Status: done

§9.4.2.15 Table 9.8 ChecksumFlags (0,1) CRC-32C

Spec: §9.4.2.15, S. 166, Table 9.8 — “0, 1 — Checksum32_t — … the big-endian representation of the CRC-32C (Castagnoli) checksum of the RTPS message. … It shall be serialized into the 4-bytes of the Checksum32_t type using CDR big endian encoding.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::message_checksum, seal_message, verify_message, encode_body, decode_body); crates/rtps/src/datagram.rs (decode_submessage)

Tests: crates/rtps/src/header_extension.rs::tests::checksum_compute_crc32c_matches_rfc4960_vector, crates/rtps/src/header_extension.rs::tests::the_checksums_of_tables_9_10_and_9_12, crates/rtps/src/header_extension.rs::tests::a_sealed_message_verifies_and_a_changed_one_does_not

Status: done

§9.4.2.15 Table 9.8 ChecksumFlags (1,0) CRC-64/XZ

Spec: §9.4.2.15, S. 166–167, Table 9.8 — “1, 0 — Checksum64_t — … the big-endian representation of the CRC-64/XZ checksum of the RTPS message. … CDR big endian encoding.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::message_checksum, seal_message, verify_message, encode_body, decode_body); crates/rtps/src/datagram.rs (decode_submessage)

Tests: crates/rtps/src/header_extension.rs::tests::checksum_compute_crc64_xz_matches_known_vector, crates/rtps/src/header_extension.rs::tests::the_checksums_of_tables_9_10_and_9_12, crates/rtps/src/header_extension.rs::tests::a_sealed_message_verifies_and_a_changed_one_does_not

Status: done

§9.4.2.15 Table 9.8 ChecksumFlags (1,1) MD5

Spec: §9.4.2.15, S. 167, Table 9.8 — “1,1 — Checksum128_t — The messageChecksum is a 128-bit checksum. It shall hold the MD5 digest of the RTPS message.”

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::message_checksum, seal_message, verify_message, encode_body, decode_body); crates/rtps/src/datagram.rs (decode_submessage)

Tests: crates/rtps/src/header_extension.rs::tests::checksum_compute_md5_matches_rfc1321_vector, crates/rtps/src/header_extension.rs::tests::a_sealed_message_verifies_and_a_changed_one_does_not

Status: done

§9.4.2.15 Prüfsumme: Byte-Reihenfolge, Rechenbereich, Prüfung

Spec: §9.4.2.15, S. 167 — “the checksum shall be computed over the content of the RTPS Message, which includes the RTPS Header and HeaderExtension submessage. Moreover, for the purpose of computing the checksum, all the bytes of the messageChecksum field in the RTPS HeaderExtension shall be set to zero.”; Table 9.8: “CDR big endian encoding”.

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::message_checksum, seal_message, verify_message, encode_body, decode_body); crates/rtps/src/datagram.rs (decode_submessage)

Tests: crates/rtps/src/header_extension.rs::tests::a_sealed_message_verifies_and_a_changed_one_does_not, crates/rtps/src/header_extension.rs::tests::the_checksum_is_big_endian_in_a_little_endian_header_extension, crates/rtps/src/datagram.rs::tests::a_message_with_a_wrong_checksum_is_refused_and_counted

Status: done — CRC-32C und CRC-64 stehen in Big-Endian, die Prüfsumme ist über die ganze Nachricht mit genulltem Feld gerechnet, der Empfang prüft sie.

§9.4.2.15 Table 9.9 Parameter von CRC-32C

Spec: §9.4.2.15, S. 168, Table 9.9 — Breite 32 Bit, Polynom 0x1EDC6F41, Eingabe und Ergebnis gespiegelt, Startwert und Schluss-XOR 0xFFFFFFFF.

Repo: crates/foundation (crc32c)

Tests: crates/rtps/src/header_extension.rs::tests::checksum_compute_crc32c_matches_rfc4960_vector

Status: done

§9.4.2.15 Table 9.10 Beispiele CRC-32C

Spec: §9.4.2.15, S. 168, Table 9.10 — “Example Checksum32_t computation”: 00 00 00 00 → 0x48674BC7, FF FF FF FF → 0xFFFFFFFF, 33 22 55 AA BB CC DD EE FF → 0xB59CA09B.

Repo: crates/rtps/src/header_extension.rs (ChecksumValue::compute)

Tests: crates/rtps/src/header_extension.rs::tests::the_checksums_of_tables_9_10_and_9_12

Status: done — die drei Beispiele der Tabelle (Eingabe, CRC-32C, Checksum32_t-Oktette).

§9.4.2.15 Table 9.11 Parameter von CRC-64/XZ

Spec: §9.4.2.15, S. 168, Table 9.11 — Breite 64 Bit, Polynom 0x42F0E1EBA9EA3693, Eingabe und Ergebnis gespiegelt, Startwert und Schluss-XOR 0xFFFFFFFFFFFFFFFF.

Repo: crates/foundation (crc64_xz)

Tests: crates/rtps/src/header_extension.rs::tests::checksum_compute_crc64_xz_matches_known_vector

Status: done

§9.4.2.15 Table 9.12 Beispiele CRC-64/XZ

Spec: §9.4.2.15, S. 169, Table 9.12 — “Example Checksum64_t computation”: 00 00 00 00 → 0xF4A586351E1B9F4B, FF FF FF FF → 0xFFFFFFFF00000000, 33 22 55 AA BB CC DD EE FF → 0x701ECEB219A8E5D5.

Repo: crates/rtps/src/header_extension.rs (ChecksumValue::compute)

Tests: crates/rtps/src/header_extension.rs::tests::the_checksums_of_tables_9_10_and_9_12

Status: done — die drei Beispiele der Tabelle.

§9.4.2.16 MessageLength

Spec: §9.4.2.16, S. 169 — “typedef MessageLength_t MessageLength;” Leitungsbild unsigned long length.

Repo: crates/rtps/src/header_extension.rs (message_length)

Tests: crates/rtps/src/header_extension.rs::tests::wire_layout_le_message_length_correct

Status: done

§9.4.2.17 UExtension4

Spec: §9.4.2.17, S. 169 — “typedef UExtension4_t UExtension4;” Leitungsbild octet value[4].

Repo: crates/rtps/src/header_extension.rs (uextension4)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_uextension4_be

Status: done

§9.4.2.18 WExtension8

Spec: §9.4.2.18, S. 169 — “typedef WExtension8_t WExtension8;” Leitungsbild octet value[8].

Repo: crates/rtps/src/header_extension.rs (wextension8)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_wextension8_le

Status: done

§9.4.2.19 GroupDigest

Spec: §9.4.2.19, S. 169–170 — “typedef GroupDigest_t GroupDigest;” Leitungsbild octet value[4].

Repo: crates/rtps/src/group_digest.rs (GroupDigest, GroupDigest::of_entities)

Tests: crates/rtps/src/group_digest.rs::tests::two_writers_digest_as_section_9_3_2_5_computes_it, crates/rtps/src/group_digest.rs::tests::the_digest_does_not_depend_on_the_order_given, crates/rtps/src/group_digest.rs::tests::the_empty_group_is_zero_and_not_the_hash_of_an_empty_sequence

Status: done

§9.4.3.1 LocatorUDPv4

Spec: §9.4.3.1, S. 170, Table 9.13 — “The LocatorUDPv4 SubmessageElement is identical to a LocatorList SubmessageElement containing a single locator of kind LOCATOR_KIND_UDPv4.” Leitungsbild unsigned long address, unsigned long port.

Repo: crates/rtps/src/submessages.rs (InfoReplyIp4Submessage::write_locator_udpv4, read_locator_udpv4)

Tests: crates/rtps/src/submessages.rs::tests::locator_udpv4_is_two_unsigned_longs_in_the_byte_order_of_the_submessage, crates/rtps/src/submessages.rs::tests::info_reply_ip4_with_multicast_roundtrip_be

Status: done — address und port sind je ein unsigned long in der Byte-Reihenfolge der Submessage; 192.0.2.10 ist die Zahl 0xC000020A (das erste Oktett höchstwertig). Zuvor stand die Adresse in jeder Byte-Reihenfolge als vier Oktette in Netzreihenfolge, was im Little-Endian-Fall abweicht. 2.5 definiert LocatorUDPv4_t nicht; die Zuordnung von a.b.c.d auf die Zahl ist eine Annahme. Kein Hersteller ist gemessen.

Spec: §9.4.4, S. 170 — Leitungsbild 'R' 'T' 'P' 'S', ProtocolVersion version, VendorId vendorId, GuidPrefix guidPrefix. “The structure of the Header cannot change in this major version (2) of the protocol.”

Repo: crates/rtps/src/header.rs (RtpsHeader::to_bytes, from_bytes)

Tests: crates/rtps/src/header.rs::tests::header_roundtrip, crates/rtps/src/header.rs::tests::header_total_size_is_20_bytes

Status: done

§9.4.4 Zugewiesene VendorId verwenden

Spec: §9.4.4, S. 170 — “To be compliant with the DDS Interoperability Specification a vendor must have a reserved Vendor ID and use it.”

Repo: —

Tests: —

Status: blocked — Zuweisung einer VendorId durch die OMG (beantragt); hebt sich auf, sobald die OMG den Wert zuweist und VendorId::ZERODDS ihn trägt. Bis dahin sendet ZeroDDS 0x01F0 (crates/rtps/src/wire_types.rs, laut Kommentar ein Zwischenwert), einen Wert, den die OMG-Liste nicht führt (vergeben bis {0x01,0x1C}, {0x01,0x1D} und {0x01,0x1E} reserviert).

§9.4.5.1 SubmessageHeader

Spec: §9.4.5.1, S. 171 — “struct SubmessageHeader { octet submessageId; octet flags; unsigned short submessageLength; /* octetsToNextHeader */ };” “This general structure cannot change in this major version (2) of the protocol.”

Repo: crates/rtps/src/submessage_header.rs (SubmessageHeader::to_bytes, from_bytes)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_header_layout_le, crates/rtps/src/submessage_header.rs::tests::submessage_header_layout_be

Status: done

§9.4.5.1.1 SubmessageKind RTPS_HE = 0x00

Spec: §9.4.5.1.1, S. 171 — “@value(0x00) RTPS_HE, /* HeaderExtension */“.

Repo: crates/rtps/src/header_extension.rs (SUBMESSAGE_ID_HEADER_EXTENSION = 0x00), crates/rtps/src/datagram.rs (decode_datagram)

Tests: crates/rtps/tests/cyclone_he_must_understand.rs::local_encoder_produces_must_understand_bit, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§9.4.5.1.1 SubmessageKind PAD = 0x01

Spec: §9.4.5.1.1, S. 171 — “@value(0x01) PAD, /* Pad */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::Pad)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_octets_match_spec_table_8_13

Status: done

§9.4.5.1.1 SubmessageKind ACKNACK = 0x06

Spec: §9.4.5.1.1, S. 171 — “@value(0x06) ACKNACK /* AckNack */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::AckNack)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_acknack_is_0x06

Status: done

§9.4.5.1.1 SubmessageKind HEARTBEAT = 0x07

Spec: §9.4.5.1.1, S. 171 — “@value(0x07) HEARTBEAT /* Heartbeat */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::Heartbeat)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_heartbeat_is_0x07

Status: done

§9.4.5.1.1 SubmessageKind GAP = 0x08

Spec: §9.4.5.1.1, S. 171 — “@value(8x08) GAP /* Gap */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::Gap)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_gap_is_0x08

Status: done

§9.4.5.1.1 SubmessageKind INFO_TS = 0x09

Spec: §9.4.5.1.1, S. 171 — “@value(0x09) INFO_TS /* InfoTimestamp */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::InfoTs)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_octets_match_spec_table_8_13

Status: done

§9.4.5.1.1 SubmessageKind INFO_SRC = 0x0c

Spec: §9.4.5.1.1, S. 171 — “@value(0x0c) INFO_SRC /* InfoSource */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::InfoSrc)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_octets_match_spec_table_8_13

Status: done

§9.4.5.1.1 SubmessageKind INFO_REPLY_IP4 = 0x0d

Spec: §9.4.5.1.1, S. 171 — “@value(0x0d) INFO_REPLY_IP4 /* InfoReplyIp4 */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::InfoReplyIp4)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_octets_match_spec_table_8_13

Status: done

§9.4.5.1.1 SubmessageKind INFO_DST = 0x0e

Spec: §9.4.5.1.1, S. 171 — “@value(0x0e) INFO_DST /* InfoDestination */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::InfoDst)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_octets_match_spec_table_8_13

Status: done

§9.4.5.1.1 SubmessageKind INFO_REPLY = 0x0f

Spec: §9.4.5.1.1, S. 171 — “@value(0x0f) INFO_REPLY /* InfoReply */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::InfoReply)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_octets_match_spec_table_8_13

Status: done

§9.4.5.1.1 SubmessageKind NACK_FRAG = 0x12

Spec: §9.4.5.1.1, S. 171 — “@value(0x12) NACK_FRAG /* NackFrag */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::NackFrag)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_octets_match_spec_table_8_13

Status: done

§9.4.5.1.1 SubmessageKind HEARTBEAT_FRAG = 0x13

Spec: §9.4.5.1.1, S. 171 — “@value(0x13) HEARTBEAT_FRAG /* HeartbeatFrag */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::HeartbeatFrag)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_octets_match_spec_table_8_13

Status: done

§9.4.5.1.1 SubmessageKind DATA = 0x15

Spec: §9.4.5.1.1, S. 171 — “@value(0x15) DATA /* Data */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::Data)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_data_is_0x15

Status: done

§9.4.5.1.1 SubmessageKind DATA_FRAG = 0x16

Spec: §9.4.5.1.1, S. 171 — “@value(0x16) DATA_FRAG /* DataFrag */“.

Repo: crates/rtps/src/submessage_header.rs (SubmessageId::DataFrag)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_id_octets_match_spec_table_8_13

Status: done

§9.4.5.1.1 Bedeutung der SubmessageIds unveränderlich

Spec: §9.4.5.1.1, S. 171 — “The meaning of the Submessage IDs cannot be modified in this major version (2). Additional Submessages can be added in higher minor versions.”

Repo: —

Tests: —

Status: n/a (informative) — Anforderung an künftige Fassungen der Spezifikation.

§9.4.5.1.1 Kennungen 0x80–0xff nach VendorId

Spec: §9.4.5.1.1, S. 171 — “Submessages with ID’s 0x80 to 0xff (inclusive) are vendor-specific; they will not be defined by future versions of the protocol. Their interpretation is dependent on the vendorId that is current when the Submessage is encountered.”

Repo: crates/rtps/src/datagram.rs (decode_datagram, ParsedSubmessage::Unknown)

Tests: crates/rtps/src/datagram.rs::tests::decode_skips_an_unknown_submessage_whatever_its_flags

Status: done — ZeroDDS definiert keine eigene Submessage; jede Kennung 0x80–0xff wird übergangen.

§9.4.5.1.1.1 Table 9.14 DDS-Security 0x30–0x3f

Spec: §9.4.5.1.1.1, S. 172, Table 9.14 — “DDS-Security 1.1 — 0x30-0x3f”.

Repo: crates/security-rtps/src/codec.rs (SEC_PREFIX = 0x31, SEC_BODY, SEC_POSTFIX, SRTPS_PREFIX, SRTPS_POSTFIX)

Tests: crates/security-rtps/src/codec.rs::tests::constants_match_spec, crates/security-rtps/src/codec.rs::tests::three_submessages_carry_spec_ids_flags_and_lengths_in_order

Status: done

§9.4.5.1.2 EndiannessFlag im niederwertigsten Bit

Spec: §9.4.5.1.2, S. 172 — “The PSM maps the EndiannessFlag flag into the least-significant bit (LSB) of the flags. … E=0 means big-endian, E=1 means little-endian. … E = SubmessageHeader.flags & 0x01”.

Repo: crates/rtps/src/submessage_header.rs (FLAG_E_LITTLE_ENDIAN = 0x01)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_header_is_little_endian_flag, crates/rtps/src/submessage_header.rs::tests::submessage_header_roundtrip_be

Status: done

§9.4.5.1.2 X-Flags: null senden, beim Empfang ignorieren

Spec: §9.4.5.1.2, S. 172 — “Implementations of RTPS version 2.5 should set these to zero when sending and ignore these when receiving.”

Repo: crates/rtps/src/submessages.rs (die Encoder setzen nur die definierten Flags; die Decoder lesen nur diese); crates/rtps/src/datagram.rs

Tests: crates/rtps/src/datagram.rs::tests::x_flags_are_zero_when_sending_and_ignored_when_receiving, crates/rtps/src/datagram.rs::tests::decode_heartbeat_preserves_final_and_liveliness_flags, crates/rtps/src/datagram.rs::tests::data_frag_spec_and_cyclone_flag_oracle

Status: done — die Encoder von HEARTBEAT, ACKNACK, GAP, HEARTBEAT_FRAG, NACK_FRAG, INFO_TS, INFO_SRC, INFO_REPLY, INFO_REPLY_IP4 und DATA setzen nur E und die für die Submessage definierten Flags; die Decoder geben mit allen übrigen Flag-Bits gesetzt denselben Wert. Bei unbekannten Submessages gilt §8.3.4.1 Regel 3.

§9.4.5.1.3 octetsToNextHeader als ushort

Spec: §9.4.5.1.3, S. 172 — “The representation of this field is a CDR unsigned short (ushort).”

Repo: crates/rtps/src/submessage_header.rs (octets_to_next_header: u16)

Tests: crates/rtps/src/submessage_header.rs::tests::submessage_header_roundtrip_le

Status: done

§9.4.5.1.3 octetsToNextHeader > 0

Spec: §9.4.5.1.3, S. 172 — “In case octetsToNextHeader > 0, it is the number of octets from the first octet of the contents of the Submessage until the first octet of the header of the next Submessage … OR it is the number of octets remaining in the Message”.

Repo: crates/rtps/src/datagram.rs (decode_datagram: body_end)

Tests: crates/rtps/src/datagram.rs::tests::encode_decode_two_data_submessages, crates/rtps/src/datagram.rs::tests::pad_submessage_is_skipped_and_the_data_behind_it_still_decodes

Status: done

§9.4.5.1.3 octetsToNextHeader == 0 außer PAD und INFO_TS

Spec: §9.4.5.1.3, S. 172 — “In case octetsToNextHeader==0 and the kind of Submessage is NOT PAD or INFO_TS, the Submessage is the last Submessage in the Message and extends up to the end of the Message.”

Repo: crates/rtps/src/datagram.rs (decode_datagram)

Tests: crates/rtps/src/datagram.rs::tests::decode_handles_last_submessage_zero_length

Status: done

§9.4.5.1.3 octetsToNextHeader == 0 bei PAD und INFO_TS

Spec: §9.4.5.1.3, S. 172 — “In case the octetsToNextHeader==0 and the kind of Submessage is PAD or INFO_TS, the next Submessage header starts immediately after the current Submessage header OR the PAD or INFO_TS is the last Submessage in the Message.”

Repo: crates/rtps/src/datagram.rs (decode_datagram)

Tests: crates/rtps/src/datagram.rs::tests::an_info_ts_without_a_body_is_not_the_last_submessage, crates/rtps/src/datagram.rs::tests::pad_submessage_is_skipped_and_re_encoded_byte_for_byte

Status: done

§9.4.5.2 HeaderExtension: Leitungsbild

Spec: §9.4.5.2, S. 173 — RTPS_HE |P|C|C|W|U|T|L|E|, dann messageLength [L], rtpsSendTimestamp [T], uExtension4 [U], wExtension8 [W], messageChecksum [CC != 00], parameters [P].

Repo: crates/rtps/src/header_extension.rs (HeaderExtension::encode_body, decode_body)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_all_fields_set_le, crates/rtps/src/header_extension.rs::tests::roundtrip_all_fields_set_be, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§9.4.5.2 HeaderExtension LengthFlag (0x02)

Spec: §9.4.5.2, S. 173 — “L = SubmessageHeader.flags & 0x02”.

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_L)

Tests: crates/rtps/src/header_extension.rs::tests::flag_byte_with_message_length, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§9.4.5.2 HeaderExtension TimestampFlag (0x04)

Spec: §9.4.5.2, S. 173 — “The TimestampFlag is represented with the literal ‘T’.” (Ausdruck im Text: “T = SubmessageHeader.flags & 0x04”).

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_W, Bit 2)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_timestamp_le, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§9.4.5.2 HeaderExtension UExtension4Flag (0x08)

Spec: §9.4.5.2, S. 173 — “U = SubmessageHeader.flags & 0x08”.

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_U)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_uextension4_be, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§9.4.5.2 HeaderExtension WExtension8Flag (0x10)

Spec: §9.4.5.2, S. 173 — “W = SubmessageHeader.flags & 0x10”.

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_V, Bit 4)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_wextension8_le, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§9.4.5.2 HeaderExtension ChecksumFlags C1 (0x40), C2 (0x20)

Spec: §9.4.5.2, S. 173 — “C1 = SubmessageHeader.flags & 0x40; C2 = SubmessageHeader.flags & 0x20”.

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_C_MASK, ChecksumKind::from_flags)

Tests: crates/rtps/src/header_extension.rs::tests::checksum_kind_roundtrip, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§9.4.5.2 HeaderExtension ParametersFlag (0x80)

Spec: §9.4.5.2, S. 174 — “P = SubmessageHeader.flags & 0x80”.

Repo: crates/rtps/src/header_extension.rs (HE_FLAG_P)

Tests: crates/rtps/src/header_extension.rs::tests::roundtrip_with_parameter_list, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension

Status: done

§9.4.5.3 AckNack: Leitungsbild

Spec: §9.4.5.3, S. 174 — ACKNACK |X|X|X|X|X|X|F|E|, readerId, writerId, SequenceNumberSet readerSNState, Count count.

Repo: crates/rtps/src/submessages.rs (AckNackSubmessage::write_body, read_body)

Tests: crates/rtps/src/submessages.rs::tests::acknack_submessage_roundtrip_le

Status: done

§9.4.5.3 AckNack FinalFlag (0x02)

Spec: §9.4.5.3, S. 174 — “The PSM maps the FinalFlag flag into the 2nd least-significant bit (LSB) of the flags. … F = SubmessageHeader.flags & 0x02”.

Repo: crates/rtps/src/submessages.rs (ACKNACK_FLAG_FINAL = 0x02)

Tests: crates/rtps/src/datagram.rs::tests::decode_acknack_preserves_final_flag, crates/rtps/src/submessages.rs::tests::acknack_submessage_with_final_flag

Status: done

§9.4.5.3 AckNack F = 0: Writer antwortet mit Heartbeat

Spec: §9.4.5.3, S. 174 — “F=1 means the reader does not require a Heartbeat from the writer. F=0 means the writer must respond to the AckNack message with a Heartbeat message.”

Repo: crates/rtps/src/reliable_writer.rs (note_acknack_final_flag, tick); crates/rtps/src/reader_proxy.rs (heartbeat_asked, heartbeat_is_asked); Aufrufe in crates/dcps/src/runtime.rs, crates/discovery/src/sedp/stack.rs, crates/dcps/src/type_lookup_transport.rs

Tests: crates/rtps/src/reliable_writer.rs::tests::an_acknack_with_the_final_flag_clear_is_answered_by_a_heartbeat

Status: done — ein ACKNACK mit F = 0 wird mit einem HEARTBEAT beantwortet, sofort, wenn der Reader noch keinen hatte, sonst frühestens eine Periode nach dem letzten; Nutzer-, SEDP- und TypeLookup-Writer.

§9.4.5.4 Data: Leitungsbild

Spec: §9.4.5.4, S. 174 — DATA |X|X|X|N|K|D|Q|E|, extraFlags, octetsToInlineQos, readerId, writerId, writerSN, inlineQos [Q], serializedPayload [D || K].

Repo: crates/rtps/src/submessages.rs (DataSubmessage::write_body, read_body_into)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_roundtrip_le, crates/rtps/tests/cyclone_compliance.rs::cyclone_data_cdr2_roundtrip_bit_identical

Status: done

§9.4.5.4 Data InlineQosFlag (0x02)

Spec: §9.4.5.4, S. 175 — “Q = SubmessageHeader.flags & 0x02”.

Repo: crates/rtps/src/submessages.rs (DATA_FLAG_INLINE_QOS = 0x02)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_all_valid_flags_combined_roundtrip, crates/rtps/tests/vendor_frames.rs::cyclone_session_re_encodes_byte_for_byte

Status: done

§9.4.5.4 Data DataFlag (0x04)

Spec: §9.4.5.4, S. 175 — “D = SubmessageHeader.flags & 0x04”.

Repo: crates/rtps/src/submessages.rs (DATA_FLAG_DATA = 0x04)

Tests: crates/rtps/tests/cyclone_compliance.rs::cyclone_data_cdr2_payload_decodes_and_carries_payload, crates/rtps/src/submessages.rs::tests::data_submessage_all_valid_flags_combined_roundtrip

Status: done

§9.4.5.4 Data KeyFlag (0x08)

Spec: §9.4.5.4, S. 175 — “K = SubmessageHeader.flags & 0x08”.

Repo: crates/rtps/src/submessages.rs (DATA_FLAG_KEY = 0x08)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_key_flag_roundtrip, crates/discovery/src/sedp/reader.rs::tests::handle_data_reports_a_cyclone_dispose_without_key_hash_as_removed

Status: done

§9.4.5.4 Data NonStandardPayloadFlag (0x10)

Spec: §9.4.5.4, S. 175 — “N = SubmessageHeader.flags & 0x10”.

Repo: crates/rtps/src/submessages.rs (DATA_FLAG_NON_STANDARD = 0x10)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_non_standard_flag_roundtrip

Status: done

§9.4.5.4 Data: Kombinationen von D und K

Spec: §9.4.5.4, S. 175 — “D=0 and K=0 means that there is no serializedPayload SubmessageElement. D=1 and K=0 means that the serializedPayload SubmessageElement contains the serialized Data. D=0 and K=1 means that the serializedPayload SubmessageElement contains the serialized Key.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage); crates/rtps/src/reliable_reader.rs (handle_data_into)

Tests: crates/rtps/src/submessages.rs::tests::data_submessage_roundtrip_be_with_empty_payload, crates/dcps/tests/lifecycle_wire_e2e.rs::linux::dispose_marker_carries_the_key_fields_of_a_string_keyed_type

Status: done

§9.4.5.4 Data: D = 1 und K = 1 ungültig

Spec: §9.4.5.4, S. 175 — “D=1 and K=1 is an invalid combination in this version of the protocol.”

Repo: crates/rtps/src/submessages.rs (DataSubmessage::read_body_into)

Tests: crates/rtps/src/submessages.rs::validity_tests::data_with_writer_sn_not_positive_or_with_d_and_k_is_invalid

Status: done — ein DATA mit D = 1 und K = 1 wird abgewiesen, mit dem Rest der Nachricht.

§9.4.5.4 Data extraFlags null

Spec: §9.4.5.4, S. 175 — “This version of the protocol should set all the bits in the extraFlags to zero.”

Repo: crates/rtps/src/reliable_writer.rs (extra_flags: 0)

Tests: crates/rtps/src/submessages.rs::tests::data_frag_decode_accepts_nonzero_extra_flags_silently, crates/rtps/tests/cyclone_compliance.rs::zerodds_writer_produces_compatible_data_layout

Status: done

§9.4.5.4 Data octetsToInlineQos

Spec: §9.4.5.4, S. 175 — “Implementations of the protocol that are processing a received submessage should always use the octetsToInlineQos to skip any submessage header elements it does not expect or understand and continue to process the inlineQos SubmessageElement”.

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::octets_to_inline_qos_skips_header_elements_of_a_later_version, crates/rtps/src/submessages.rs::tests::data_submessage_octets_to_inline_qos_is_16

Status: done

§9.4.5.5 DataFrag: Leitungsbild

Spec: §9.4.5.5, S. 176 — DATA_FRAG |X|X|X|X|N|K|Q|E|, extraFlags, octetsToInlineQos, readerId, writerId, writerSN, fragmentStartingNum, ushort fragmentsInSubmessage, ushort fragmentSize, unsigned long sampleSize, inlineQos [Q], serializedPayload.

Repo: crates/rtps/src/submessages.rs (DataFragSubmessage::write_body, read_body)

Tests: crates/rtps/src/submessages.rs::tests::data_frag_roundtrip_le, crates/rtps/src/submessages.rs::tests::data_frag_roundtrip_be

Status: done

§9.4.5.5 DataFrag InlineQosFlag (0x02)

Spec: §9.4.5.5, S. 176 — “Q = SubmessageHeader.flags & 0x02”.

Repo: crates/rtps/src/submessages.rs (DATA_FRAG_FLAG_INLINE_QOS = 0x02)

Tests: crates/rtps/src/datagram.rs::tests::data_frag_spec_and_cyclone_flag_oracle

Status: done

§9.4.5.5 DataFrag KeyFlag (0x04)

Spec: §9.4.5.5, S. 176 — “K = SubmessageHeader.flags & 0x04”.

Repo: crates/rtps/src/submessages.rs (DATA_FRAG_FLAG_KEY = 0x04)

Tests: crates/rtps/src/datagram.rs::tests::data_frag_spec_and_cyclone_flag_oracle

Status: done

§9.4.5.5 DataFrag NonStandardPayloadFlag (0x08)

Spec: §9.4.5.5, S. 176 — “N = SubmessageHeader.flags & 0x08”.

Repo: crates/rtps/src/submessages.rs (DATA_FRAG_FLAG_NON_STANDARD = 0x08)

Tests: crates/rtps/src/datagram.rs::tests::data_frag_spec_and_cyclone_flag_oracle, crates/rtps/src/submessages.rs::tests::data_frag_flags_survive_roundtrip

Status: done

§9.4.5.6 Gap: Leitungsbild

Spec: §9.4.5.6, S. 177 — GAP |X|X|X|X|X|F|G|E|, readerId, writerId, gapStart, gapList, gapStartGSN [G], gapEndGSN [G], ChangeCount filteredCount [F].

Repo: crates/rtps/src/submessages.rs (GapSubmessage::write_body, read_body)

Tests: crates/rtps/src/submessages.rs::tests::gap_filtered_count_is_eight_octets_high_then_low, crates/rtps/src/submessages.rs::tests::gap_with_filtered_count_roundtrip_le

Status: done

§9.4.5.6 Gap GroupInfoFlag (0x02)

Spec: §9.4.5.6, S. 177 — “G = SubmessageHeader.flags & 0x02”.

Repo: crates/rtps/src/submessages.rs (GAP_FLAG_GROUP_INFO = 0x02)

Tests: crates/rtps/src/submessages.rs::tests::the_gap_flags_are_those_of_9_4_5_6

Status: done

§9.4.5.6 Gap FilteredCountFlag (0x04)

Spec: §9.4.5.6, S. 177 — “F = SubmessageHeader.flags & 0x04”.

Repo: crates/rtps/src/submessages.rs (GAP_FLAG_FILTERED_COUNT = 0x04)

Tests: crates/rtps/src/submessages.rs::tests::the_gap_flags_are_those_of_9_4_5_6

Status: done

§9.4.5.6 Gap gapStartGSN und gapEndGSN

Spec: §9.4.5.6, S. 177 — “G=1 means the Gap also includes a gapStartGSN and a gapEndGSN.”

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::gap_with_group_info_roundtrip_be, crates/rtps/src/submessages.rs::tests::gap_decode_rejects_invalid_group_sequence_numbers, crates/rtps/src/submessages.rs::tests::a_gap_end_gsn_one_below_its_start_is_an_empty_range_and_valid, crates/rtps/src/submessages.rs::tests::the_gap_flags_are_those_of_9_4_5_6

Status: done

§9.4.5.7 Heartbeat: Leitungsbild

Spec: §9.4.5.7, S. 178 — HEARTBEAT |X|X|X|X|G|L|F|E|, readerId, writerId, firstSN, lastSN, Count count, currentGSN/firstGSN/lastGSN [G].

Repo: crates/rtps/src/submessages.rs (HeartbeatSubmessage::write_body, read_body)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_submessage_roundtrip_le, crates/rtps/tests/cyclone_compliance.rs::cyclone_heartbeat_decodes

Status: done — der Teil nach count ist unter „Heartbeat: Group-Felder“ geführt.

§9.4.5.7 Heartbeat FinalFlag (0x02)

Spec: §9.4.5.7, S. 178 — “F = SubmessageHeader.flags & 0x02”.

Repo: crates/rtps/src/submessages.rs (HEARTBEAT_FLAG_FINAL = 0x02)

Tests: crates/rtps/src/datagram.rs::tests::decode_heartbeat_preserves_final_and_liveliness_flags

Status: done

§9.4.5.7 Heartbeat LivelinessFlag (0x04)

Spec: §9.4.5.7, S. 178 — “L = SubmessageHeader.flags & 0x04”.

Repo: crates/rtps/src/submessages.rs (HEARTBEAT_FLAG_LIVELINESS = 0x04)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_submessage_liveliness_flag_roundtrip, crates/rtps/src/datagram.rs::tests::decode_heartbeat_preserves_final_and_liveliness_flags

Status: done

§9.4.5.7 Heartbeat GroupInfoFlag (0x08)

Spec: §9.4.5.7, S. 178 — “G = SubmessageHeader.flags & 0x08”.

Repo: crates/rtps/src/submessages.rs (HEARTBEAT_FLAG_GROUP_INFO = 0x08)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_with_group_info_roundtrip_le, crates/rtps/src/submessages.rs::tests::the_group_info_is_the_three_sequence_numbers_of_9_4_5_7

Status: done

§9.4.5.7 Heartbeat: Group-Felder

Spec: §9.4.5.7, S. 178 — “G=1 means the HeartBeat includes the currentGSN, firstGSN, and lastGSN.”

Repo: —

Tests: crates/rtps/src/submessages.rs::tests::the_group_info_is_the_three_sequence_numbers_of_9_4_5_7, crates/rtps/src/submessages.rs::tests::heartbeat_with_group_info_roundtrip_le, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_heartbeat_carries_the_groups_numbers

Status: done

§9.4.5.8 HeartBeatFrag: Leitungsbild

Spec: §9.4.5.8, S. 179 — HEARTBEAT_FRAG |X|X|X|X|X|X|X|E|, readerId, writerId, writerSN, lastFragmentNum, count.

Repo: crates/rtps/src/submessages.rs (HeartbeatFragSubmessage)

Tests: crates/rtps/src/submessages.rs::tests::heartbeat_frag_roundtrip_le, crates/rtps/src/datagram.rs::tests::decode_heartbeat_frag_roundtrip

Status: done

§9.4.5.9 InfoDestination: Leitungsbild

Spec: §9.4.5.9, S. 179 — INFO_DST |X|X|X|X|X|X|X|E|, GuidPrefix guidPrefix.

Repo: crates/rtps/src/datagram.rs (ParsedSubmessage::InfoDestination)

Tests: crates/rtps/src/datagram.rs::tests::info_dst_body_of_exactly_twelve_decodes, crates/rtps/src/datagram.rs::tests::info_dst_decodes_to_typed_destination_prefix

Status: done

§9.4.5.10 InfoReply: Leitungsbild

Spec: §9.4.5.10, S. 179 — INFO_REPLY |X|X|X|X|X|X|M|E|, LocatorList unicastLocatorList, LocatorList multicastLocatorList [M].

Repo: crates/rtps/src/submessages.rs (InfoReplySubmessage)

Tests: crates/rtps/src/submessages.rs::tests::info_reply_unicast_only_roundtrip_le, crates/rtps/src/submessages.rs::tests::info_reply_with_multicast_roundtrip_be

Status: done

§9.4.5.10 InfoReply MulticastFlag (0x02)

Spec: §9.4.5.10, S. 180 — “M = SubmessageHeader.flags & 0x02”.

Repo: crates/rtps/src/submessages.rs (INFO_REPLY_FLAG_MULTICAST = 0x02)

Tests: crates/rtps/src/submessages.rs::tests::info_reply_with_multicast_roundtrip_le, crates/rtps/src/datagram.rs::tests::decode_info_reply_with_multicast_via_datagram

Status: done

§9.4.5.11 InfoSource: Leitungsbild

Spec: §9.4.5.11, S. 180 — INFO_SRC |X|X|X|X|X|X|X|E|, long unused, ProtocolVersion version, VendorId vendorId, GuidPrefix guidPrefix.

Repo: crates/rtps/src/submessages.rs (InfoSourceSubmessage)

Tests: crates/rtps/src/submessages.rs::tests::info_source_wire_size_is_20, crates/rtps/src/submessages.rs::tests::info_source_unused_field_roundtrips

Status: done

§9.4.5.12 InfoTimestamp: Leitungsbild

Spec: §9.4.5.12, S. 180 — INFO_TS |X|X|X|X|X|X|I|E|, Timestamp timestamp [only if I==0].

Repo: crates/rtps/src/submessages.rs (InfoTimestampSubmessage)

Tests: crates/rtps/src/submessages.rs::tests::info_timestamp_roundtrip_le, crates/rtps/src/submessages.rs::tests::info_timestamp_decode_with_invalidate_ignores_body

Status: done

§9.4.5.12 InfoTimestamp InvalidateFlag (0x02)

Spec: §9.4.5.12, S. 180 — “I = SubmessageHeader.flags & 0x02”.

Repo: crates/rtps/src/submessages.rs (INFO_TIMESTAMP_FLAG_INVALIDATE = 0x02)

Tests: crates/rtps/src/submessages.rs::tests::info_timestamp_invalidate_flag_yields_empty_body, crates/rtps/src/datagram.rs::tests::receiver_walk_info_timestamp_invalidate_clears_have_timestamp

Status: done

§9.4.5.13 Pad: Leitungsbild

Spec: §9.4.5.13, S. 180–181 — PAD |X|X|X|X|X|X|X|E| octetsToNextHeader.

Repo: crates/rtps/src/datagram.rs (decode_datagram: PAD wird übersprungen)

Tests: crates/rtps/src/datagram.rs::tests::pad_submessage_is_skipped_and_re_encoded_byte_for_byte

Status: done

§9.4.5.14 NackFrag: Leitungsbild

Spec: §9.4.5.14, S. 181 — NACK_FRAG |X|X|X|X|X|X|X|E|, readerId, writerId, writerSN, FragmentNumberSet fragmentNumberState, count.

Repo: crates/rtps/src/submessages.rs (NackFragSubmessage)

Tests: crates/rtps/src/submessages.rs::tests::nack_frag_roundtrip_le, crates/rtps/src/datagram.rs::tests::decode_nack_frag_roundtrip

Status: done

§9.4.5.15 InfoReplyIp4: Leitungsbild

Spec: §9.4.5.15, S. 181 — INFO_REPLY_IP4 |X|X|X|X|X|X|M|E|, LocatorUDPv4 unicastLocator, LocatorUDPv4 multicastLocator [M]. “Its use and interpretation are identical to those of an InfoReply Submessage containing a single unicast and possibly a single multicast locator”.

Repo: crates/rtps/src/submessages.rs (InfoReplyIp4Submessage)

Tests: crates/rtps/src/submessages.rs::tests::locator_udpv4_is_two_unsigned_longs_in_the_byte_order_of_the_submessage, crates/rtps/src/submessages.rs::tests::info_reply_ip4_unicast_only_roundtrip_le, crates/rtps/src/datagram.rs::tests::receiver_walk_info_reply_ip4_sets_reply_locators

Status: done — Aufbau (Unicast-LocatorUDPv4, mit M-Flag ein Multicast-LocatorUDPv4), Flags (E, M) und Wirkung stimmen; die Adresse folgt LocatorUDPv4 (Item unter §9.4.3.1).

§9.4.5.15 InfoReplyIp4 MulticastFlag (0x02)

Spec: §9.4.5.15, S. 182 — “M = SubmessageHeader.flags & 0x02”.

Repo: crates/rtps/src/submessages.rs (InfoReplyIp4Submessage::write_body, read_body)

Tests: crates/rtps/src/submessages.rs::tests::info_reply_ip4_with_multicast_roundtrip_be

Status: done

§9.5 Eine Nachricht je UDP-Datagramm

Spec: §9.5, S. 182 — “When RTPS is used over UDP/IP, a Message is the contents (payload) of exactly one UDP/IP Datagram.”

Repo: crates/transport-udp/src/udp_transport.rs (UdpTransport)

Tests: crates/transport-udp/tests/e2e.rs::e2e_write_udp_read_single_datagram, crates/transport-udp/src/udp_transport.rs::tests::without_the_cache_a_largest_datagram_arrives

Status: done

§9.6.1 ParameterIds in der HeaderExtension

Spec: §9.6.1, S. 182 — “This version of the protocol does not specify any ParameterId that may appear in the HeaderExtension. … Compliant implementations encountering an unrecognized ParameterId within the HeaderExtension shall either skip and the parameter or reject the entire RTPS Message, as specified in Table 9.6.”

Repo: crates/rtps/src/datagram.rs (decode_datagram: validate_must_understand_in_data_pipeline auf die Parameter der HeaderExtension)

Tests: crates/rtps/tests/cyclone_he_must_understand.rs::the_decoder_refuses_a_header_extension_with_an_unknown_must_understand_pid, crates/rtps/src/header_extension.rs::tests::roundtrip_with_parameter_list, crates/rtps/src/datagram.rs::tests::decode_data_after_header_extension, crates/rtps/src/parameter_list.rs::tests::a_vendor_specific_must_understand_pid_of_another_vendor_is_an_error

Status: done — ein nicht erkannter PID mit Bit 0x4000 in der HeaderExtension verwirft die Nachricht, auch ein herstellerspezifischer (siehe Table 9.6); einer ohne das Bit wird übergangen.

§9.6.2.1 Table 9.15 SPDP_WELL_KNOWN_MULTICAST_PORT

Spec: §9.6.2.1, S. 182, Table 9.15 — “Multicast — SPDP_WELL_KNOWN_MULTICAST_PORT — PB + DG * domainId + d0”.

Repo: crates/rtps/src/wire_types.rs (spdp_multicast_port)

Tests: crates/rtps/src/wire_types.rs::tests::all_four_ports_follow_the_spec_formula, crates/rtps/src/wire_types.rs::tests::spdp_multicast_port_domain_0_is_7400

Status: done

§9.6.2.1 Table 9.15 SPDP_WELL_KNOWN_UNICAST_PORT

Spec: §9.6.2.1, S. 182, Table 9.15 — “Unicast — SPDP_WELL_KNOWN_UNICAST_PORT — PB + DG * domainId + d1 + PG * participantId”.

Repo: crates/rtps/src/wire_types.rs (spdp_unicast_port)

Tests: crates/rtps/src/wire_types.rs::tests::domain_zero_ports_match_the_worked_spec_example, crates/dcps/src/runtime.rs::tests::spdp_unicast_port_follows_rtps_formula

Status: done

§9.6.2.1 Eindeutige participantId je Knoten und Domain

Spec: §9.6.2.1, S. 182 — “Each Participant on the same node and in the same domain must use a unique participantId.” “participantId values ideally start at 0 and are incremented for each additional Participant on the same node and in the same domain.”

Repo: crates/dcps/src/runtime.rs (DcpsRuntime::start: participantId 0 bis 119, der erste freie SPDP-Unicast-Port; sonst ein freier Port)

Tests: crates/dcps/src/runtime.rs::tests::two_runtimes_discover_each_other_via_spdp, crates/dcps/src/runtime.rs::tests::expand_initial_peer_ip_only_yields_well_known_port_range

Status: done — ist keiner der 120 Ports frei, bindet ZeroDDS einen beliebigen Port und ist nur über Multicast erreichbar.

§9.6.2.1 SEDP auf den Ports von SPDP

Spec: §9.6.2.1, S. 182 — “The default ports used by the SEDP built-in Endpoints match those used by the SPDP. If a node chooses not to use the default ports for the SEDP, it can include the new port numbers as part of the information exchanged during the SPDP.”

Repo: crates/dcps/src/runtime.rs (Metatraffic-Locatoren = SPDP-Unicast- Socket und SPDP-Multicast-Gruppe)

Tests: crates/dcps/src/runtime.rs::tests::two_runtimes_discover_each_other_via_spdp

Status: done

§9.6.2.2 Table 9.16 Nutzerdaten: Multicast-Port

Spec: §9.6.2.2, S. 183, Table 9.16 — “Multicast — PB + DG * domainId + d2”. “User-defined Endpoints may choose to not use the default ports.”

Repo: crates/rtps/src/wire_types.rs (user_traffic_multicast_port); crates/dcps/src/runtime.rs (transport.user_multicast)

Tests: crates/rtps/src/wire_types.rs::tests::all_four_ports_follow_the_spec_formula, crates/dcps/src/runtime.rs::tests::the_user_multicast_port_is_d2_and_announced_unless_turned_off

Status: done — ZeroDDS-Endpunkte kündigen den Multicast-Locator auf PB + DG * domainId + d2 an (Vorgabe; transport.user_multicast: false für einen Host ohne Multicast). Erwartet: Cyclone DDS (kündigt 239.255.0.1 auf d2 an), Fast DDS und OpenDDS nehmen einen angekündigten Multicast-Locator an oder ignorieren ihn; ZeroDDS-Writer senden selbst nur an Unicast-Locators.

§9.6.2.2 Table 9.16 Nutzerdaten: Unicast-Port

Spec: §9.6.2.2, S. 183, Table 9.16 — “Unicast — PB + DG * domainId + d3 + PG * participantId”. “In that case, remote Endpoints obtain the port number as part of the information exchanged during the Simple Endpoint Discovery Protocol.”

Repo: crates/rtps/src/wire_types.rs (user_traffic_unicast_port); crates/dcps/src/runtime.rs (Nutzer-Socket auf einem frei gewählten Port, angekündigt als Default-Unicast-Locator)

Tests: crates/rtps/src/wire_types.rs::tests::the_four_ports_of_one_participant_are_distinct, crates/dcps/src/runtime.rs::tests::announce_locators_automatic_is_non_empty_and_includes_probe

Status: done — ZeroDDS verwendet nicht den Vorgabeport, sondern kündigt den gebundenen an, wie der Abschnitt erlaubt.

§9.6.2.3 Vorgabewerte PB, DG, PG, d0–d3

Spec: §9.6.2.3, S. 183 — “PB = 7400 DG = 250 PG = 2 d0 = 0 d1 = 10 d2 = 1 d3 = 11”.

Repo: crates/rtps/src/wire_types.rs (SPDP_PORT_BASE, SPDP_DOMAIN_GAIN, SPDP_PARTICIPANT_GAIN und die Offsets)

Tests: crates/rtps/src/wire_types.rs::tests::port_formula_constants_match_spec

Status: done

§9.6.2.3 Parameter für den Anwender einstellbar

Spec: §9.6.2.3, S. 183 — “Implementations must expose these parameters so they can be customized by the user.”

Repo: crates/rtps/src/wire_types.rs (PortMapping); crates/dcps/src/runtime.rs (RuntimeConfig::port_mapping, select_user_transport, user_port_fallbacks, transport.user_multicast); man/man5/zerodds.yaml.5

Tests: crates/rtps/src/wire_types.rs::tests::the_port_mapping_formulas_use_the_given_parameters, crates/dcps/tests/runtime_config_layering.rs::the_port_mapping_parameters_are_settings, crates/dcps/src/runtime.rs::tests::the_spdp_unicast_port_follows_the_configured_port_mapping, crates/dcps/src/runtime.rs::tests::the_user_unicast_socket_takes_the_d3_port_of_its_participant_id, crates/dcps/src/runtime.rs::tests::a_taken_user_port_is_counted_and_the_socket_takes_an_ephemeral_one, crates/dcps/src/runtime.rs::tests::the_user_multicast_port_is_d2_and_announced_unless_turned_off

Status: done — PB, DG, PG und d0 bis d3 sind Einstellungen (Datei und Umgebung, 0..=65535, Vorgabe die Spec-Werte). Der Runtime bindet die Discovery-Ports (d0, d1) und den Nutzer-Unicast-Socket auf PB + DG * domainId + d3 + PG * participantId mit der participantId des SPDP-Unicast-Sockets; ist der Port belegt, nimmt der Socket einen flüchtigen Port, das wird gezählt (user_port_fallbacks) und als Ereignis transport.user_unicast.port_taken protokolliert. Der Nutzer-Multicast-Port d2 wird mit transport.user_multicast gebunden (Beitritt zur SPDP-Gruppe, Empfang, Ankündigung als Default-Multicast-Locator); Vorgabe an (die Default-Locators von §9.6.2.3 enthalten d2), false für einen Host ohne Multicast. Gemessen in tools/wire-capture/rtps-sessions (Locators der SPDP-Ankündigungen): Fast DDS 2.6.10 und RTI 7.7.0 binden d1/d3 + PG * participantId (Fast DDS 23160/23161, 23162/23163; RTI 22910/22911, 22912/22913); Cyclone 11.0.1 nimmt flüchtige Ports für Metatraffic und Nutzerdaten (derselbe Port) und kündigt Default-Multicast 239.255.0.1 auf d2 an; OpenDDS 3.34.0 nimmt einen flüchtigen Metatraffic-Port und kündigt als Nutzer-Locator 127.0.0.1:12345 an (kein d3-Port). Nicht gemessen: ein Lauf gegen die Hersteller mit der Port-Änderung und das Verhalten von ZeroDDS-Writern gegenüber angekündigten Multicast-Locators (sie senden nur an Unicast-Locators).

§9.6.2.4 Default-Multicast-Adresse 239.255.0.1

Spec: §9.6.2.4, S. 183 — “DefaultMulticastLocator = {LOCATOR_KIND_UDPv4, “239.255.0.1”, PB + DG * domainId + d0}. All Participants must announce and listen on this multicast address.”

Repo: crates/rtps/src/wire_types.rs (SPDP_DEFAULT_MULTICAST_ADDRESS); crates/dcps/src/runtime.rs (spdp_multicast_group, Beitritt und Ankündigung)

Tests: crates/rtps/src/wire_types.rs::tests::spdp_default_multicast_is_239_255_0_1, crates/discovery/tests/spdp_loopback_e2e.rs::loopback_multicast_self_discovery

Status: done — die Gruppe ist einstellbar; ohne Multicast arbeitet ZeroDDS mit Initial-Peers.

§9.6.2.4 Default-Ankündigungsrate 30 Sekunden

Spec: §9.6.2.4, S. 183 — “The default rate by which SPDP periodic announcements are sent equals 30 seconds. SPDPbuiltinParticipantWriter. resendPeriod = {30, 0};”

Repo: crates/dcps/src/runtime.rs (DEFAULT_SPDP_PERIOD, default_spdp_period_for); man/man5/zerodds.yaml.5; packaging/linux/configs/zerodds.yaml.example

Tests: crates/dcps/src/runtime.rs::tests::a_short_lease_without_a_period_beacons_three_times_a_lease, crates/dcps/tests/runtime_config_layering.rs::the_protocol_timing_parameters_are_settings

Status: done — DEFAULT_SPDP_PERIOD = 30 s (YAML-Vorgabe, Man-Seite, Beispielkonfiguration); die früheren 5 s bleiben über discovery.spdp_period_ms: 5000 erreichbar. Eine Lease unter 90 s verkürzt die Vorgabe auf ein Drittel (§8.5.3.1).

§9.6.3.1 ParticipantMessageData: Struktur und Leitungsbild

Spec: §9.6.3.1, S. 184 — “struct ParticipantMessageData { GuidPrefix_t participantGuidPrefix; OctetArray4 kind; OctetSeq data; };” Leitungsbild: GuidPrefix_t participantGuidPrefix (12 Oktette), octet[4] kind, unsigned long data.length, octet[] data.value.

Repo: crates/rtps/src/participant_message_data.rs (ParticipantMessageData, to_cdr, from_cdr)

Tests: crates/rtps/src/participant_message_data.rs::tests::participant_message_data_octets_are_those_of_9_6_3_1, crates/rtps/src/participant_message_data.rs::tests::participant_message_data_reads_the_fast_dds_beat, crates/rtps/src/participant_message_data.rs::tests::participant_message_data_roundtrip_with_topic_token

Status: done

§9.6.3.1 ParticipantMessageData: Werte von kind

Spec: §9.6.3.1, S. 184 — “#define PARTICIPANT_MESSAGE_DATA_KIND_UNKNOWN {0x00, 0x00, 0x00, 0x00} #define PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE {0x00, 0x00, 0x00, 0x01} #define PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE {0x00, 0x00, 0x00, 0x02}”; “kind.value[0] & 0x80 == 1 // vendor specific kind”.

Repo: crates/rtps/src/participant_message_data.rs (PARTICIPANT_MESSAGE_DATA_KIND_*, ParticipantMessageData::is_vendor_kind)

Tests: crates/rtps/src/participant_message_data.rs::tests::participant_message_data_kind_constants_match_spec, crates/rtps/src/participant_message_data.rs::tests::participant_message_data_octets_are_those_of_9_6_3_1, crates/rtps/src/participant_message_data.rs::tests::participant_message_data_reads_the_fast_dds_beat

Status: done

§9.6.3.1 ParticipantMessageData: data mindestens 128 Oktette

Spec: §9.6.3.1, S. 184 — “Implementations can decide the upper length of the data field but must be able to support at least 128 bytes.”

Repo: crates/rtps/src/participant_message_data.rs (MAX_DATA_LEN = 4096)

Tests: crates/rtps/src/participant_message_data.rs::tests::participant_message_data_rejects_overlong_data, crates/rtps/src/participant_message_data.rs::tests::participant_message_data_encoder_caps_data_length

Status: done

§9.6.3.2 IDL der SPDP- und SEDP-Datentypen

Spec: §9.6.3.2, S. 184–185 — “struct SPDPdiscoveredParticipantData { … ParticipantProxy participantProxy; Duration_t leaseDuration; }; struct DiscoveredWriterData { … WriterProxy mWriterProxy; }; struct DiscoveredReaderData { … ReaderProxy mReaderProxy; ContentFilterProperty_t contentFilter; }; struct DiscoveredTopicData { DDS::TopicBuiltinTopicData ddsTopicData; };”

Repo: crates/rtps/src/participant_data.rs, crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs, crates/rtps/src/topic_data.rs

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies, crates/rtps/tests/sedp_qos_roundtrip.rs::subscription_data_roundtrip_preserves_reader_qos_policies

Status: done — die fehlenden Attribute sind unter §8.5.3.2 und §8.5.4.4 geführt.

§9.6.3.2 Discovery-Daten als ParameterList in CDR

Spec: §9.6.3.2, S. 185 — “the wire-representation of the SerializedData within the Data Submessage uses the format of a ParameterList SubmessageElement. … Within each parameter, the parameter value is represented using CDR.”

Repo: crates/rtps/src/participant_data.rs (to_pl_cdr_le, to_pl_cdr_be, from_pl_cdr_le); crates/rtps/src/publication_data.rs (to_pl_cdr_le)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_first_4_bytes_are_pl_cdr_le_encapsulation, crates/discovery/tests/vendor_discovery_frames.rs::opendds_announcements_read_and_write_back

Status: done

§9.6.3.2 Herstellerspezifisches EDP über eigenen ParameterId

Spec: §9.6.3.2, S. 185 — “As this is a vendor-specific parameterId, other vendors’ implementations would simply ignore the parameter and the information it contains.”

Repo: crates/rtps/src/publication_data.rs (Herstellerparameter nach VendorId)

Tests: crates/rtps/src/publication_data.rs::tests::a_foreign_vendors_0x8002_is_not_read_as_a_type_identifier

Status: done

§9.6.3.2 Keine redundanten Parameter

Spec: §9.6.3.2, S. 185 — “For optimization, implementations of the protocol shall not include a parameter in the Data submessage if it contains information that is redundant with other parameters already present in that same Data submessage.”

Repo: crates/rtps/src/participant_data.rs, crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full, crates/rtps/src/publication_data.rs::tests::roundtrip_le

Status: done — die einzelnen Fälle stehen unter Table 9.17.

§9.6.3.2 Table 9.17 SPDPdiscoveredParticipantData: ParticipantProxy::guidPrefix

Spec: §9.6.3.2, S. 185, Table 9.17 — “SPDPdiscoveredParticipantData — ParticipantProxy::guidPrefix — ParticipantBuiltinTopicData::key”.

Repo: crates/rtps/src/participant_data.rs (to_pl_cdr_le: nur PID_PARTICIPANT_GUID)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_decode_requires_guid_pid

Status: done

§9.6.3.2 Table 9.17 DiscoveredReaderData: ReaderProxy::remoteReaderGuid

Spec: §9.6.3.2, S. 185, Table 9.17 — “DiscoveredReaderData — ReaderProxy::remoteReaderGuid — SubscriptionBuiltinTopicData::key”.

Repo: crates/rtps/src/subscription_data.rs (to_pl_cdr_le: nur PID_ENDPOINT_GUID)

Tests: crates/rtps/src/subscription_data.rs::tests::roundtrip_le

Status: done

§9.6.3.2 Table 9.17 DiscoveredWriterData: WriterProxy::remoteWriterGuid

Spec: §9.6.3.2, S. 185, Table 9.17 — “DiscoveredWriterData — WriterProxy::remoteWriterGuid — PublicationBuiltinTopicData::key”.

Repo: crates/rtps/src/publication_data.rs (to_pl_cdr_le: nur PID_ENDPOINT_GUID)

Tests: crates/rtps/src/publication_data.rs::tests::decode_rejects_missing_endpoint_guid

Status: done

§9.6.3.2 Schlüssel-DATA der Builtin-Topics

Spec: §9.6.3.2, S. 185 — “In the case of a DATA submessage containing the SPDPdiscoveredParticipantData with KeyFlag=1, the only parameterId present within the ParameterList shall be the PID_PARTICIPANT_GUID. In the case of a DATA submessage containing one of SEDPdiscoveredPublicationData, SEDPdiscoveredSubscriptionData, or SEDPdiscoveredTopicData with KeyFlag=1, the only parameterId present within the ParameterList shall be the PID_ENDPOINT_GUID.”

Repo: crates/rtps/src/parameter_list.rs (spdp_participant_key_pl_cdr_le, sedp_endpoint_key_pl_cdr_le); crates/discovery/src/spdp.rs (serialize_departure)

Tests: crates/discovery/src/spdp.rs::tests::a_departure_reads_back_as_departed_with_key_and_status, crates/rtps/src/parameter_list.rs::tests::sedp_endpoint_key_matches_the_measured_cyclone_octets

Status: done

§9.6.3.2 Table 9.18/9.19 PID_PAD

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_PAD — 0x0000 — N/A”; Table 9.19, S. 187 — “PID_PAD — - — N/A”.

Repo: crates/rtps/src/parameter_list.rs (pid::PAD, ParameterList::from_bytes_with_consumed)

Tests: crates/rtps/src/parameter_list.rs::tests::pid_pad_is_skipped

Status: done

§9.6.3.2 Table 9.18/9.19 PID_SENTINEL

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_SENTINEL — 0x0001 — N/A”.

Repo: crates/qos/src/pid.rs (Pid::SENTINEL); crates/rtps/src/parameter_list.rs

Tests: crates/rtps/src/parameter_list.rs::tests::empty_parameter_list_is_just_sentinel

Status: done

§9.6.3.2 Table 9.18/9.19 PID_USER_DATA

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_USER_DATA — 0x002c — UserDataQosPolicy”; Table 9.19, S. 187 — ParticipantBuiltinTopicData, PublicationBuiltinTopicData, SubscriptionBuiltinTopicData user_data, Vorgabe “See DDS Specification”.

Repo: crates/qos/src/pid.rs (Pid::USER_DATA); crates/rtps/src/participant_data.rs, crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs (user_data)

Tests: crates/rtps/tests/user_data_propagation.rs::participant_user_data_roundtrip, crates/rtps/tests/user_data_propagation.rs::subscription_user_data_roundtrip, crates/rtps/tests/user_data_propagation.rs::publication_empty_user_data_omits_pid

Status: done

§9.6.3.2 Table 9.18/9.19 PID_TOPIC_NAME

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_TOPIC_NAME — 0x0005 — string<256>”; Table 9.19, S. 187 — TopicBuiltinTopicData::name, Publication/Subscription topic_name, Vorgabe N/A.

Repo: crates/rtps/src/parameter_list.rs (pid::TOPIC_NAME); crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs, crates/rtps/src/topic_data.rs

Tests: crates/rtps/src/publication_data.rs::tests::roundtrip_utf8_topic_name, crates/rtps/src/publication_data.rs::tests::decode_rejects_missing_topic_name, crates/rtps/src/publication_data.rs::tests::topic_and_type_names_are_bounded_by_string_256

Status: done

§9.6.3.2 Table 9.18/9.19 PID_TYPE_NAME

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_TYPE_NAME — 0x0007 — string<256>”; Table 9.19, S. 187 — TopicBuiltinTopicData, Publication/Subscription type_name, Vorgabe N/A.

Repo: crates/rtps/src/parameter_list.rs (pid::TYPE_NAME); crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs, crates/rtps/src/topic_data.rs

Tests: crates/rtps/src/publication_data.rs::tests::decode_rejects_missing_type_name, crates/rtps/src/publication_data.rs::tests::roundtrip_le, crates/rtps/src/publication_data.rs::tests::topic_and_type_names_are_bounded_by_string_256

Status: done

§9.6.3.2 string<256> für Namen und domainTag

Spec: §9.6.3.2, S. 186, Table 9.18 — PID_TOPIC_NAME, PID_TYPE_NAME, PID_DOMAIN_TAG: “string<256>”.

Repo: crates/rtps/src/publication_data.rs (STRING_256_MAX, encode_bounded_cdr_string_le, decode_bounded_cdr_string); crates/dcps/src/participant.rs; crates/dcps/src/runtime.rs (start)

Tests: crates/rtps/src/publication_data.rs::tests::topic_and_type_names_are_bounded_by_string_256, crates/rtps/src/participant_data.rs::tests::a_domain_tag_longer_than_string_256_is_refused, crates/dcps/src/participant.rs::tests::create_topic_rejects_a_name_longer_than_string_256

Status: done — Topic-, Typ- und domainTag-Namen sind auf 256 Oktette begrenzt: Senden und Lesen weisen mehr ab (die Ankündigung eines Peers mit längerem Namen wird abgewiesen und gezählt), create_topic und DcpsRuntime::start lehnen sie ab.

§9.6.3.2 Table 9.18/9.19 PID_GROUP_DATA

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_GROUP_DATA — 0x002d — GroupDataQosPolicy”; Table 9.19, S. 187 — Publication/Subscription group_data.

Repo: crates/qos/src/pid.rs (Pid::GROUP_DATA); crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs

Tests: crates/rtps/src/publication_data.rs::tests::user_topic_and_group_data_survive_the_sedp_roundtrip, crates/rtps/tests/sedp_qos_roundtrip.rs::topic_data_and_group_data_survive_the_builtin_topic_untouched

Status: done

§9.6.3.2 Table 9.18/9.19 PID_TOPIC_DATA

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_TOPIC_DATA — 0x002e — TopicDataQosPolicy”; Table 9.19, S. 187 — TopicBuiltinTopicData, Publication/Subscription topic_data.

Repo: crates/qos/src/pid.rs (Pid::TOPIC_DATA); crates/rtps/src/topic_data.rs, crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs

Tests: crates/rtps/src/publication_data.rs::tests::user_topic_and_group_data_survive_the_sedp_roundtrip, crates/rtps/tests/sedp_qos_roundtrip.rs::topic_data_and_group_data_survive_the_builtin_topic_untouched

Status: done

§9.6.3.2 Table 9.18/9.19 PID_DURABILITY

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_DURABILITY — 0x001d — DurabilityQosPolicy”; Table 9.19, S. 187 — Topic, Publication, Subscription durability.

Repo: crates/qos/src/pid.rs (Pid::DURABILITY); crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs, crates/rtps/src/topic_data.rs

Tests: crates/rtps/src/publication_data.rs::tests::durability_try_from_u32_rejects_unknown, crates/rtps/tests/sedp_qos_roundtrip.rs::defaults_roundtrip_stays_default

Status: done

§9.6.3.2 Table 9.18/9.19 PID_DURABILITY_SERVICE

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_DURABILITY_SERVICE — 0x001e — DurabilityServiceQosPolicy”; Table 9.19, S. 187 — Topic, Publication durability_service.

Repo: crates/qos/src/pid.rs (Pid::DURABILITY_SERVICE); crates/rtps/src/publication_data.rs, crates/rtps/src/topic_data.rs

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies, crates/qos/src/policies/durability_service.rs::tests::default_matches_spec

Status: done

§9.6.3.2 Table 9.18/9.19 PID_DEADLINE

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_DEADLINE — 0x0023 — DeadlineQosPolicy”; Table 9.19, S. 188 — Topic, Publication, Subscription deadline.

Repo: crates/qos/src/pid.rs (Pid::DEADLINE)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies, crates/rtps/tests/sedp_qos_roundtrip.rs::subscription_data_roundtrip_preserves_reader_qos_policies

Status: done

§9.6.3.2 Table 9.18/9.19 PID_LATENCY_BUDGET

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_LATENCY_BUDGET — 0x0027 — LatencyBudgetQosPolicy”; Table 9.19, S. 188 — Topic, Publication, Subscription latency_budget.

Repo: crates/qos/src/pid.rs (Pid::LATENCY_BUDGET)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies, crates/rtps/tests/sedp_qos_roundtrip.rs::subscription_data_roundtrip_preserves_reader_qos_policies

Status: done

§9.6.3.2 Table 9.18/9.19 PID_LIVELINESS

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_LIVELINESS — 0x001b — LivelinessQosPolicy”; Table 9.19, S. 188 — Topic, Publication, Subscription liveliness.

Repo: crates/qos/src/pid.rs (Pid::LIVELINESS)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies, crates/discovery/tests/vendor_discovery_frames.rs::cyclone_announcements_read_and_write_back

Status: done

§9.6.3.2 Table 9.18/9.19 PID_RELIABILITY

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_RELIABILITY — 0x001a — ReliabilityQosPolicy” mit Fußnote 3: “The encoding of DDS::ReliabilityQoSPolicy::kind is defined by RTPS::ReliabilityKind_t (9.3.2)”; Table 9.19, S. 188 — Topic, Publication, Subscription reliability.

Repo: crates/qos/src/pid.rs (Pid::RELIABILITY); crates/rtps/src/publication_data.rs (Art als 1/2)

Tests: crates/rtps/src/publication_data.rs::tests::an_absent_reliability_parameter_reads_as_reliable_on_a_publication, crates/rtps/src/publication_data.rs::tests::reliability_try_from_u32_rejects_unknown

Status: done

§9.6.3.2 Table 9.18/9.19 PID_LIFESPAN

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_LIFESPAN — 0x002b — LifespanQosPolicy”; Table 9.19, S. 188 — Topic, Publication lifespan.

Repo: crates/qos/src/pid.rs (Pid::LIFESPAN)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies

Status: done

§9.6.3.2 Table 9.18/9.19 PID_DESTINATION_ORDER

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_DESTINATION_ORDER — 0x0025 — DestinationOrderQosPolicy”; Table 9.19, S. 188 — Topic, Publication, Subscription destination_order.

Repo: crates/qos/src/pid.rs (Pid::DESTINATION_ORDER)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies, crates/qos/src/policies/destination_order.rs::tests::roundtrip

Status: done

§9.6.3.2 Table 9.18/9.19 PID_HISTORY

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_HISTORY — 0x0040 — HistoryQosPolicy”; Table 9.19, S. 188 — TopicBuiltinTopicData::history.

Repo: crates/qos/src/pid.rs (Pid::HISTORY); crates/rtps/src/topic_data.rs

Tests: crates/discovery/src/sedp/stack.rs::tests::two_stacks_exchange_a_topic_its_new_qos_and_its_dispose

Status: done

§9.6.3.2 Table 9.18/9.19 PID_RESOURCE_LIMITS

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_RESOURCE_LIMITS — 0x0041 — ResourceLimitsQosPolicy”; Table 9.19, S. 188 — TopicBuiltinTopicData::resource_limits.

Repo: crates/qos/src/pid.rs (Pid::RESOURCE_LIMITS); crates/rtps/src/topic_data.rs

Tests: crates/discovery/src/sedp/stack.rs::tests::two_stacks_exchange_a_topic_its_new_qos_and_its_dispose

Status: done

§9.6.3.2 Table 9.18/9.19 PID_OWNERSHIP

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_OWNERSHIP — 0x001f — OwnershipQosPolicy”; Table 9.19, S. 188 — Topic, Publication, Subscription ownership.

Repo: crates/qos/src/pid.rs (Pid::OWNERSHIP)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies, crates/rtps/tests/sedp_qos_roundtrip.rs::subscription_data_roundtrip_preserves_reader_qos_policies

Status: done

§9.6.3.2 Table 9.18/9.19 PID_OWNERSHIP_STRENGTH

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_OWNERSHIP_STRENGTH — 0x0006 — OwnershipStrengthQosPolicy”; Table 9.19, S. 188 — PublicationBuiltinTopicData::ownership_strength.

Repo: crates/qos/src/pid.rs (Pid::OWNERSHIP_STRENGTH)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies

Status: done

§9.6.3.2 Table 9.18/9.19 PID_PRESENTATION

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_PRESENTATION — 0x0021 — PresentationQosPolicy”; Table 9.19, S. 188 — Publication, Subscription presentation.

Repo: crates/qos/src/pid.rs (Pid::PRESENTATION)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies, crates/rtps/tests/sedp_qos_roundtrip.rs::subscription_data_roundtrip_preserves_reader_qos_policies

Status: done

§9.6.3.2 Table 9.18/9.19 PID_PARTITION

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_PARTITION — 0x0029 — PartitionQosPolicy”; Table 9.19, S. 188 — Publication, Subscription partition.

Repo: crates/qos/src/pid.rs (Pid::PARTITION)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::publication_data_roundtrip_preserves_all_new_qos_policies, crates/dcps/src/runtime.rs::tests::a_partition_change_unmatches_without_a_status_and_is_announced

Status: done

§9.6.3.2 Table 9.18/9.19 PID_TIME_BASED_FILTER

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_TIME_BASED_FILTER — 0x0004 — TimeBasedFilterQosPolicy”; Table 9.19, S. 188 — SubscriptionBuiltinTopicData::time_based_filter.

Repo: crates/qos/src/pid.rs (Pid::TIME_BASED_FILTER); crates/rtps/src/subscription_data.rs

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::subscription_data_roundtrip_preserves_reader_qos_policies

Status: done

§9.6.3.2 Table 9.18 PID_TRANSPORT_PRIORITY

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_TRANSPORT_PRIORITY — 0x0049 — TransportPriorityQoSPolicy”. Table 9.19 führt keine Zeile dafür.

Repo: crates/qos/src/pid.rs (Pid::TRANSPORT_PRIORITY); crates/rtps/src/topic_data.rs; crates/rtps/src/publication_data.rs (Inline-QoS)

Tests: crates/rtps/src/publication_data.rs::tests::a_transport_priority_goes_in_line_and_not_into_the_announcement

Status: done

§9.6.3.2 Table 9.18/9.19 PID_DOMAIN_ID

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID__DOMAIN_ID — 0x000f — DomainId_t”; Table 9.19, S. 188 — ParticipantProxy::domainId, Vorgabe “The domainId of the local participant receiving the SPDPdiscoveredParticipantData”.

Repo: crates/rtps/src/parameter_list.rs (pid::DOMAIN_ID); crates/dcps/src/runtime.rs (spdp_announced: fehlend = eigene Domain)

Tests: crates/dcps/src/runtime.rs::tests::a_participant_of_another_domain_id_is_not_discovered, crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§9.6.3.2 Table 9.18/9.19 PID_DOMAIN_TAG

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_DOMAIN_TAG — 0x4014 — string<256>”; Table 9.19, S. 188 — ParticipantProxy::domainTag, Vorgabe ““” (empty, zero-length string)”.

Repo: crates/rtps/src/parameter_list.rs (pid::DOMAIN_TAG); crates/rtps/src/participant_data.rs (fehlend = leer)

Tests: crates/rtps/src/participant_data.rs::tests::domain_tag_goes_out_when_set_and_reads_back, crates/rtps/src/participant_data.rs::tests::domain_tag_is_a_standard_must_understand_pid, crates/rtps/src/participant_data.rs::tests::a_domain_tag_longer_than_string_256_is_refused

Status: done

§9.6.3.2 Table 9.18/9.19 PID_PROTOCOL_VERSION

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_PROTOCOL_VERSION — 0x0015 — ProtocolVersion_t”; Table 9.19, S. 188 — ParticipantProxy::protocolVersion.

Repo: crates/rtps/src/parameter_list.rs (pid::PROTOCOL_VERSION); crates/rtps/src/participant_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§9.6.3.2 Table 9.18/9.19 PID_VENDORID

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_VENDORID — 0x0016 — VendorId_t”; Table 9.19, S. 188 — ParticipantProxy::vendorId.

Repo: crates/rtps/src/parameter_list.rs (pid::VENDOR_ID); crates/rtps/src/participant_data.rs, crates/rtps/src/publication_data.rs

Tests: crates/rtps/src/publication_data.rs::tests::a_foreign_vendor_id_survives_read_and_write_back, crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§9.6.3.2 Table 9.18/9.19 PID_UNICAST_LOCATOR

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_UNICAST_LOCATOR — 0x002f — Locator_t”; Table 9.19, S. 188 — ReaderProxy/WriterProxy::unicastLocatorList.

Repo: crates/rtps/src/parameter_list.rs (pid::UNICAST_LOCATOR); crates/rtps/src/publication_data.rs (collect_locator_params)

Tests: crates/rtps/src/publication_data.rs::tests::locator_params_of_a_big_endian_list_are_read

Status: done

§9.6.3.2 Table 9.18/9.19 PID_MULTICAST_LOCATOR

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_MULTICAST_LOCATOR — 0x0030 — Locator_t”; Table 9.19, S. 188 — ReaderProxy/WriterProxy::multicastLocatorList.

Repo: crates/rtps/src/parameter_list.rs (pid::MULTICAST_LOCATOR); crates/rtps/src/publication_data.rs (collect_locator_params)

Tests: crates/rtps/src/publication_data.rs::tests::locator_params_of_a_big_endian_list_are_read

Status: done

§9.6.3.2 Endpunkt-Locatoren in PL_CDR_BE

Spec: §9.6.3.2, Table 9.19, S. 188 — PID_UNICAST_LOCATOR und PID_MULTICAST_LOCATOR für ReaderProxy und WriterProxy; §9.6.3.2, S. 185: “Within each parameter, the parameter value is represented using CDR.”

Repo: —

Tests: crates/rtps/src/publication_data.rs::tests::locator_params_of_a_big_endian_list_are_read

Status: done

§9.6.3.2 Table 9.18/9.19 PID_DEFAULT_UNICAST_LOCATOR

Spec: §9.6.3.2, S. 186, Table 9.18 — “PID_DEFAULT_UNICAST_LOCATOR — 0x0031 — Locator_t”; Table 9.19, S. 188 — ParticipantProxy::defaultUnicastLocatorList.

Repo: crates/rtps/src/parameter_list.rs (pid::DEFAULT_UNICAST_LOCATOR); crates/rtps/src/participant_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::decode_retains_all_repeated_unicast_locators_in_order_le_and_be

Status: done

§9.6.3.2 Table 9.18/9.19 PID_DEFAULT_MULTICAST_LOCATOR

Spec: §9.6.3.2, S. 187, Table 9.18 — “PID_DEFAULT_MULTICAST_LOCATOR — 0x0048 — Locator_t”; Table 9.19, S. 189 — ParticipantProxy::defaultMulticastLocatorList.

Repo: crates/rtps/src/parameter_list.rs (pid::DEFAULT_MULTICAST_LOCATOR); crates/rtps/src/participant_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§9.6.3.2 Table 9.18/9.19 PID_METATRAFFIC_UNICAST_LOCATOR

Spec: §9.6.3.2, S. 187, Table 9.18 — “PID_METATRAFFIC_UNICAST_LOCATOR — 0x0032 — Locator_t”; Table 9.19, S. 189 — ParticipantProxy::metatrafficUnicastLocatorList.

Repo: crates/rtps/src/parameter_list.rs (pid::METATRAFFIC_UNICAST_LOCATOR); crates/rtps/src/participant_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::decode_retains_all_repeated_unicast_locators_in_order_le_and_be

Status: done

§9.6.3.2 Table 9.18/9.19 PID_METATRAFFIC_MULTICAST_LOCATOR

Spec: §9.6.3.2, S. 187, Table 9.18 — “PID_METATRAFFIC_MULTICAST_LOCATOR — 0x0033 — Locator_t”; Table 9.19, S. 189 — ParticipantProxy::metatrafficMulticastLocatorList.

Repo: crates/rtps/src/parameter_list.rs (pid::METATRAFFIC_MULTICAST_LOCATOR); crates/rtps/src/participant_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_roundtrip_full

Status: done

§9.6.3.2 Table 9.18/9.19 PID_EXPECTS_INLINE_QOS

Spec: §9.6.3.2, S. 187, Table 9.18 — “PID_EXPECTS_INLINE_QOS — 0x0043 — boolean”; Table 9.19, S. 189 — ParticipantProxy::expectsInlineQos, Vorgabe FALSE.

Repo: crates/rtps/src/parameter_list.rs (pid::EXPECTS_INLINE_QOS); crates/rtps/src/participant_data.rs, crates/rtps/src/subscription_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::expects_inline_qos_goes_out_when_set_and_reads_back, crates/rtps/src/subscription_data.rs::tests::expects_inline_qos_goes_out_when_set_and_reads_back

Status: done

§9.6.3.2 Table 9.18/9.19 PID_PARTICIPANT_MANUAL_LIVELINESS_COUNT

Spec: §9.6.3.2, S. 187, Table 9.18 — “PID_PARTICIPANT_MANUAL_LIVELINESS_COUNT — 0x0034 — Count_t”; Table 9.19, S. 189 — ParticipantProxy::manualLivelinessCount.

Repo: crates/rtps/src/parameter_list.rs (pid::PARTICIPANT_MANUAL_LIVELINESS_COUNT); crates/rtps/src/participant_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::manual_liveliness_count_and_builtin_endpoint_qos_go_out_and_read_back, crates/discovery/tests/vendor_discovery_frames.rs::opendds_announcements_read_and_write_back

Status: done — gelesen, geschrieben und in is_standard_pid; OpenDDS sendet 0 und bekommt 0 zurück.

§9.6.3.2 Table 9.18/9.19 PID_PARTICIPANT_LEASE_DURATION

Spec: §9.6.3.2, S. 187, Table 9.18 — “PID_PARTICIPANT_LEASE_DURATION — 0x0002 — Duration_t”; Table 9.19, S. 189 — SPDPdiscoveredParticipantData::leaseDuration, Vorgabe {100, 0}.

Repo: crates/rtps/src/parameter_list.rs (pid::PARTICIPANT_LEASE_DURATION); crates/rtps/src/participant_data.rs (fehlend = 100 s)

Tests: crates/rtps/src/participant_data.rs::tests::to_pl_cdr_be_is_big_endian_roundtrips_and_omits_credential_tokens

Status: done

§9.6.3.2 PID_PARTICIPANT_LEASE_DURATION in PL_CDR_BE

Spec: §9.6.3.2, S. 185 — “Within each parameter, the parameter value is represented using CDR.”; Table 9.18: Duration_t.

Repo: —

Tests: crates/rtps/src/participant_data.rs::tests::to_pl_cdr_be_is_big_endian_roundtrips_and_omits_credential_tokens

Status: done

§9.6.3.2 Table 9.18/9.19 PID_CONTENT_FILTER_PROPERTY

Spec: §9.6.3.2, S. 187, Table 9.18 — “PID_CONTENT_FILTER_PROPERTY — 0x0035 — ContentFilterProperty_t”; Table 9.19, S. 189 — DiscoveredReaderData::contentFilter.

Repo: crates/rtps/src/parameter_list.rs (pid::CONTENT_FILTER_PROPERTY); crates/rtps/src/subscription_data.rs

Tests: crates/rtps/src/subscription_data.rs::tests::subscription_with_content_filter_roundtrip_le

Status: done

§9.6.3.2 Table 9.18/9.19 PID_PARTICIPANT_GUID

Spec: §9.6.3.2, S. 187, Table 9.18 — “PID_PARTICIPANT_GUID — 0x0050 — GUID_t”; Table 9.19, S. 189 — ParticipantBuiltinTopicData::key, Publication/Subscription participant_key.

Repo: crates/rtps/src/parameter_list.rs (pid::PARTICIPANT_GUID); crates/rtps/src/participant_data.rs, crates/rtps/src/publication_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_decode_requires_guid_pid, crates/rtps/src/publication_data.rs::tests::participant_key_fallback_when_pid_missing

Status: done

§9.6.3.2 Table 9.18/9.19 PID_GROUP_GUID

Spec: §9.6.3.2, S. 187, Table 9.18 — “PID_GROUP_GUID — 0x0052 — GUID_t”; Table 9.19 — WriterProxy/ReaderProxy::remoteGroupGuid, Vorgabe GUID_UNKNOWN.

Repo: —

Tests: crates/rtps/src/publication_data.rs::tests::the_writers_group_travels_as_pid_group_guid

Status: done

§9.6.3.2 Table 9.18/9.19 PID_GROUP_ENTITY_ID

Spec: §9.6.3.2, S. 187, Table 9.18 — “PID_GROUP_ENTITY_ID — 0x0053 — EntityId_t”; Table 9.19, S. 189 — WriterProxy/ReaderProxy::remoteGroupGuid.entityId, Vorgabe ENTITYID_UNKNOWN.

Repo: —

Tests: crates/rtps/src/publication_data.rs::tests::the_writers_group_travels_as_pid_group_guid

Status: done — gelesen; ZeroDDS sendet die Gruppe als volle GUID in PID_GROUP_GUID.

§9.6.3.2 Table 9.18/9.19 PID_BUILTIN_ENDPOINT_SET

Spec: §9.6.3.2, S. 187, Table 9.18 — “PID_BUILTIN_ENDPOINT_SET — 0x0058 — BuiltinEndpointSet_t”; Table 9.19, S. 189 — ParticipantProxy::availableBuiltinEndpoints.

Repo: crates/rtps/src/parameter_list.rs (pid::BUILTIN_ENDPOINT_SET); crates/rtps/src/participant_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::endpoint_flag_roundtrip_through_pl_cdr

Status: done

§9.6.3.2 Table 9.18/9.19 PID_BUILTIN_ENDPOINT_QOS

Spec: §9.6.3.2, S. 187, Table 9.18 — “PID_BUILTIN_ENDPOINT_QOS — 0x0077 — BuiltinEndpointQos_t”; Table 9.19, S. 189 — ParticipantProxy::builtinEndpointQos.

Repo: crates/rtps/src/parameter_list.rs (pid::BUILTIN_ENDPOINT_QOS); crates/rtps/src/participant_data.rs

Tests: crates/rtps/src/participant_data.rs::tests::manual_liveliness_count_and_builtin_endpoint_qos_go_out_and_read_back, crates/discovery/tests/vendor_discovery_frames.rs::opendds_announcements_read_and_write_back

Status: done — gelesen, geschrieben und in is_standard_pid.

§9.6.3.2 Table 9.18 PID_PROPERTY_LIST

Spec: §9.6.3.2, S. 187, Table 9.18 — “PID_PROPERTY_LIST — 0x0059 — sequence”. Table 9.19 führt keine Zeile dafür.

Repo: crates/rtps/src/parameter_list.rs (pid::PROPERTY_LIST); crates/rtps/src/participant_data.rs (properties); crates/rtps/src/property_list.rs (WirePropertyList::decode)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_properties_roundtrip, crates/rtps/src/participant_data.rs::tests::participant_data_empty_properties_omits_pid, crates/rtps/src/property_list.rs::tests::decode_reads_the_rtps_form_without_binary_value

Status: done — gesendet in SPDP und, wo ein Endpoint Properties hat, in SEDP, in der Form von DDS-Security 1.2 §7.5.1.4 (mit binary_value). Gelesen werden beide Formen; eine Liste, die nach ihren Properties endet (diese Zeile), hat keine binären Einträge.

§9.6.3.2 Table 9.18/9.19 PID_TYPE_MAX_SIZE_SERIALIZED

Spec: §9.6.3.2, S. 187, Table 9.18 — “PID_TYPE_MAX_SIZE_SERIALIZED — 0x0060 — long”; Table 9.19, S. 189 — “PID_DATA_MAX_SIZE_SERIALIZED — WriterProxy::dataMaxSizeSerialized”.

Repo: crates/rtps/src/publication_data.rs (data_max_size_serialized)

Tests: crates/rtps/src/publication_data.rs::tests::the_max_payload_size_and_the_name_of_a_writer_travel, crates/rtps/src/reliable_reader.rs::tests::a_payload_beyond_the_announced_maximum_is_refused_and_counted

Status: done — Publications senden und lesen den PID als long (PublicationBuiltinTopicData::data_max_size_serialized); in vendor_discovery_frames.rs ist 0x0060 nicht mehr unter den verworfenen PIDs. Gemessen in tools/wire-capture/rtps-sessions/rti: RTI 7.7.0 kündigt den Wert 8 an, und das DATA seines Writers trägt ein SerializedPayload von 8 Oktetten, den Encapsulation-Header eingerechnet; der Wert zählt also wie die Spec mit Header. Fast DDS 2.6.10 kündigt 12, 32 und 52 an (kein Nutzer-DATA im Mitschnitt); Cyclone und OpenDDS kündigen den PID nicht an. Ein Reader weist ein Payload ab, das den genannten Wert überschreitet. Nicht gemessen: ein Lauf gegen die Hersteller mit diesem Abweis.

§9.6.3.2 Table 9.18 PID_ENTITY_NAME

Spec: §9.6.3.2, S. 187, Table 9.18 — “PID_ENTITY_NAME — 0x0062 — EntityName_t”. Table 9.19 führt keine Zeile dafür.

Repo: crates/rtps/src/participant_data.rs, crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs (entity_name); crates/dcps/src/runtime.rs (built_entity_name, built_participant_name, RuntimeConfig::participant_name)

Tests: crates/rtps/src/participant_data.rs::tests::the_participant_name_goes_out_and_reads_back, crates/rtps/src/publication_data.rs::tests::the_max_payload_size_and_the_name_of_a_writer_travel

Status: done — Participant, Writer und Reader senden und lesen PID_ENTITY_NAME als EntityName_t (CDR-String). Die DCPS-API hat keine EntityName-QoS; die Namen sind gebaut: Participant zerodds: und das GUID-Präfix in Hex (überschreibbar mit discovery.participant_name), Writer und Reader DataWriter:<Topic>:<EntityId hex> bzw. DataReader:…. UserWriterConfig::entity_name und UserReaderConfig::entity_name nehmen einen gesetzten Namen. Ein nicht lesbarer Name (kein gültiger CDR-String) verwirft die Ankündigung wie ein nicht lesbarer domainTag.

§9.6.3.2 Table 9.18/9.19 PID_ENDPOINT_GUID

Spec: §9.6.3.2, S. 187, Table 9.18 — “PID_ENDPOINT_GUID — 0x005a — GUID_t”; Table 9.19, S. 189 — Topic-, Subscription-, PublicationBuiltinTopicData::key.

Repo: crates/rtps/src/parameter_list.rs (pid::ENDPOINT_GUID); crates/rtps/src/publication_data.rs, crates/rtps/src/topic_data.rs

Tests: crates/rtps/src/publication_data.rs::tests::decode_rejects_missing_endpoint_guid, crates/discovery/src/sedp/stack.rs::tests::two_stacks_exchange_a_topic_its_new_qos_and_its_dispose

Status: done

§9.6.3.2 Vorgaben “See DDS Specification” für fehlende QoS-PIDs

Spec: §9.6.3.2, Table 9.19, S. 187–188 — die QoS-Zeilen nennen als Vorgabe “See DDS Specification.”; §9.6.3.2: “Unrecognized parameterIDs shall be treated as specified in Table 9.6.”

Repo: crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs, crates/rtps/src/topic_data.rs (unwrap_or_default je Policy)

Tests: crates/rtps/tests/sedp_qos_roundtrip.rs::defaults_roundtrip_stays_default, crates/rtps/src/publication_data.rs::tests::an_absent_reliability_parameter_reads_as_reliable_on_a_publication

Status: done

§9.6.4 Inline-QoS-ParameterIds

Spec: §9.6.4, S. 189 — “Sub clause 8.7.2.1 defines the complete set of parameters that can appear within the inlineQos SubmessageElement. The corresponding set of parameterIds is listed in Table 9.20. Unrecognized parameterIDs shall be treated as specified in Table 9.6.”

Repo: crates/rtps/src/inline_qos.rs; crates/rtps/src/parameter_list.rs

Tests: crates/rtps/src/inline_qos.rs::tests::roundtrip_in_data_submessage_inline_qos, crates/rtps/src/datagram.rs::tests::decode_accepts_data_with_known_must_understand_pid_in_inline_qos

Status: done — die Behandlung unbekannter PIDs ist unter §9.4.2.11 Table 9.6 geführt.

§9.6.4 Table 9.20 PID_PAD

Spec: §9.6.4, S. 189, Table 9.20 — “PID_PAD — N/A”.

Repo: crates/rtps/src/parameter_list.rs (pid::PAD, ParameterList::from_bytes_with_consumed)

Tests: crates/rtps/src/parameter_list.rs::tests::pid_pad_is_skipped

Status: done

§9.6.4 Table 9.20 PID_SENTINEL

Spec: §9.6.4, S. 189, Table 9.20 — “PID_SENTINEL — N/A”.

Repo: crates/rtps/src/parameter_list.rs (pid::SENTINEL)

Tests: crates/rtps/src/parameter_list.rs::tests::empty_parameter_list_is_just_sentinel

Status: done

§9.6.4 Table 9.20 PID_TOPIC_NAME

Spec: §9.6.4, S. 189, Table 9.20 — “PID_TOPIC_NAME — See Table 9.18 — string<256>”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_DURABILITY

Spec: §9.6.4, S. 189, Table 9.20 — “PID_DURABILITY — See Table 9.18 — DurabilityQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_PRESENTATION

Spec: §9.6.4, S. 189, Table 9.20 — “PID_PRESENTATION — PresentationQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_DEADLINE

Spec: §9.6.4, S. 190, Table 9.20 — “PID_DEADLINE — DeadlineQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_LATENCY_BUDGET

Spec: §9.6.4, S. 190, Table 9.20 — “PID_LATENCY_BUDGET — LatencyBudgetQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_OWNERSHIP

Spec: §9.6.4, S. 190, Table 9.20 — “PID_OWNERSHIP — OwnershipQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_OWNERSHIP_STRENGTH

Spec: §9.6.4, S. 190, Table 9.20 — “PID_OWNERSHIP_STRENGTH — OwnershipStrengthQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_LIVELINESS

Spec: §9.6.4, S. 190, Table 9.20 — “PID_LIVELINESS — LivelinessQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_PARTITION

Spec: §9.6.4, S. 190, Table 9.20 — “PID_PARTITION — PartitionQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_RELIABILITY

Spec: §9.6.4, S. 190, Table 9.20 — “PID_RELIABILITY — ReliabilityQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_TRANSPORT_PRIORITY

Spec: §9.6.4, S. 190, Table 9.20 — “PID_TRANSPORT_PRIORITY — TransportPriorityQoSPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::a_transport_priority_goes_in_line_and_not_into_the_announcement

Status: done

§9.6.4 Table 9.20 PID_LIFESPAN

Spec: §9.6.4, S. 190, Table 9.20 — “PID_LIFESPAN — LifespanQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_DESTINATION_ORDER

Spec: §9.6.4, S. 190, Table 9.20 — “PID_DESTINATION_ORDER — DestinationOrderQosPolicy”.

Repo: crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::inline_qos)

Tests: crates/rtps/src/publication_data.rs::tests::inline_qos_is_the_announcements_in_line_policies_and_the_topic_name

Status: done

§9.6.4 Table 9.20 PID_CONTENT_FILTER_INFO (0x0055)

Spec: §9.6.4, S. 190, Table 9.20 — “PID_CONTENT_FILTER_INFO — 0x0055 — ContentFilterInfo_t”.

Repo: —

Tests: —

Status: open — ZeroDDS kennt den PID nicht; ein empfangener Parameter wird als unbekannter PID ohne Must-Understand-Bit übergangen. Teil der optionalen Filterung auf der Writer-Seite (§8.7.3), die ZeroDDS nicht ausführt.

§9.6.4 Table 9.20 PID_COHERENT_SET (0x0056)

Spec: §9.6.4, S. 190, Table 9.20 — “PID_COHERENT_SET — 0x0056 — SequenceNumber_t”.

Repo: crates/rtps/src/parameter_list.rs (pid::COHERENT_SET); crates/rtps/src/inline_qos.rs (coherent_set_inline_qos, find_coherent_set)

Tests: crates/rtps/src/inline_qos.rs::tests::coherent_set_param_is_pid_0x0056_with_sequence_number_layout, crates/rtps/src/inline_qos.rs::tests::coherent_set_roundtrip_both_endiannesses

Status: done

§9.6.4 Table 9.20 PID_DIRECTED_WRITE (0x0057)

Spec: §9.6.4, S. 190, Table 9.20 — “PID_DIRECTED_WRITE — 0x0057 — GUID_t” mit Fußnote 4: “RTPS protocol versions prior to 2.4 defined this as a sequence. … when interacting with protocol versions earlier than 2.4 this parameter should be ignored unless the receiver knows the format used by the vendor”.

Repo: crates/rtps/src/parameter_list.rs (pid::DIRECTED_WRITE); crates/rtps/src/inline_qos.rs (directed_write_param, find_directed_write); crates/rtps/src/datagram.rs (ignore_directed_write_before_2_4)

Tests: crates/rtps/src/inline_qos.rs::tests::table_9_20_directed_write_original_writer_info_and_secure_group_info, crates/rtps/src/inline_qos.rs::tests::directed_write_param_carries_target_guid, crates/rtps/src/inline_qos.rs::tests::find_directed_write_rejects_truncated_value, crates/rtps/src/datagram.rs::tests::pid_directed_write_of_a_peer_before_2_4_is_ignored

Status: done — 0x0057 mit einer GUID_t; Anmerkung 4: bei einer Protokollversion vor 2.4 (dort sequence<GUID_t>) wird der Parameter ignoriert. Senden und Auswerten stehen unter §8.7.7 auf done.

§9.6.4 Table 9.20 PID_ORIGINAL_WRITER_INFO (0x0061)

Spec: §9.6.4, S. 190, Table 9.20 — “PID_ORIGINAL_WRITER_INFO — 0x0061 — OriginalWriterInfo_t”.

Repo: crates/rtps/src/parameter_list.rs (pid::ORIGINAL_WRITER_INFO); crates/rtps/src/inline_qos.rs (original_writer_info_param)

Tests: crates/rtps/src/inline_qos.rs::tests::table_9_20_directed_write_original_writer_info_and_secure_group_info, crates/rtps/src/parameter_list.rs::tests::the_group_and_name_parameter_ids_are_those_of_table_9_18, crates/rtps/src/inline_qos.rs::tests::original_writer_info_roundtrip_le

Status: done — 0x0061 mit OriginalWriterInfo_t (24 Oktette, §9.6.4.7). Senden und Auswerten stehen unter §8.7.9 auf done.

§9.6.4 Table 9.20 PID_GROUP_COHERENT_SET (0x0063)

Spec: §9.6.4, S. 190, Table 9.20 — “PID_GROUP_COHERENT_SET — 0x0063 — SequenceNumber_t”.

Repo: —

Tests: crates/rtps/src/reliable_writer.rs::tests::a_group_coherent_set_carries_the_parameters_of_table_9_23, crates/rtps/src/reliable_writer.rs::tests::a_participant_set_to_go_without_it_gets_no_group_coherent_set_pid, crates/rtps/src/reliable_writer.rs::tests::a_participant_set_to_coherent_sets_only_gets_no_group_information, crates/rtps/src/parameter_list.rs::tests::the_group_and_name_parameter_ids_are_those_of_table_9_18

Status: done

§9.6.4 Table 9.20 PID_GROUP_SEQ_NUM (0x0064)

Spec: §9.6.4, S. 190, Table 9.20 — “PID_GROUP_SEQ_NUM — 0x0064 — SequenceNumber_t”.

Repo: —

Tests: crates/rtps/src/inline_qos.rs::tests::group_seq_num_is_a_cdr_sequence_number_with_pid_0x0064, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_data_carries_its_group_sequence_number, crates/rtps/src/parameter_list.rs::tests::the_group_and_name_parameter_ids_are_those_of_table_9_18

Status: done

§9.6.4 Table 9.20 PID_WRITER_GROUP_INFO (0x0065)

Spec: §9.6.4, S. 190, Table 9.20 — “PID_WRITER_GROUP_INFO — 0x0065 — WriterGroupInfo_t”.

Repo: —

Tests: crates/rtps/src/inline_qos.rs::tests::writer_group_info_carries_the_four_digest_octets_with_pid_0x0065, crates/rtps/src/parameter_list.rs::tests::the_group_and_name_parameter_ids_are_those_of_table_9_18

Status: done

§9.6.4 Table 9.20 PID_SECURE_WRITER_GROUP_INFO (0x0066)

Spec: §9.6.4, S. 190, Table 9.20 — “PID_SECURE_WRITER_GROUP_INFO — 0x0066 — WriterGroupInfo_t”.

Repo: crates/rtps/src/parameter_list.rs (pid::SECURE_WRITER_GROUP_INFO); crates/rtps/src/inline_qos.rs (secure_writer_group_info_param, find_writer_group_info)

Tests: crates/rtps/src/inline_qos.rs::tests::table_9_20_directed_write_original_writer_info_and_secure_group_info, crates/rtps/src/reliable_writer.rs::tests::the_secure_writer_group_info_stands_where_the_plain_one_is_required, crates/rtps/src/parameter_list.rs::tests::the_group_and_name_parameter_ids_are_those_of_table_9_18

Status: done — 0x0066 mit WriterGroupInfo_t (4 Oktette); ein Writer unter DDS-Security sendet ihn, ein Reader liest ihn an der Stelle von PID_WRITER_GROUP_INFO.

§9.6.4 Table 9.20 PID_KEY_HASH (0x0070)

Spec: §9.6.4, S. 190, Table 9.20 — “PID_KEY_HASH — 0x0070 — KeyHash_t”.

Repo: crates/rtps/src/parameter_list.rs (pid::KEY_HASH); crates/rtps/src/inline_qos.rs (find_key_hash)

Tests: crates/rtps/src/submessages.rs::tests::data_frag_key_hash_roundtrips_both_byte_orders, crates/dcps/src/runtime.rs::tests::alive_sample_without_key_hash_gets_the_types_computed_hash

Status: done

§9.6.4 Table 9.20 PID_STATUS_INFO (0x0071)

Spec: §9.6.4, S. 190, Table 9.20 — “PID_STATUS_INFO — 0x0071 — StatusInfo_t”.

Repo: crates/rtps/src/parameter_list.rs (pid::STATUS_INFO); crates/rtps/src/inline_qos.rs (status_info_param, find_status_info)

Tests: crates/dcps/tests/lifecycle_wire_decode.rs::reader_push_lifecycle_disposed_sets_instance_state, crates/dcps/tests/lifecycle_wire_e2e.rs::linux::dispose_propagates_over_wire_to_reader

Status: done

§9.6.4.1 PID_CONTENT_FILTER_INFO: Leitungsbild, Bitmap, Signatur

Spec: §9.6.4.1, S. 191 — Leitungsbild numBitmaps, bitmaps, numSignatures, FilterSignature_t; “The content filter info in-line QoS is invalid unless numBitmaps == ([numSignatures/32] + (numSignatures%32 ? 1 : 0))”; “A filter’s signature is calculated as the 128-bit MD5 checksum of all strings in the filter’s ContentFilterProperty_t.”

Repo: —

Tests: —

Status: open — Teil der optionalen Filterung auf der Writer-Seite (§8.7.3), die ZeroDDS nicht ausführt.

§9.6.4.1 Table 9.21 filterResult

Spec: §9.6.4.1, S. 191, Table 9.21 — “0 — Sample was filtered by the corresponding filter and did not pass. 1 — Sample was filtered by the corresponding filter and passed.”

Repo: —

Tests: —

Status: open — Teil der optionalen Filterung auf der Writer-Seite (§8.7.3), die ZeroDDS nicht ausführt.

§9.6.4.2 PID_COHERENT_SET: Kodierung und Wert

Spec: §9.6.4.2, S. 191 — “The coherent set in-line QoS parameter uses the CDR encoding for SequenceNumber_t. … all Data and DataFrag Submessages that belong to the same coherent set must contain the coherent set in-line QoS parameter with value equal to the sequence number of the first sample in the set.”

Repo: —

Tests: crates/rtps/src/inline_qos.rs::tests::coherent_set_param_is_pid_0x0056_with_sequence_number_layout, crates/rtps/src/inline_qos.rs::tests::coherent_set_roundtrip_both_endiannesses, crates/rtps/src/reliable_writer.rs::tests::coherent_set_member_data_carries_pid_0x0056_with_set_first_sn_octets

Status: done

§9.6.4.2 Table 9.22 Beispiele für das Ende eines Coherent Sets

Spec: §9.6.4.2, S. 192, Table 9.22 — “Example Data Submessages to denote the end of a coherent set”.

Repo: crates/rtps/src/reliable_reader.rs (receive_data: coherent_set_end); crates/rtps/src/reliable_writer.rs (emit_coherent_set_end)

Tests: crates/rtps/src/reliable_reader.rs::tests::table_9_22_each_form_that_ends_a_coherent_set_ends_it, crates/rtps/src/reliable_reader.rs::tests::end_of_coherent_set_data_is_delivered_as_a_terminator, crates/rtps/src/reliable_writer.rs::tests::end_coherent_set_emits_ecs_data_with_d_and_k_clear

Status: done — der Reader erkennt alle drei Formen der Tabelle: Beispiel 1 (DATA mit Daten und PID_COHERENT_SET 7, ein neues Set), Beispiel 2 (ohne Daten, PID_COHERENT_SET SEQUENCENUMBER_UNKNOWN) und Beispiel 3 (ohne Daten, ohne Inline-QoS); das Set 3 bis 6 ist danach beendet und vollständig. Der Writer sendet Beispiel 3.

§9.6.4.3 PID_GROUP_COHERENT_SET

Spec: §9.6.4.3, S. 192 — “The group coherent set in-line QoS parameter uses the CDR encoding for SequenceNumber_t. … all Data submessages and the first DataFrag submessage belonging to a sample must contain the group coherent set in-line QoS parameter”.

Repo: —

Tests: crates/rtps/src/reliable_writer.rs::tests::a_group_coherent_set_carries_the_parameters_of_table_9_23, crates/rtps/src/reliable_writer.rs::tests::a_participant_set_to_go_without_it_gets_no_group_coherent_set_pid, crates/rtps/src/reliable_writer.rs::tests::a_participant_set_to_coherent_sets_only_gets_no_group_information, crates/rtps/src/parameter_list.rs::tests::the_group_and_name_parameter_ids_are_those_of_table_9_18

Status: done

§9.6.4.3 Table 9.23 Beispiel eines GROUP-Coherent-Sets

Spec: §9.6.4.3, S. 192, Table 9.23 — “Example Data Submessages in a GROUP coherent set”.

Repo: crates/rtps/src/reliable_writer.rs (push_set_params); crates/rtps/src/inline_qos.rs (find_change_group_info); crates/rtps/src/reliable_reader.rs (DeliveredSample::group)

Tests: crates/rtps/src/reliable_writer.rs::tests::a_group_coherent_set_carries_the_parameters_of_table_9_23, crates/rtps/src/reliable_reader.rs::tests::table_9_23_the_data_of_a_group_coherent_set_reach_the_consumer_with_their_group_numbers, crates/rtps/src/writer_group.rs::tests::the_numbers_of_table_9_23

Status: done — zwei Writer eines GROUP-Publishers erzeugen die Werte der Tabelle (writerSN 4, 8, 5, 6, 9; GSN 11 bis 14; PID_COHERENT_SET 4 und 8; PID_GROUP_COHERENT_SET 11); der Reader gibt zu jedem Sample seine Gruppennummern weiter.

§9.6.4.4 PID_GROUP_SEQ_NUM

Spec: §9.6.4.4, S. 193 — “all Data submessages and the first DataFrag submessage sent by DataWriters belonging to a Publisher with Presentation access scope GROUP must contain the group sequence number in-line QoS parameter with value equal to the group sequence number.”

Repo: —

Tests: crates/rtps/src/inline_qos.rs::tests::group_seq_num_is_a_cdr_sequence_number_with_pid_0x0064, crates/rtps/src/reliable_writer.rs::tests::a_group_writers_data_carries_its_group_sequence_number, crates/rtps/src/parameter_list.rs::tests::the_group_and_name_parameter_ids_are_those_of_table_9_18

Status: done

§9.6.4.5 PID_WRITER_GROUP_INFO

Spec: §9.6.4.5, S. 193 — “for DataWriters belonging to a Publisher with Presentation access scope GROUP, the Data submessages and the first DataFrag submessage of each sample shall contain the publisher writer info in-line QoS parameter. The End Coherent Set Data submessage … shall also contain the publisher writer info in-line QoS parameter.”

Repo: —

Tests: crates/rtps/src/inline_qos.rs::tests::writer_group_info_carries_the_four_digest_octets_with_pid_0x0065, crates/rtps/src/parameter_list.rs::tests::the_group_and_name_parameter_ids_are_those_of_table_9_18

Status: done

§9.6.4.6 PID_SECURE_WRITER_GROUP_INFO

Spec: §9.6.4.6, S. 193 — “The secure publisher writer info in-line QoS is reserved for DDS Security. In the cases when it is used it shall be added anywhere that the PID_WRITER_GROUP_INFO in-line QoS is required.”

Repo: crates/rtps/src/parameter_list.rs (pid::SECURE_WRITER_GROUP_INFO); crates/rtps/src/reliable_writer.rs (set_secure_writer_group_info, push_set_params); crates/rtps/src/inline_qos.rs (secure_writer_group_info_param, find_writer_group_info); crates/dcps/src/runtime.rs (Writer-Anlage unter Security)

Tests: crates/rtps/src/reliable_writer.rs::tests::the_secure_writer_group_info_stands_where_the_plain_one_is_required, crates/rtps/src/inline_qos.rs::tests::table_9_20_directed_write_original_writer_info_and_secure_group_info

Status: done — unter DDS-Security (RuntimeConfig::security) senden Writer eines GROUP-Publishers PID_SECURE_WRITER_GROUP_INFO überall dort, wo sonst PID_WRITER_GROUP_INFO steht; ein Reader nimmt beide. Der Test mit Security-Laufzeit steht nicht in diesem Lauf (nur die Writer-Einstellung ist getestet).

§9.6.4.7 PID_ORIGINAL_WRITER_INFO: Leitungsbild

Spec: §9.6.4.7, S. 193 — Leitungsbild GUID_t originalWriterGUID, SequenceNumber originalWriterSN. “The original writer info parameter may appear in the Data or in the DataFrag submessages.”

Repo: crates/rtps/src/inline_qos.rs (original_writer_info_param, find_original_writer_info)

Tests: crates/rtps/src/inline_qos.rs::tests::original_writer_info_param_24_byte_layout_le, crates/rtps/src/inline_qos.rs::tests::original_writer_info_roundtrip_be, crates/rtps/src/inline_qos.rs::tests::table_9_20_directed_write_original_writer_info_and_secure_group_info

Status: done — das Leitungsbild stimmt (GUID_t, SequenceNumber_t); der Parameter wird in DATA und DATA_FRAG gesendet und ausgewertet (Items unter §8.7.9).

§9.6.4.8 KeyHash: 16 Oktette

Spec: §9.6.4.8, S. 193 — “The KeyHash_t is defined as a 16-Byte octet array (see 9.3.2) therefore the key hash inline parameter just copies those 16 Bytes.”

Repo: crates/dcps/src/key_hash.rs (KEY_HASH_LEN); crates/rtps/src/inline_qos.rs (find_key_hash)

Tests: crates/dcps/src/key_hash.rs::tests::a_holder_of_exactly_sixteen_is_the_hash, crates/rtps/src/submessages.rs::tests::data_frag_key_hash_roundtrips_both_byte_orders

Status: done

§9.6.4.8 KeyHash Schritt 1: FooKeyHolder

Spec: §9.6.4.8, S. 193–194 — “FooKeyHolder shall have extensibility kind ‘FINAL’ … If there are any key members, then remove the non-key members … Reorder the members in ascending order of their memberId values.”

Repo: crates/dcps/src/key_hash.rs (keyhash_cdr2_be: Sortierung nach member_id)

Tests: crates/dcps/src/key_hash.rs::tests::the_member_order_does_not_reach_the_hash

Status: done

§9.6.4.8 KeyHash Schritte 2 und 3: Werte und Rekursion

Spec: §9.6.4.8, S. 194 — “Step 2. … setting the members present in FooKeyHolderObject to the same values as the corresponding members in FooObject. Step 3. Apply steps 1 and 2 recursively to the members of FooKeyHolder if they are themselves Aggregated types”.

Repo: crates/dcps/src/key_hash.rs (PlainCdr2BeKeyHolder); crates/dcps/src/runtime.rs (reader_key_hash_context)

Tests: crates/dcps/src/runtime.rs::tests::alive_sample_without_key_hash_gets_the_types_computed_hash, crates/dcps/tests/lifecycle_wire_e2e.rs::linux::dispose_marker_carries_the_key_fields_of_a_string_keyed_type

Status: done

§9.6.4.8 KeyHash Schritt 4: PLAIN_CDR2 Big Endian

Spec: §9.6.4.8, S. 194 — “Compute the PLAIN_CDR2 Big Endian Serialization … The serialization shall be performed on a buffer that is initially aligned to the maximum alignment in PLAIN_CDR2 (i.e., 4). Furthermore, any padding bytes added due to alignment rules shall be set to zero.”

Repo: crates/dcps/src/key_hash.rs (PlainCdr2BeKeyHolder)

Tests: crates/dcps/src/key_hash.rs::tests::a_u32_goes_out_big_endian, crates/dcps/src/key_hash.rs::tests::a_u64_is_aligned_to_four_and_not_to_eight, crates/dcps/src/key_hash.rs::tests::a_string_carries_its_terminator_in_its_length

Status: done

§9.6.4.8 KeyHash Schritt 5: Polsterung oder MD5 nach der Maximalgröße

Spec: §9.6.4.8, S. 194 — “Step 5.1 If the FooKeyHolder has a maximum serialized size that is less than or equal to 16 bytes, then the KeyHash of FooObject shall be set to the result of Step 4, extended to 16 bytes. … Step 5.2 If the FooKeyHolder has a maximum serialized size that is greater than 16 bytes, then the KeyHash_t of FooObject shall be set to the MD5 Hash”.

Repo: crates/dcps/src/key_hash.rs (compute_key_hash: key_holder_max_size)

Tests: crates/dcps/src/key_hash.rs::tests::a_short_instance_of_a_bounded_type_still_pads, crates/dcps/src/key_hash.rs::tests::a_holder_over_sixteen_is_hashed

Status: done

§9.6.4.8 KeyHash Beispiele 1 bis 3

Spec: §9.6.4.8, S. 194–196 — “Example 1 …”, “Example 2 …”, “Example 3 …” mit den erwarteten Oktetten.

Repo: crates/dcps/src/key_hash.rs (PlainCdr2BeKeyHolder, compute_key_hash); crates/dcps/src/dds_type.rs (DdsType::compute_key_hash)

Tests: crates/dcps/src/dds_type.rs::tests::key_hash_example_1_of_the_spec_is_the_holder_padded_with_zeros, crates/dcps/src/dds_type.rs::tests::key_hash_example_2_of_the_spec_is_the_md5_of_the_holder, crates/dcps/src/dds_type.rs::tests::key_hash_example_3_of_the_spec_is_the_md5_of_the_reordered_holder

Status: done — die drei Beispiele ergeben die Oktette der Spec: Beispiel 1 den mit Nullen auf 16 Oktette erweiterten Holder, Beispiel 2 und 3 den MD5 des 20- und des 13-Oktett-Holders (f91a59e3…, 374b96e2…).

§9.6.4.9 StatusInfo_t: 4 Oktette

Spec: §9.6.4.9, S. 196 — “The StatusInfo_t is defined as a 4-Byte octet array (see 9.3.2) therefore the status info inline parameter just copies those 4 Bytes.”

Repo: crates/rtps/src/inline_qos.rs (status_info_param: Netzreihenfolge; find_status_info)

Tests: crates/dcps/tests/lifecycle_wire_decode.rs::reader_push_lifecycle_unregistered_sets_instance_state, crates/dcps/tests/lifecycle_wire_e2e.rs::linux::unregister_with_autodispose_false_propagates_unregister_only

Status: done

§9.6.4.9 StatusInfo in Data oder DataFrag

Spec: §9.6.4.9, S. 196 — “The status info parameter may appear in the Data or in the DataFrag submessages.”

Repo: crates/rtps/src/reliable_reader.rs (classify_change_kind für DATA, handle_data_frag_opening für DATA_FRAG)

Tests: crates/dcps/tests/lifecycle_wire_decode.rs::reader_push_lifecycle_disposed_sets_instance_state, crates/rtps/src/reliable_reader.rs::tests::a_reassembled_key_is_a_dispose_or_a_registration_as_a_data_is, crates/rtps/src/reliable_reader.rs::tests::a_reassembled_sample_with_the_filtered_flag_is_known_but_not_delivered

Status: done — in DATA und in DATA_FRAG ausgewertet (Schlüssel mit D oder U als Dispose und Unregister, F als gefiltertes Sample).

§9.6.4.9 StatusInfo: X-Flags

Spec: §9.6.4.9, S. 197 — “The flags represented with the literal ‘X’ are unused by this version of the protocol and should be set to zero by the writer and not interpreted by the reader”.

Repo: crates/rtps/src/inline_qos.rs (status_info); crates/rtps/src/reliable_reader.rs (classify_change_kind: nur D und U)

Tests: crates/dcps/tests/lifecycle_wire_decode.rs::reader_push_lifecycle_disposed_sets_instance_state

Status: done

§9.6.4.9 StatusInfo DisposedFlag

Spec: §9.6.4.9, S. 197 — “D=1 indicates that the DDS DataWriter has disposed the instance of the data-object whose Key appears in the submessage.”

Repo: crates/rtps/src/inline_qos.rs (status_info::DISPOSED = 0x1)

Tests: crates/dcps/tests/lifecycle_wire_e2e.rs::linux::dispose_propagates_over_wire_to_reader, crates/dcps/tests/lifecycle_wire_decode.rs::reader_push_lifecycle_disposed_sets_instance_state

Status: done

§9.6.4.9 StatusInfo UnregisteredFlag

Spec: §9.6.4.9, S. 197 — “U=1 indicates that the DDS DataWriter has unregistered the instance of the data-object whose Key appears in the submessage.”

Repo: crates/rtps/src/inline_qos.rs (status_info::UNREGISTERED = 0x2)

Tests: crates/dcps/tests/lifecycle_wire_decode.rs::reader_push_lifecycle_unregistered_sets_instance_state, crates/dcps/tests/lifecycle_wire_e2e.rs::linux::instance_goes_no_writers_when_its_last_writer_disappears

Status: done

§9.6.4.9 StatusInfo FilteredFlag

Spec: §9.6.4.9, S. 197 — “F=1 indicates that the DDS DataWriter has written as sample for the instance … but the sample did not pass the content filter specified by the DDS DataReader.” “If both DisposedFlag==0 and UnregisteredFlag=0 … FilteredFlag==1 indicates it did not pass the filter.”

Repo: crates/rtps/src/reliable_reader.rs (status_change_kind, classify_change_kind, ReliableReader::filtered_sample_count)

Tests: crates/rtps/src/reliable_reader.rs::tests::a_sample_with_the_filtered_flag_is_known_but_not_delivered, crates/rtps/src/reliable_reader.rs::tests::a_reassembled_sample_with_the_filtered_flag_is_known_but_not_delivered, crates/rtps/src/reliable_reader.rs::tests::the_reader_keeps_the_status_of_each_change

Status: done — ein DATA oder DATA_FRAG mit F = 1 und D = U = 0 (mit oder ohne Nutzdaten und Key-Flag) ergibt ChangeKind::AliveFiltered: die Nummer ist bekannt und NA_FILTERED (der Writer wiederholt sie nicht), das Sample wird nicht ausgeliefert und in filtered_sample_count gezählt. Bei gesetztem D oder U gilt die Lebenszyklus-Marke. ZeroDDS sendet F nicht (die Laufzeit filtert nicht auf der Writer-Seite); ob ein anderer Hersteller F sendet, ist nicht gemessen.

§9.6.4.9 Registrierung nicht übertragen

Spec: §9.6.4.9, S. 197 — “Note that the protocol does not require that the DDS DataWriter propagates the”register” operation.”

Repo: —

Tests: —

Status: n/a (informative) — keine Anforderung.

§9.6.5 Table 9.24 DDS-XTypes

Spec: §9.6.5, S. 197, Table 9.24 — “DDS-XTypes 1.1 … 1.3 — 0x0069, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076; Note that 0x0076 was deprecated in DDS-XTypes 1.2”.

Repo: crates/rtps/src/parameter_list.rs (pid::DATA_REPRESENTATION, TYPE_CONSISTENCY_ENFORCEMENT, TYPE_INFORMATION)

Tests: crates/rtps/src/publication_data.rs::tests::issue30_type_identifier_from_standard_type_information, crates/discovery/tests/vendor_discovery_frames.rs::cyclone_announcements_read_and_write_back

Status: done

§9.6.5 Table 9.24 DDS-Security

Spec: §9.6.5, S. 197, Table 9.24 — “DDS-Security 1.1 — Parameter IDs in the range 0x1000 to 0x1FFF; Parameter IDs in the range 0x5000 to 0x5FFF”.

Repo: crates/rtps/src/parameter_list.rs (Sicherheits-PIDs 0x1001 bis 0x1013)

Tests: crates/rtps/src/parameter_list.rs::tests::is_standard_pid_recognises_dds_security_pids, crates/rtps/src/participant_data.rs::tests::participant_security_info_pid_roundtrip

Status: done

§9.6.5 Table 9.24 DDS-RPC

Spec: §9.6.5, S. 197, Table 9.24 — “DDS-RPC 1.0 — 0x0080, 0x0081, 0x0082, 0x0083”.

Repo: crates/rtps/src/parameter_list.rs (pid::SERVICE_INSTANCE_NAME, RELATED_ENTITY_GUID, TOPIC_ALIASES, RELATED_SAMPLE_IDENTITY)

Tests: crates/rtps/src/parameter_list.rs::tests::rpc_pid_constants_match_spec, crates/rtps/src/publication_data.rs::tests::rpc_pid_constants_in_emitted_bytes

Status: done

§9.6.6 Table 9.25 PID_PERSISTENCE (0x0003)

Spec: §9.6.6, S. 197–198, Table 9.25 — “PID_PERSISTENCE — 0x0003 — 2.2”; “These parameters should not be used by versions of the protocol equal or newer than the deprecated version unless they are used with the same meaning as in versions prior to the deprecated version.”

Repo: —

Tests: —

Status: n/a (informative) — veralteter PID; ZeroDDS sendet ihn nicht und übergeht ihn beim Empfang.

§9.6.6 Table 9.25 PID_TYPE_CHECKSUM (0x0008)

Spec: §9.6.6, S. 198, Table 9.25 — “PID_TYPE_CHECKSUM — 0x0008 — 2.2”.

Repo: —

Tests: —

Status: n/a (informative) — veralteter PID; ZeroDDS sendet ihn nicht und übergeht ihn beim Empfang.

§9.6.6 Table 9.25 PID_TYPE2_NAME (0x0009)

Spec: §9.6.6, S. 198, Table 9.25 — “PID_TYPE2_NAME — 0x0009 — 2.2”.

Repo: —

Tests: —

Status: n/a (informative) — veralteter PID; ZeroDDS sendet ihn nicht und übergeht ihn beim Empfang.

§9.6.6 Table 9.25 PID_TYPE2_CHECKSUM (0x000a)

Spec: §9.6.6, S. 198, Table 9.25 — “PID_TYPE2_CHECKSUM — 0x000a — 2.2”.

Repo: —

Tests: —

Status: n/a (informative) — veralteter PID; ZeroDDS sendet ihn nicht und übergeht ihn beim Empfang.

§9.6.6 Table 9.25 PID_EXPECTS_ACK (0x0010)

Spec: §9.6.6, S. 198, Table 9.25 — “PID_EXPECTS_ACK — 0x0010 — 2.2”.

Repo: —

Tests: —

Status: n/a (informative) — veralteter PID; ZeroDDS sendet ihn nicht und übergeht ihn beim Empfang.

§9.6.6 Table 9.25 PID_MANAGER_KEY (0x0012)

Spec: §9.6.6, S. 198, Table 9.25 — “PID_MANAGER_KEY — 0x0012 — 2.2”.

Repo: —

Tests: —

Status: n/a (informative) — veralteter PID; ZeroDDS sendet ihn nicht und übergeht ihn beim Empfang.

§9.6.6 Table 9.25 PID_SEND_QUEUE_SIZE (0x0013)

Spec: §9.6.6, S. 198, Table 9.25 — “PID_SEND_QUEUE_SIZE — 0x0013 — 2.2”.

Repo: —

Tests: —

Status: n/a (informative) — veralteter PID; ZeroDDS sendet ihn nicht und übergeht ihn beim Empfang (RTI sendet ihn, vendor_discovery_frames.rs).

§9.6.6 Table 9.25 PID_RELIABILITY_ENABLED (0x0014)

Spec: §9.6.6, S. 198, Table 9.25 — “PID_RELIABILITY_ENABLED — 0x0014 — 2.2”.

Repo: —

Tests: —

Status: n/a (informative) — veralteter PID; ZeroDDS sendet ihn nicht und übergeht ihn beim Empfang.

§9.6.6 Table 9.25 PID_VARGAPPS_SEQUENCE_NUMBER_LAST (0x0017)

Spec: §9.6.6, S. 198, Table 9.25 — “PID_VARGAPPS_SEQUENCE_NUMBER_LAST — 0x0017 — 2.2”.

Repo: —

Tests: —

Status: n/a (informative) — veralteter PID; ZeroDDS sendet ihn nicht und übergeht ihn beim Empfang.

§9.6.6 Table 9.25 PID_RECV_QUEUE_SIZE (0x0018)

Spec: §9.6.6, S. 198, Table 9.25 — “PID_RECV_QUEUE_SIZE — 0x0018 — 2.2”.

Repo: —

Tests: —

Status: n/a (informative) — veralteter PID; ZeroDDS sendet ihn nicht und übergeht ihn beim Empfang (RTI sendet ihn, vendor_discovery_frames.rs).

§9.6.6 Table 9.25 PID_RELIABILITY_OFFERED (0x0019)

Spec: §9.6.6, S. 198, Table 9.25 — “PID_RELIABILITY_OFFERED — 0x0019 — 2.2”.

Repo: —

Tests: —

Status: n/a (informative) — veralteter PID; ZeroDDS sendet ihn nicht und übergeht ihn beim Empfang.

§10 Serialized Payload Representation

§10.1 Einleitung

Spec: §10.1, S. 199 — “The representation of the serialized application data is not part of the RTPS protocol. The RTPS protocol does not interpret the content of the SerializedPayload.”; “the content and format of the SerializedPayload is defined in sections 10.3 to 10.5.”

Repo: —

Tests: —

Status: n/a (informative) — Überblick; die Anforderungen stehen in §10.2 bis §10.5.

§10.2 SerializedPayloadHeader am Anfang jeder SerializedPayload

Spec: §10.2, S. 199 — “All SerializedPayload shall start with the SerializedPayloadHeader defined below.”; “The SerializedPayloadHeader occupies the first four octets of the SerializedPayload”.

Repo: crates/dcps/src/runtime.rs (user_payload_encap, write_user_sample_pooled); crates/rtps/src/participant_data.rs (to_pl_cdr_le); crates/rtps/src/participant_message_data.rs (to_cdr); crates/security/src/generic_message.rs (encode_generic_message)

Tests: crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility, crates/rtps/src/participant_data.rs::tests::participant_data_first_4_bytes_are_pl_cdr_le_encapsulation, crates/rtps/src/participant_message_data.rs::tests::participant_message_data_roundtrip_le, crates/security-runtime/src/builtin_topics.rs::tests::encode_starts_with_cdr_le_encapsulation

Status: done

§10.2 SerializedPayloadHeader: Struktur

Spec: §10.2, S. 199 — “typedef octet RepresentationIdentifier[2]; typedef octet RepresentationOptions[2]; struct SerializedPayloadHeader { RepresentationIdentifier representation_identifier; RepresentationOptions representation_options; };”

Repo: crates/dcps/src/runtime.rs (user_encap_body, encap_representation, encap_big_endian)

Tests: crates/dcps/src/runtime.rs::tests::strip_user_encap_xcdr1_le, crates/dcps/src/runtime.rs::tests::strip_user_encap_xcdr2_le, crates/dcps/src/runtime.rs::tests::strip_user_encap_rejects_short

Status: done

§10.2 RepresentationOptions im Zusammenhang des RepresentationIdentifier

Spec: §10.2, S. 199 — “The RepresentationOptions shall be interpreted in the context of the RepresentationIdentifier, such that each RepresentationIdentifier may define the representation_options that it requires.”

Repo: crates/dcps/src/runtime.rs (user_encap_body: die unteren zwei Bit als Zahl der angehängten Füll-Oktette nach DDS-XTypes 1.3 §7.6.3.1.2)

Tests: crates/dcps/src/runtime.rs::tests::strip_user_encap_drops_the_padding_the_options_name, crates/dcps/src/runtime.rs::tests::strip_user_encap_refuses_padding_the_body_cannot_hold

Status: done

§10.2 CDR-Strom beginnt nach representation_options

Spec: §10.2, S. 199 — “For alignment purposes, the CDR stream is logically reset at the position that follows the representation_options. Therefore, there should be no initial padding before the serialized data is added to the CDR stream.”

Repo: crates/dcps/src/runtime.rs (write_user_sample_pooled: Kopf und getrennt kodierter Körper; user_encap_body: Körper ab Oktett 4)

Tests: crates/dcps/src/interop.rs::tests::u64_type_xcdr1_and_xcdr2_alignment_differs, crates/dcps/src/runtime.rs::tests::strip_user_encap_xcdr1_le

Status: done

§10.2 Fußnote 5: ältere Versionen

Spec: §10.2, S. 199, Fußnote 5 — “Versions of the RTPS specification previous to version 2.4 did not clearly state where the CDR stream was reset for alignment purposes. Therefore implementations may need to take into account the vendor and protocol version when interpreting the Serialized Data.”

Repo: —

Tests: —

Status: n/a (informative) — Hinweis ohne Pflicht.

§10.3 Discovery-Builtin-Endpoints verwenden Table 10.1

Spec: §10.3, S. 200 — “The SerializedPayload for the data messages associated with built-in discovery endpoints shall use the RepresentationIdentifier values and formats defined in Table 10.1 below.”

Repo: crates/rtps/src/participant_data.rs, crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs, crates/rtps/src/topic_data.rs (Kodierung mit PL_CDR_LE oder PL_CDR_BE, andere Kennungen beim Lesen abgewiesen)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_decode_rejects_unknown_encapsulation, crates/rtps/src/publication_data.rs::tests::decode_rejects_unknown_encapsulation

Status: done

§10.3 Table 10.1 PL_CDR_BE {0x00, 0x02}

Spec: §10.3, S. 200, Table 10.1 — “PL_CDR_BE — {0x00, 0x02} — ParameterList (9.4.2.11). Both the parameter list and its parameters are encapsulated using OMG CDR Big Endian.”

Repo: crates/rtps/src/participant_data.rs (to_pl_cdr_be, from_pl_cdr_le); crates/rtps/src/publication_data.rs, crates/rtps/src/subscription_data.rs (Lesen bei [0x00, 0x02])

Tests: crates/rtps/src/participant_data.rs::tests::to_pl_cdr_be_is_big_endian_roundtrips_and_omits_credential_tokens, crates/rtps/src/publication_data.rs::tests::locator_params_of_a_big_endian_list_are_read

Status: done

§10.3 Table 10.1 PL_CDR_LE {0x00, 0x03}

Spec: §10.3, S. 200, Table 10.1 — “PL_CDR_LE — {0x00, 0x03} — ParameterList (9.4.2.11). Both the parameter list and its parameters are encapsulated using OMG CDR Little Endian.”

Repo: crates/rtps/src/participant_data.rs (ENCAPSULATION_PL_CDR_LE, to_pl_cdr_le)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_first_4_bytes_are_pl_cdr_le_encapsulation, crates/discovery/tests/vendor_discovery_frames.rs::cyclone_announcements_read_and_write_back

Status: done

§10.3 representation_options: Sender setzt null

Spec: §10.3, S. 200 — “The current version of the protocol does not use the representation_options: The sender shall set the representation_options to zero.”

Repo: crates/rtps/src/participant_data.rs (to_pl_cdr_le, to_pl_cdr_be: options 0x0000)

Tests: crates/rtps/src/participant_data.rs::tests::participant_data_first_4_bytes_are_pl_cdr_le_encapsulation

Status: done

§10.3 representation_options: Empfänger ignoriert sie

Spec: §10.3, S. 200 — “The receiver shall ignore the value of the representation_options.”

Repo: crates/rtps/src/participant_data.rs, publication_data.rs, subscription_data.rs (from_pl_cdr_le)

Tests: crates/rtps/src/subscription_data.rs::tests::the_receiver_ignores_the_representation_options, crates/rtps/src/participant_data.rs::tests::the_receiver_ignores_the_representation_options_of_a_participant, crates/rtps/src/publication_data.rs::tests::the_receiver_ignores_the_representation_options_of_a_publication

Status: done — die Decoder lesen eine Ankündigung mit representation_options ≠ 0 wie die mit 0; der Sender schreibt 0.

§10.4 Andere Builtin-Endpoints verwenden Table 10.2

Spec: §10.4, S. 200 — “The SerializedPayload for the data messages associated with built-in endpoints other than discovery built-in endpoints shall use one of the RepresentationIdentifier values and formats defined in Table 10.2 below.”

Repo: crates/rtps/src/participant_message_data.rs (to_cdr: CDR_LE oder CDR_BE); crates/security/src/generic_message.rs (CDR_LE)

Tests: crates/rtps/src/participant_message_data.rs::tests::participant_message_data_roundtrip_le, crates/security-runtime/src/builtin_topics.rs::tests::encode_starts_with_cdr_le_encapsulation

Status: done — ParticipantMessageData und die Nachrichten der DDS-Security-Endpoints verwenden CDR_LE. Die TypeLookup-Endpoints verwenden CDR2_LE, die Repräsentation, die ihre eigene Definition nennt (DDS-XTypes 1.4 Beta 1 §7.6.3.3.3), und CDR_LE unter der Einstellung xcdr1 (Item „TypeLookup-Endpoints mit CDR2_LE“).

§10.4 TypeLookup-Endpoints mit CDR2_LE

Spec: §10.4, S. 200 — “shall use one of the RepresentationIdentifier values and formats defined in Table 10.2 below.” Table 10.2 nennt CDR_BE, CDR_LE, PL_CDR_BE und PL_CDR_LE.

Repo: crates/types/src/type_lookup.rs (TypeLookupEncoding, TypeLookupEncapsulation, to_payload), crates/types/src/framing.rs (EncodingVersion, encode_optional, encode_mutable), crates/dcps/src/runtime.rs (send_type_lookup_request_datagram, send_type_lookup_reply, dispatch_type_lookup_datagram, RuntimeConfig::type_lookup_encoding), crates/java-omgdds/java/src/main/java/org/zerodds/typelookup/TypeLookupService.java (Encoding, Encapsulation), .../generated/ZdCodec.java (ZdCodec.Xcdr1)

Tests: crates/types/tests/type_lookup_xcdr1.rs (acht Tests, darunter a_get_types_request_is_cdr_le_with_its_parameters_as_a_parameter_list und a_get_types_reply_carries_its_object_in_the_encoding_version_1), crates/dcps/tests/type_lookup_e2e.rs::{server_handles_inbound_get_types_request_via_dispatch, a_get_types_request_in_cdr_le_is_answered, the_setting_xcdr1_answers_in_cdr_le, a_request_is_written_in_the_configured_encoding}, crates/dcps/tests/typelookup_resolution_e2e.rs::a_complete_object_crosses_between_an_xcdr1_and_an_xcdr2_participant, crates/java-omgdds/java/src/test/java/org/zerodds/typelookup/TypeLookupEncodingTest.java (fünf Tests), crates/dcps/tests/java_typelookup_live.rs (Java fragt die Rust-Laufzeit, die Rust-Laufzeit fragt Java, über RTPS zwischen zwei Prozessen, beide mit der Vorgabe XCDR2)

Status: done — Anfrage und Antwort des TypeLookup-Dienstes gehen standardmäßig mit 00 07 (CDR2_LE) und XCDR2-Codierung hinaus: die FINAL-Hülle ohne DHEADER, die appendable Unions mit einem, die MUTABLE-Parameter _In/_Out mit DHEADER und einem EMHEADER je Member. DDS-XTypes 1.4 Beta 1 (ptc/2026-02-06) §7.6.3.3.3: “The Data Representation used by these endpoints shall be Extended CDR Representation (encoding version 2)”, die Auflösung von OMG-Issue DDSXTY14-29. §10.4 überlässt das Format „the definition of each of those builtin Endpoints“, und diese Definition nennt jetzt XCDR2; CDR2_LE steht nicht in Table 10.2, und DDSI-RTPS 2.5 ist die aktuelle Fassung. Die Form von Table 10.2 ist die benannte Einstellung wire.type_lookup_encoding = xcdr1 (Env ZERODDS_WIRE_TYPE_LOOKUP_ENCODING, zerodds.yaml(5)): 00 01 (CDR_LE) mit XCDR1, äußerer Typ ohne Kopf, die MUTABLE-Parameter als PL_CDR1-Listen mit PID_EXTENDED (0x7F01, Table 34) für die @hashid-Kennungen über 0x3F00 und PID_LIST_END (0x7F02), die @optional-Member der TypeObjects mit Parameterkopf statt Präsenz-Oktett (XTypes 1.3 §7.4.1.1.5.2, §7.4.1.2). Sie ist die Lesart von XTypes 1.3, das für diese Endpoints keine Repräsentation nennt: keine DataRepresentation (Vorgabe XCDR, §7.6.3.1.1), ein äußerer Typ ohne Annotation ist APPENDABLE (§7.3.1.2.1.8), Table 60 ergibt CDR_LE. Eine empfangene Probe wird in der Codierung gelesen, die ihre Kennung nennt (CDR_BE/CDR_LE → XCDR1, CDR2_BE/CDR2_LE → XCDR2), in beiden Einstellungen; eine andere Kennung wird mit typelookup.sample.rejected verworfen und gemeldet. Die Probe endet auf einer Vier-Oktett-Grenze, die Optionen zählen die Füllbytes (XTypes 1.3 §7.6.3.1.2, 38d06cac567). Die Java-Laufzeit (crates/java-omgdds) hat dieselbe Vorgabe und dieselbe Einstellung (Property zerodds.wire.type_lookup_encoding oder dieselbe Env-Variable, 21bbd369efa); ihr XCDR1-Codec ist aus derselben unveränderten IDL generiert und schreibt dieselben Oktette wie die Rust-Laufzeit (TypeLookupEncodingTest::aGetTypesRequestIsWrittenInTheEncodingVersion1, theRustReplyReadsAndIsWrittenBackOctetForOctet). Die erwarteten XCDR1-Oktette der Tests sind aus den Klauseln hergeleitet, kein Hersteller-Mitschnitt: kein gemessener Hersteller sendet diese Form. Gemessen (Linux-Testhost, internal/release/evidence/rc7-typelookup-encapsulation, e954fd7cfe8), je Richtung mit einem Typ, den der Peer nicht kennt:

Hersteller sendet liest CDR_LE-Anfrage liest CDR_LE-Antwort
Cyclone DDS 11.0.1 CDR2_LE, Optionen = Füllbytes nein (deserialization failed) nein (deserialization failed)
Fast DDS 3.6.1 CDR2_LE (Antworten) ja, antwortet nicht gemessen: Fast DDS fragte in keiner Zelle
OpenDDS 3.34.0 CDR2_LE, Optionen 0000 nein (failed to deserialize type lookup request) nein (failed to deserialize type lookup reply)
RTI Connext 7.7.0 CDR2_LE nein (no deserialization program … CDR_LE) nein (dieselbe Meldung)

InterCom DDS 4.3.1 sendet ebenfalls CDR2_LE (früherer Mitschnitt, an_intercom_get_types_request_padded_without_its_options_is_read). OpenDDS setzt das Optionswort auf 0000 auch auf eine Probe, die drei Oktette vor der Vier-Oktett-Grenze endet; XTypes 1.3 §7.6.3.1.2 verlangt dort die Zahl der Füllbytes. ZeroDDS liest sie ohne Raten: die Struktur der Hülle sagt, wo sie endet, und Null-Oktette bis zur nächsten Vier-Oktett-Grenze sind die Füllung hinter einem Submessage (DDSI-RTPS 2.5 §9.4.1), mit und ohne sie (runtime::tests::an_opendds_get_types_request_without_its_padding_count_is_read mit der mitgeschnittenen Anfrage, 6224b8ceab5). Die Runner setzen dafür nichts; jedes Paar läuft mit der Vorgabe. Mit CDR2_LE liefert die Cyclone-Zelle mit angehängtem Member ihre Samples (cyc-answers-x2: 38), mit CDR_LE keine (cyc-answers-x1).

§10.4 Table 10.2 CDR_BE {0x00, 0x00}

Spec: §10.4, S. 200, Table 10.2 — “CDR_BE — {0x00, 0x00} — Classic CDR representation with Big Endian encoding.”

Repo: crates/rtps/src/participant_message_data.rs (to_cdr(false), from_cdr)

Tests: crates/rtps/src/participant_message_data.rs::tests::participant_message_data_roundtrip_be

Status: done

§10.4 Table 10.2 CDR_LE {0x00, 0x01}

Spec: §10.4, S. 200, Table 10.2 — “CDR_LE — {0x00, 0x01} — Classic CDR representation with Little Endian encoding.”

Repo: crates/rtps/src/participant_message_data.rs (ENCAPSULATION_CDR_LE); crates/security/src/generic_message.rs (ENCAPSULATION_CDR_LE)

Tests: crates/rtps/src/participant_message_data.rs::tests::participant_message_data_roundtrip_le, crates/security-runtime/src/builtin_topics.rs::tests::encode_starts_with_cdr_le_encapsulation

Status: done

§10.4 Table 10.2 PL_CDR_BE {0x00, 0x02}

Spec: §10.4, S. 200, Table 10.2 — “PL_CDR_BE — {0x00, 0x02} — ParameterList (9.4.2.11) with Big Endian encoding.”

Repo: —

Tests: —

Status: n/a (informative) — eine der zulässigen Kennungen; ZeroDDS verwendet für diese Endpoints CDR_LE und CDR_BE.

§10.4 Table 10.2 PL_CDR_LE {0x00, 0x03}

Spec: §10.4, S. 200, Table 10.2 — “PL_CDR_LE — {0x00, 0x03} — ParameterList (9.4.2.11) with Little Endian encoding.”

Repo: —

Tests: —

Status: n/a (informative) — eine der zulässigen Kennungen; ZeroDDS verwendet für diese Endpoints CDR_LE und CDR_BE.

§10.4 Definition je Builtin-Endpoint

Spec: §10.4, S. 200 — “The definition of each of those builtin Endpoints should indicate the serialized data format and RepresentationIdentifier used.”

Repo: —

Tests: —

Status: n/a (informative) — richtet sich an die Spezifikationen, die Builtin-Endpoints definieren.

§10.5 Anwender-Topics verwenden die Darstellungen aus DDS-XTypes §7.4

Spec: §10.5, S. 200 — “The SerializedPayload for the data messages associated with the user-defined DDS Topics shall use the data representations defined in DDS-XTYPES clause 7.4 (Data Representation). Accordingly, the RepresentationIdentifier values and the corresponding formats shall be as defined in Table 10.3.”

Repo: crates/dcps/src/runtime.rs (user_payload_encap, encap_in_table, user_encap_body); wire.encapsulation_ids

Tests: crates/dcps/src/runtime.rs::tests::encap_in_table_maps_table_60_onto_table_39, crates/dcps/src/runtime.rs::tests::a_writer_stamps_the_identifiers_of_table_39_when_the_runtime_is_set_to_them, crates/dcps/src/runtime.rs::tests::the_encapsulation_identifiers_of_table_39_are_read, crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility, crates/dcps/tests/runtime_config_layering.rs::the_encapsulation_and_pl_cdr1_settings_default_to_the_vendors_and_are_set_by_file_and_environment

Status: done — XCDR1, XCDR2 und XML sind umgesetzt. Gelesen werden beide Wertemengen. Gesendet wird als Vorgabe DDS-XTypes 1.3 Table 60, auf die die Kopfzeile von Table 10.3 verweist und die Cyclone DDS 11.0.1, Fast DDS, OpenDDS 3.34.0 und RTI 7.7.0 senden (gemessen in tools/wire-capture/frames/*/*.xcdr2.frames). Mit wire.encapsulation_ids: table-39 (Umgebung ZERODDS_WIRE_ENCAPSULATION_IDS) sendet ZeroDDS die Kennungen aus Table 39 (§7.4.3.4), deren XCDR2-Werte die aus Table 10.3 sind (XML: {0x01, 0x00}). Erwartet bei den Herstellern: ein Peer, der nur Table 60 liest, kann Daten mit 0x0010 bis 0x0015 nicht lesen; die Einstellung ist für Peers, die Table 10.3 senden und erwarten. Nicht gemessen: ein Lauf gegen die Hersteller mit der Einstellung.

§10.5 Table 10.3 CDR_BE {0x00, 0x00}

Spec: §10.5, S. 201, Table 10.3 — “CDR_BE — {0x00, 0x00} — Classic CDR representation with Big Endian encoding.”

Repo: crates/dcps/src/runtime.rs (user_payload_encap mit big_endian, encap_big_endian)

Tests: crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility, crates/dcps/src/subscriber.rs::tests::cache_materialize_honors_xcdr1_encapsulation_le_and_be

Status: done

§10.5 Table 10.3 CDR_LE {0x00, 0x01}

Spec: §10.5, S. 201, Table 10.3 — “CDR_LE — {0x00, 0x01} — Classic CDR representation with Little Endian encoding.”

Repo: crates/dcps/src/runtime.rs (USER_PAYLOAD_ENCAP, user_payload_encap)

Tests: crates/dcps/src/runtime.rs::tests::user_payload_encap_is_cdr_le, crates/dcps/src/runtime.rs::tests::strip_user_encap_xcdr1_le

Status: done

§10.5 Table 10.3 PL_CDR_BE {0x00, 0x02}

Spec: §10.5, S. 201, Table 10.3 — “PL_CDR_BE — {0x00, 0x02} — ParameterList (9.4.2.11) with Big Endian encoding.”

Repo: crates/dcps/src/runtime.rs (user_payload_encap: XCDR1 und MUTABLE)

Tests: crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility

Status: done

§10.5 Table 10.3 PL_CDR_LE {0x00, 0x03}

Spec: §10.5, S. 201, Table 10.3 — “PL_CDR_LE — {0x00, 0x03} — ParameterList (9.4.2.11) with Little Endian encoding.”

Repo: crates/dcps/src/runtime.rs (user_payload_encap: XCDR1 und MUTABLE)

Tests: crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility

Status: done

§10.5 Table 10.3 CDR2_BE {0x00, 0x10}

Spec: §10.5, S. 201, Table 10.3 — “CDR2_BE — {0x00, 0x10} — Plain CDR representation (version2) with Big Endian encoding.”

Repo: crates/dcps/src/runtime.rs (user_payload_encap, encap_in_table, user_encap_body); wire.encapsulation_ids

Tests: crates/dcps/src/runtime.rs::tests::encap_in_table_maps_table_60_onto_table_39, crates/dcps/src/runtime.rs::tests::a_writer_stamps_the_identifiers_of_table_39_when_the_runtime_is_set_to_them, crates/dcps/src/runtime.rs::tests::the_encapsulation_identifiers_of_table_39_are_read, crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility, crates/dcps/tests/runtime_config_layering.rs::the_encapsulation_and_pl_cdr1_settings_default_to_the_vendors_and_are_set_by_file_and_environment

Status: done — CDR2_BE: Big-Endian, gerade Kennung. Gelesen werden beide Wertemengen. Gesendet wird als Vorgabe DDS-XTypes 1.3 Table 60, auf die die Kopfzeile von Table 10.3 verweist und die Cyclone DDS 11.0.1, Fast DDS, OpenDDS 3.34.0 und RTI 7.7.0 senden (gemessen in tools/wire-capture/frames/*/*.xcdr2.frames). Mit wire.encapsulation_ids: table-39 (Umgebung ZERODDS_WIRE_ENCAPSULATION_IDS) sendet ZeroDDS die Kennungen aus Table 39 (§7.4.3.4), deren XCDR2-Werte die aus Table 10.3 sind (XML: {0x01, 0x00}). Erwartet bei den Herstellern: ein Peer, der nur Table 60 liest, kann Daten mit 0x0010 bis 0x0015 nicht lesen; die Einstellung ist für Peers, die Table 10.3 senden und erwarten. Nicht gemessen: ein Lauf gegen die Hersteller mit der Einstellung.

§10.5 Table 10.3 CDR2_LE {0x00, 0x11}

Spec: §10.5, S. 201, Table 10.3 — “CDR2_LE — {0x00, 0x11} — Plain CDR representation (version2) with Little Endian encoding.”

Repo: crates/dcps/src/runtime.rs (user_payload_encap, encap_in_table, user_encap_body); wire.encapsulation_ids

Tests: crates/dcps/src/runtime.rs::tests::encap_in_table_maps_table_60_onto_table_39, crates/dcps/src/runtime.rs::tests::a_writer_stamps_the_identifiers_of_table_39_when_the_runtime_is_set_to_them, crates/dcps/src/runtime.rs::tests::the_encapsulation_identifiers_of_table_39_are_read, crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility, crates/dcps/tests/runtime_config_layering.rs::the_encapsulation_and_pl_cdr1_settings_default_to_the_vendors_and_are_set_by_file_and_environment

Status: done — CDR2_LE. Gelesen werden beide Wertemengen. Gesendet wird als Vorgabe DDS-XTypes 1.3 Table 60, auf die die Kopfzeile von Table 10.3 verweist und die Cyclone DDS 11.0.1, Fast DDS, OpenDDS 3.34.0 und RTI 7.7.0 senden (gemessen in tools/wire-capture/frames/*/*.xcdr2.frames). Mit wire.encapsulation_ids: table-39 (Umgebung ZERODDS_WIRE_ENCAPSULATION_IDS) sendet ZeroDDS die Kennungen aus Table 39 (§7.4.3.4), deren XCDR2-Werte die aus Table 10.3 sind (XML: {0x01, 0x00}). Erwartet bei den Herstellern: ein Peer, der nur Table 60 liest, kann Daten mit 0x0010 bis 0x0015 nicht lesen; die Einstellung ist für Peers, die Table 10.3 senden und erwarten. Nicht gemessen: ein Lauf gegen die Hersteller mit der Einstellung.

§10.5 Table 10.3 PL_CDR2_BE {0x00, 0x12}

Spec: §10.5, S. 201, Table 10.3 — “PL_CDR2_BE — {0x00, 0x12} — Extended CDR representation (version2) for MUTABLE types with Big Endian encoding.”

Repo: crates/dcps/src/runtime.rs (user_payload_encap, encap_in_table, user_encap_body); wire.encapsulation_ids

Tests: crates/dcps/src/runtime.rs::tests::encap_in_table_maps_table_60_onto_table_39, crates/dcps/src/runtime.rs::tests::a_writer_stamps_the_identifiers_of_table_39_when_the_runtime_is_set_to_them, crates/dcps/src/runtime.rs::tests::the_encapsulation_identifiers_of_table_39_are_read, crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility, crates/dcps/tests/runtime_config_layering.rs::the_encapsulation_and_pl_cdr1_settings_default_to_the_vendors_and_are_set_by_file_and_environment

Status: done — PL_CDR2_BE. Gelesen werden beide Wertemengen. Gesendet wird als Vorgabe DDS-XTypes 1.3 Table 60, auf die die Kopfzeile von Table 10.3 verweist und die Cyclone DDS 11.0.1, Fast DDS, OpenDDS 3.34.0 und RTI 7.7.0 senden (gemessen in tools/wire-capture/frames/*/*.xcdr2.frames). Mit wire.encapsulation_ids: table-39 (Umgebung ZERODDS_WIRE_ENCAPSULATION_IDS) sendet ZeroDDS die Kennungen aus Table 39 (§7.4.3.4), deren XCDR2-Werte die aus Table 10.3 sind (XML: {0x01, 0x00}). Erwartet bei den Herstellern: ein Peer, der nur Table 60 liest, kann Daten mit 0x0010 bis 0x0015 nicht lesen; die Einstellung ist für Peers, die Table 10.3 senden und erwarten. Nicht gemessen: ein Lauf gegen die Hersteller mit der Einstellung.

§10.5 Table 10.3 PL_CDR2_LE {0x00, 0x13}

Spec: §10.5, S. 201, Table 10.3 — “PL_CDR2_LE — {0x00, 0x13} — Extended CDR representation (version2) for MUTABLE types with Little Endian encoding.”

Repo: crates/dcps/src/runtime.rs (user_payload_encap, encap_in_table, user_encap_body); wire.encapsulation_ids

Tests: crates/dcps/src/runtime.rs::tests::encap_in_table_maps_table_60_onto_table_39, crates/dcps/src/runtime.rs::tests::a_writer_stamps_the_identifiers_of_table_39_when_the_runtime_is_set_to_them, crates/dcps/src/runtime.rs::tests::the_encapsulation_identifiers_of_table_39_are_read, crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility, crates/dcps/tests/runtime_config_layering.rs::the_encapsulation_and_pl_cdr1_settings_default_to_the_vendors_and_are_set_by_file_and_environment

Status: done — PL_CDR2_LE. Gelesen werden beide Wertemengen. Gesendet wird als Vorgabe DDS-XTypes 1.3 Table 60, auf die die Kopfzeile von Table 10.3 verweist und die Cyclone DDS 11.0.1, Fast DDS, OpenDDS 3.34.0 und RTI 7.7.0 senden (gemessen in tools/wire-capture/frames/*/*.xcdr2.frames). Mit wire.encapsulation_ids: table-39 (Umgebung ZERODDS_WIRE_ENCAPSULATION_IDS) sendet ZeroDDS die Kennungen aus Table 39 (§7.4.3.4), deren XCDR2-Werte die aus Table 10.3 sind (XML: {0x01, 0x00}). Erwartet bei den Herstellern: ein Peer, der nur Table 60 liest, kann Daten mit 0x0010 bis 0x0015 nicht lesen; die Einstellung ist für Peers, die Table 10.3 senden und erwarten. Nicht gemessen: ein Lauf gegen die Hersteller mit der Einstellung.

§10.5 Table 10.3 D_CDR_BE {0x00, 0x14}

Spec: §10.5, S. 201, Table 10.3 — “D_CDR_BE — {0x00, 0x14} — Extended CDR representation (version2) for APPENDABLE types with Big Endian encoding.”

Repo: crates/dcps/src/runtime.rs (user_payload_encap, encap_in_table, user_encap_body); wire.encapsulation_ids

Tests: crates/dcps/src/runtime.rs::tests::encap_in_table_maps_table_60_onto_table_39, crates/dcps/src/runtime.rs::tests::a_writer_stamps_the_identifiers_of_table_39_when_the_runtime_is_set_to_them, crates/dcps/src/runtime.rs::tests::the_encapsulation_identifiers_of_table_39_are_read, crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility, crates/dcps/tests/runtime_config_layering.rs::the_encapsulation_and_pl_cdr1_settings_default_to_the_vendors_and_are_set_by_file_and_environment

Status: done — D_CDR_BE. Gelesen werden beide Wertemengen. Gesendet wird als Vorgabe DDS-XTypes 1.3 Table 60, auf die die Kopfzeile von Table 10.3 verweist und die Cyclone DDS 11.0.1, Fast DDS, OpenDDS 3.34.0 und RTI 7.7.0 senden (gemessen in tools/wire-capture/frames/*/*.xcdr2.frames). Mit wire.encapsulation_ids: table-39 (Umgebung ZERODDS_WIRE_ENCAPSULATION_IDS) sendet ZeroDDS die Kennungen aus Table 39 (§7.4.3.4), deren XCDR2-Werte die aus Table 10.3 sind (XML: {0x01, 0x00}). Erwartet bei den Herstellern: ein Peer, der nur Table 60 liest, kann Daten mit 0x0010 bis 0x0015 nicht lesen; die Einstellung ist für Peers, die Table 10.3 senden und erwarten. Nicht gemessen: ein Lauf gegen die Hersteller mit der Einstellung.

§10.5 Table 10.3 D_CDR_LE {0x00, 0x15}

Spec: §10.5, S. 201, Table 10.3 — “D_CDR_LE — {0x00, 0x15} — Extended CDR representation (version2) for APPENDABLE types with Little Endian encoding.”

Repo: crates/dcps/src/runtime.rs (user_payload_encap, encap_in_table, user_encap_body); wire.encapsulation_ids

Tests: crates/dcps/src/runtime.rs::tests::encap_in_table_maps_table_60_onto_table_39, crates/dcps/src/runtime.rs::tests::a_writer_stamps_the_identifiers_of_table_39_when_the_runtime_is_set_to_them, crates/dcps/src/runtime.rs::tests::the_encapsulation_identifiers_of_table_39_are_read, crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility, crates/dcps/tests/runtime_config_layering.rs::the_encapsulation_and_pl_cdr1_settings_default_to_the_vendors_and_are_set_by_file_and_environment

Status: done — D_CDR_LE. Gelesen werden beide Wertemengen. Gesendet wird als Vorgabe DDS-XTypes 1.3 Table 60, auf die die Kopfzeile von Table 10.3 verweist und die Cyclone DDS 11.0.1, Fast DDS, OpenDDS 3.34.0 und RTI 7.7.0 senden (gemessen in tools/wire-capture/frames/*/*.xcdr2.frames). Mit wire.encapsulation_ids: table-39 (Umgebung ZERODDS_WIRE_ENCAPSULATION_IDS) sendet ZeroDDS die Kennungen aus Table 39 (§7.4.3.4), deren XCDR2-Werte die aus Table 10.3 sind (XML: {0x01, 0x00}). Erwartet bei den Herstellern: ein Peer, der nur Table 60 liest, kann Daten mit 0x0010 bis 0x0015 nicht lesen; die Einstellung ist für Peers, die Table 10.3 senden und erwarten. Nicht gemessen: ein Lauf gegen die Hersteller mit der Einstellung.

§10.5 Table 10.3: Kennungen 0x0010 bis 0x0015

Spec: §10.5, S. 201, Table 10.3 — “CDR2_BE {0x00, 0x10}”, “CDR2_LE {0x00, 0x11}”, “PL_CDR2_BE {0x00, 0x12}”, “PL_CDR2_LE {0x00, 0x13}”, “D_CDR_BE {0x00, 0x14}”, “D_CDR_LE {0x00, 0x15}”.

Repo: crates/dcps/src/runtime.rs (user_payload_encap, encap_in_table, user_encap_body); wire.encapsulation_ids

Tests: crates/dcps/src/runtime.rs::tests::encap_in_table_maps_table_60_onto_table_39, crates/dcps/src/runtime.rs::tests::a_writer_stamps_the_identifiers_of_table_39_when_the_runtime_is_set_to_them, crates/dcps/src/runtime.rs::tests::the_encapsulation_identifiers_of_table_39_are_read, crates/dcps/src/runtime.rs::tests::user_payload_encap_maps_repr_and_extensibility, crates/dcps/tests/runtime_config_layering.rs::the_encapsulation_and_pl_cdr1_settings_default_to_the_vendors_and_are_set_by_file_and_environment

Status: done — Die sechs Kennungen 0x0010 bis 0x0015 (gerade Big-Endian, ungerade Little-Endian). Gelesen werden beide Wertemengen. Gesendet wird als Vorgabe DDS-XTypes 1.3 Table 60, auf die die Kopfzeile von Table 10.3 verweist und die Cyclone DDS 11.0.1, Fast DDS, OpenDDS 3.34.0 und RTI 7.7.0 senden (gemessen in tools/wire-capture/frames/*/*.xcdr2.frames). Mit wire.encapsulation_ids: table-39 (Umgebung ZERODDS_WIRE_ENCAPSULATION_IDS) sendet ZeroDDS die Kennungen aus Table 39 (§7.4.3.4), deren XCDR2-Werte die aus Table 10.3 sind (XML: {0x01, 0x00}). Erwartet bei den Herstellern: ein Peer, der nur Table 60 liest, kann Daten mit 0x0010 bis 0x0015 nicht lesen; die Einstellung ist für Peers, die Table 10.3 senden und erwarten. Nicht gemessen: ein Lauf gegen die Hersteller mit der Einstellung.

§10.5 Table 10.3 XML {0x00, 0x04}

Spec: §10.5, S. 201, Table 10.3 — “XML — {0x00, 0x04} — See DDS-XTypes [3] clause 7.4.4.”

Repo: crates/dcps/src/runtime.rs (XML_ENCAP, user_payload_encap, xml_wire_body, xml_sample_as_cdr); crates/dcps/src/xml_data.rs; crates/dcps/src/publisher.rs

Tests: crates/dcps/src/runtime.rs::tests::an_xml_sample_reaches_the_reader_as_its_cdr_body, crates/dcps/src/runtime.rs::tests::an_xml_sample_that_is_no_document_of_the_type_is_refused, crates/dcps/src/runtime.rs::tests::an_xml_dispose_carries_the_instance_key, crates/dcps/src/runtime.rs::tests::an_xml_writer_sends_the_document_of_the_sample, crates/dcps/src/runtime.rs::tests::a_writer_registered_with_xml_first_is_accepted

Status: done — ein Writer, dessen erste DataRepresentation XML ist, sendet das Dokument des Samples unter {0x00, 0x04}; ein Reader liest die Probe gegen seinen registrierten Typ und gibt den XCDR2-Rumpf weiter. Nicht gemessen: ein Hersteller, der XML sendet oder liest.

§10.5 Ältere DDS-Implementierungen ohne DDS-XTypes

Spec: §10.5, S. 201 — “Legacy DDS implementations that are not compliant with DDS-XTYPES should minimally support the RepresentationIdentifier values CDR_BE and CDR_LE and the type system elements specified in clause F1”.

Repo: —

Tests: —

Status: n/a (informative) — richtet sich an Implementierungen ohne DDS-XTypes; ZeroDDS unterstützt CDR_BE und CDR_LE (§10.5 Table 10.3).

§10.6 Beispiel für Daten eines Builtin-Endpoints

Spec: §10.6, S. 201–203 — “Following is the SerializedPayload element used by the SEDPbuiltinSubscriptionsWriter to declare a DataReader.” mit Aufbau und Oktetten.

Repo: crates/rtps/src/subscription_data.rs (SubscriptionBuiltinTopicData::from_pl_cdr_le, to_pl_cdr_le)

Tests: crates/rtps/src/subscription_data.rs::tests::the_example_of_10_6_is_read, crates/rtps/src/subscription_data.rs::tests::the_parameters_of_the_example_of_10_6_are_written_as_the_spec_prints_them

Status: done — die 84 Oktette der Spec werden als der DataReader gelesen, den sie beschreiben; die fünf Parameter des Beispiels schreibt der Encoder mit denselben Oktetten (die Spec lässt die Vorgabewerte aus, ZeroDDS schreibt sie zusätzlich).

§10.7 Beispiel für Daten eines Anwender-Topics

Spec: §10.7, S. 203–204 — “Following is the SerializedPayload element used by an application DataWriter to send Data on the Topic “Square” with type “ShapeType”” mit Aufbau und Oktetten.

Repo: crates/dcps/src/runtime.rs (user_payload_encap, strip_user_encap)

Tests: crates/dcps/src/runtime.rs::tests::the_example_of_10_7_has_the_header_and_body_of_the_spec

Status: done — Kopf CDR_LE ({0x00, 0x01}, Optionen 0) und der Rumpf von 24 Oktetten des Beispiels („BLUE“, 34, 100, 24) werden so gelesen, wie die Spec sie druckt; der Kopf für einen XCDR1-Final-Writer ist der der Spec.

Annex A References

Annex A Literatur

Spec: Annex A, S. 205 — “[1] DDS-SECURITY: DDS Security version 1.1 https://www.omg.org/spec/DDS-SECURITY”.

Repo: —

Tests: —

Status: n/a (informative) — Literaturverzeichnis.


Audit-Status

978 done / 3 partial / 15 open / 2 blocked / 127 n/a (informative).

Offene Punkte: ddsi-rtps-2.5.open.md.