5. Understanding the RTPS Packet Format

The RTPS layer contains a header (red) and a list of submessages (green):

RTPS Message

5.1. RTPS Header

The header always has the same size and is formatted as follows:

RTPS Header
  • RTPS: Literally, “RTPS” in four bytes (0x52545053).

  • Protocol version

  • Vendor ID

  • GUID prefix: GUID of the Participant that is sending this RTPS packet. Formed by host ID, app ID, and instance ID.

  • Default port mapping: Not part of the header itself, but information extracted from the destination port of the packet. By knowing the destination port, you can find the domain_id, participant_index, and the nature of the traffic (unicast or multicast, user traffic or meta traffic).

The list of submessages can be of any size (as many submessages can fit in a UDP datagram). A submessage contains a submessage ID, a submessage length (octetsToNextHeader), and the content. OctetsToNextHeader points to the beginning of the next submessage, so if the receiver of this packet doesn’t know how to deserialize this submessage (based on the ID), it can skip it and keep deserializing.

A single UDP datagram may contain multiple RTPS messages. When this occurs, the RTPS Header Extension submessage’s message length field is used to determine where each RTPS message ends and the next one begins. See the HEADER_EXTENSION description below.

5.2. RTPS Submessages

Submessages contain flags. The meaning of the flags depends on the submessage, but the most generic is the “endianness” flag. If present, the data in the submessage should be deserialized as little endian.

Submessages are sent by a DataWriter and can target “any” DataReader (DataReader GUID unknown) or one specific DataReader (DataReader GUID specified). You will see examples of both in the submessage descriptions below. For instance, the DataReader GUID is specified in the example HEARTBEAT submessage (Section 5.2.4) but not specified in the example DATA submessage (Section 5.2.8) .

Submessages not containing DataWriter and DataReader GUIDs are simply prepended to other submessages (INFO_TS specifies the source timestamp of the NEXT submessage, very likely a DATA submessage).

The most common submessages are described below.

5.2.1. HEADER_EXTENSION (0x00)

A HEADER_EXTENSION submessage (also referred to as RTPS_HE) extends the RTPS message header with additional metadata. It is defined in the OMG RTPS 2.5 specification and is typically the first submessage in an RTPS message. It can carry the following optional information, controlled by flags in the submessage header:

  • Message length: The total length of the enclosing RTPS message. This field is required when a single UDP datagram contains multiple RTPS messages, so that the receiver can determine where each message ends and the next begins. Starting with Connext 7.5.0, this field must be correctly populated in every RTPS message that does not end at the end of the underlying datagram.

  • Timestamp: A source timestamp, serving the same purpose as an INFO_TS submessage but embedded in the header extension.

  • uExtension and wExtension: Unsigned 32-bit extension fields available for vendor-specific use.

  • Checksum: A CRC-32C or MD5 checksum for detecting message corruption. See the RTPS Checksum Check feature in Wireshark Features for Packet Analysis.

  • Parameters: An optional parameter list for future extensibility.

5.2.2. INFO_TS (0x09)

An INFO_TS submessage shows the source timestamp of the packet. The endianness bit indicates if it is little endian (1) or big endian (0).

INFO_TS Submessage

5.2.3. INFO_DST (0x0e)

An INFO_DST submessage specifies the GUID of the Participant targeted in the next submessage.

A GUID is specified in order to perform a “directed write” (not a generic publication of a message). If a Participant with a GUID different than the one specified in the INFO_DST receives the message, it will drop it.

INFO_DST Submessage

5.2.4. HEARTBEAT (0x07)

A HEARTBEAT submessage indicates the availability of samples in the DataWriter’s queue. In the example below, the DataWriter is announcing that samples with Sequence Numbers 1 to 6 are available. This is HEARTBEAT number 6 sent by this DataWriter (the two uses of 6 in the example are not related).

HEARTBEAT Submessage

5.2.5. HEARTBEAT_FRAG (0x13)

When fragmenting data, and until all fragments are available, a HEARTBEATFRAG submessage is sent from an RTPS Writer to an RTPS Reader to communicate which fragments the Writer has available. This enables Reliable communication at the fragment level. Once all fragments are available, a regular Heartbeat message is used.

5.2.6. ACKNACK (0x06)

An ACKNACK submessage is used to positively or negatively acknowledge samples “offered” by a DataWriter’s HEARTBEAT. The Bitmap indicates the losses.

ACKNACK Submessage

In the example above, there are no losses. So everything up to Sequence Number 7 (not included) is acknowledged. However, in the example below, starting in sample 4 the first one (bitmap ‘1’) is NACK’ed:

ACKNACK with a Loss

5.2.7. NACK_FRAG (0x12)

A NACK_FRAG submessage is used to communicate the state of a Reader to a Writer. When a data change is sent as a series of fragments, the NACKFRAG submessage allows the Reader to inform the Writer about specific fragment numbers it is still missing.

This submessage can only contain negative acknowledgments. Note this differs from an ACKNACK submessage, which includes both positive and negative acknowledgments.

5.2.8. DATA (0x15)

A DATA submessage contains user data or metatraffic data. User data is data sent by the application by means of the write() operation. Metatraffic data is sent by Connext for different purposes (discovery, matching builtin endpoints, DDS Secure handshakes, etc.).

DATA Submessage

If the DataWriter GUID is known to Wireshark, it means this is metatraffic. For example, above the DataWriter GUID is not known (it is an application-defined writer), but below the DataWriter GUID is known (BUILTIN_PUBLICATIONS_WRITER, discovery traffic for the DataWriters).

DATA Submessage from Known DataWriter GUID

When the DATA submessages contain metatraffic, that information is properly dissected by Wireshark. In this case, we have a Participant announcement from the discovery process (the following figure shows the writerEntityId is BUILTIN_SDP_PARTICIPANT_WRITER, where SDP stands for Simple Discovery Protocol):

DATA Submessage with metatraffic

Because the DataWriter GUID is well known by Wireshark, the packet in the columns view is shown differently. Instead of DATA, it appears as DATA(p):

DATA(p) Submessage

In addition to DATA(p), Wireshark annotates DATA submessages from other well-known builtin endpoints. The annotation appears in the columns view and in the Info column:

  • DATA(p) — Participant discovery data (only SPDP)

  • DATA(P) — Builtin participant secure message (only SPDP). It is the secure variant of DATA(p), used when discovery protection is enabled.

  • DATA(Pb) — Bootstrap message (only SPDP2). Best-effort channel that propagates the minimal information necessary for participant matching (for example, domain ID, participant partition, metatraffic locators, and security configuration).

  • DATA(Pc) — Participant configuration message (only SPDP2). Reliable channel used, after bootstrap matching, to exchange the remainder of the participant’s configuration, propagate subsequent updates to mutable fields, and deliver the participant dispose notification when the participant is destroyed.

  • DATA(sPc) — Secure participant configuration message (only SPDP2).

  • DATA(s) — Participant stateless message. Best-effort channel used for the DDS Security authentication handshake. The handshake payload carries cryptographically signed authentication tokens and establishes the shared secret used to protect the participant volatile channel.

  • DATA(V) — Builtin participant volatile secure message (key exchange). Once authentication via DATA(s) completes, this endpoint distributes the cryptographic keys used to protect the secure builtin endpoints (DATA(P), DATA(sPc), DATA(W), DATA(R), DATA(M)) and user-data traffic.

  • DATA(t) — Topic discovery data (Simple Endpoint Discovery Protocol). Rarely seen in practice, since most implementations propagate topic information through DATA(w) and DATA(r) instead of a dedicated topic endpoint.

  • DATA(w) — Publication (DataWriter) discovery data (Simple Endpoint Discovery Protocol). Contains QoS, topic name, type name, and other properties of a discovered DataWriter.

  • DATA(W) — Secure publication (DataWriter) discovery data. The secure variant of DATA(w), used when discovery protection is enabled.

  • DATA(r) — Subscription (DataReader) discovery data (Simple Endpoint Discovery Protocol). Contains QoS, topic name, type name, and other properties of a discovered DataReader.

  • DATA(R) — Secure subscription (DataReader) discovery data. The secure variant of DATA(r), used when discovery protection is enabled.

  • DATA(m) — Participant liveliness assertion message.

  • DATA(M) — Secure participant liveliness assertion message. The secure variant of DATA(m), used when the builtin ParticipantMessage topic is protected.

  • DATA(trq) — TypeLookup Service request (includes secure variant). See TypeObject v2 and TypeLookup Service.

  • DATA(trp) — TypeLookup Service reply (includes secure variant). See TypeObject v2 and TypeLookup Service.

  • DATA(tq) — Topic Query service request. Sent by a DataReader to request historical samples from a matched DataWriter (for example, when a late-joining reader asks a writer to re-send data that was published before the Rrader existed).

5.2.8.1. Status Info Annotations ([U_], [_D], [UD])

In addition to the writer annotation described above, Wireshark appends an instance-lifecycle annotation in square brackets whenever the DATA submessage carries a PID_STATUS_INFO inline QoS parameter. The annotation has the form [XY], where the first position reports the Unregister flag and the second reports the Dispose flag. A letter indicates the flag is set; an underscore indicates it is not:

  • [U_] — Unregister flag set. The DataWriter is unregistering the instance (it is no longer asserting ownership of the instance’s key).

  • [_D] — Dispose flag set. The instance is being disposed (its lifecycle is ending and readers should transition it to the NOT_ALIVE_DISPOSED state).

  • [UD] — Both flags set. The instance is being unregistered and disposed in the same sample.

  • [__] — Neither flag set. This corresponds to a normal live sample and is only shown when PID_STATUS_INFO is explicitly present in the inline QoS with a value of zero; when the parameter is absent, no bracket annotation is appended at all.

The status annotation is appended directly to the writer letter, so the column may display combinations such as DATA(p[UD]) (a participant announcement carrying an unregister+dispose flag, sent when a participant departs the domain), DATA(w[UD]) / DATA(r[UD]) (a DataWriter or DataReader being removed from discovery), DATA([_D]), or DATA([U_]). When the DataWriter GUID is not a well-known builtin endpoint — for example, an application-defined user-data DataWriter — there is no writer letter to prefix, and the annotation appears standalone as DATA([UD]), DATA([U_]), or DATA([_D]).

5.2.8.2. Compressed Type Objects

When using the RTI Limited Bandwidth Plugins: Wireshark can dissect a compressed Type Object as long as the compression method used is ZLIB. Compressed Type Objects can be inspected under DATA->serializedData->PID_TYPE_OBJECT_LB.

5.2.9. DATA_FRAG (0x16)

A DATA_FRAG submessage extends the DATA submessage by enabling the serializedData to be fragmented and sent as multiple DATA_FRAG submessages. Then the fragments in the DATA_FRAG submessages are reassembled by the RTPSReader.

5.2.10. SEC_PREFIX (0x31)

A SEC_PREFIX submessage provides a way to prefix secure content inside a legal RTPS submessage. This submessage shall be followed by a single RTPS submessage, which shall be followed by a SEC_POSTFIX submessage.

SEC_PREFIX Submessage

The “Transformation Kind” parameter has the following predefined values:

  • NONE (0)

  • AES128_GMAC (1)

  • AES128_GCM (2)

  • AES256_GMAC (3)

  • AES256_GCM (4)

5.2.11. SEC_POSTFIX (0x32)

A SEC_POSTFIX submessage provides a way to authenticate the validity and origin of the RTPS submessage that precedes the SEC_PREFIX. The Cryptographic transformation applied is identified in the related SEC_PREFIX.

SEC_POSTFIX Submessage

5.2.12. SEC_BODY (0x30)

A SEC_BODY submessage wraps one or more regular RTPS submessages in such a way that their contents are secured via encryption, message authentication, and/or digital signatures.

SEC_BODY Submessage

5.2.13. SRTPS_PREFIX (0x33)

An SRTPS_PREFIX submessage provides a way to prefix a list of RTPS submessages so that they can be secured. An SRTPS_PREFIX shall be followed by a list of RTPS submessages, which themselves shall be followed by an SRTPS_POSTFIX submessage.

SRTPS_PREFIX Submessage

The “Transformation Kind” parameter has the following predefined values:

  • NONE (0)

  • AES128_GMAC (1)

  • AES128_GCM (2)

  • AES256_GMAC (3)

  • AES256_GCM (4)

5.2.14. SRTPS_POSTFIX (0x34)

An SRTPS_POSTFIX submessage provides a way to authenticate the validity and origin of the list of RTPS submessages between the related SRTPS_PREFIX and SRTPS_POSTFIX submessages. The Cryptographic transformation applied is identified in the related SRTPS_PREFIX submessage.

SRTPS_POSTFIX Submessage

5.2.15. GAP (0x08)

A GAP submessage is used to inform the DataReader that specific samples are not available in the DataWriter’s queue: for example, when an application is started after samples were sent and the DurabilityQos is VOLATILE. Another example is when samples are filtered out on the DataWriter side and the DataReader doesn’t know about it yet.

GAP Submessage

5.2.16. PAD (0x01)

A PAD submessage allows you to introduce any padding necessary to meet desired memory-alignment requirements. It has no other meaning. This submessage has no content. It accomplishes its purposes with only the submessage header part. The amount of padding is determined by the value of submessageLength.

5.3. RTI Connext Vendor-Specific Submessages

In addition to the standard RTPS submessages described above, Connext defines additional submessages to support features such as batching, session-reliable communication, application-level acknowledgment, and transport-level services. Some of these use submessage IDs that are not defined in the base RTPS specification (0x14–0x1e), while others use IDs in the vendor-specific range (0x80–0xFF). These submessages will appear in captures involving Connext participants.

5.3.1. DATA_SESSION (0x14)

A DATA_SESSION submessage is a DATA variant used on session-based RTPS channels. In addition to the regular writer sequence number, it includes a virtual sequence number. It is used for features that publish on session channels, such as MultiChannel DataWriters and TopicQuery-related traffic. When a DataWriter uses this mode, regular data samples on that channel are sent as DATA_SESSION instead of DATA. For example, both live data samples and data samples in response to a Topic Query will show up in wireshark as DATA_SESSION submessages.

5.3.2. ACK_BATCH (0x17)

An ACK_BATCH submessage provides batch-level positive and negative acknowledgment for samples sent via DATA_BATCH. It is used when batching is enabled.

5.3.3. DATA_BATCH (0x18)

A DATA_BATCH submessage carries multiple data samples packed into a single submessage. Batching improves throughput by amortizing the overhead of submessage headers and network packets across multiple samples. The submessage contains a batch sequence number, the sequence number of the first sample in the batch, and the serialized sample data.

5.3.4. HEARTBEAT_BATCH (0x19)

A HEARTBEAT_BATCH submessage announces the availability of batched samples and is paired with ACK_BATCH. It contains two pairs of sequence numbers: firstSN/lastSN (sample-level) and firstVirtualSN/lastVirtualSN (virtual ordering for the batching protocol).

5.3.5. ACK_SESSION (0x1a)

An ACK_SESSION submessage provides session-level positive and negative acknowledgment for DATA_SESSION traffic. It is used when session-based channels are enabled.

5.3.6. HEARTBEAT_SESSION (0x1b)

A HEARTBEAT_SESSION submessage is the session-level equivalent of HEARTBEAT_BATCH. It announces the availability of samples within a session-reliable communication channel, using the same wire format as HEARTBEAT_BATCH (firstSN/lastSN and firstVirtualSN/lastVirtualSN).

5.3.7. APP_ACK (0x1c)

An APP_ACK submessage is sent by a DataReader to a DataWriter when application acknowledgment is enabled. Unlike ACKNACK, which confirms receipt at the RTPS protocol level, APP_ACK confirms that samples were consumed by the subscribing application (or explicitly acknowledged by it). The submessage reports acknowledged sequence-number intervals, and can carry optional user response data as a sequence of octets.

5.3.8. APP_ACK_CONF (0x1d)

An APP_ACK_CONF submessage is sent by the DataWriter in response to an APP_ACK. It confirms receipt of the APP_ACK so the DataReader can stop retransmitting it. This provides reliability for the application-level acknowledgment protocol itself.

5.3.9. HEARTBEAT_VIRTUAL (0x1e)

A HEARTBEAT_VIRTUAL submessage provides heartbeat information for one or more virtual GUIDs within a single submessage.

5.3.10. RTI_CRC (0x80)

An RTI_CRC submessage contains a CRC-32 checksum for verifying the integrity of the RTPS message. When enabled, this submessage is appended to the message and allows the receiver to detect data corruption that may have occurred during transmission. This submessage is used when the legacy, and deprecated, RTI CRC mechanism is used. The currently supported CRC mechanism is through the use of the Header Extension submessage.

5.3.11. DATA_FRAG_SESSION (0x81)

A DATA_FRAG_SESSION submessage is the session-channel counterpart of DATA_FRAG. It is used when data sent on session-based channels must be fragmented (for example, MultiChannel and TopicQuery traffic), and includes an additional virtual sequence number compared to DATA_FRAG.

5.3.12. BINDING_PING (0x82)

Real-Time WAN Transport uses special RTPS messages called Binding Ping messages to open NAT bindings and to resolve UUID locators into public IP transport addresses.

Binding Ping messages contain the UUID and the RTPS port of the locator with which they are associated. This information allows the receiving Real-Time WAN Transport to create and update the mapping between a (UUID, RTPS port) pair and its corresponding public address.

5.3.13. NDDSPING

An NDDSPING message is a Connext non-standard RTPS message sent by an endpoint to a new UDP destination locator to populate the ARP table. This step helps in speeding up future communication with that location by avoiding unnecessary address resolution requests.