4. Understanding the RTPS Packet Format

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

RTPS Message

4.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.

4.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 4.2.3) but not specified in the example DATA submessage (Section 4.2.7) .

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.

4.2.1. 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

4.2.2. 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

4.2.3. 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

4.2.4. 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.

4.2.5. 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

4.2.6. 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 acknowledgements. Note this differs from an ACKNACK submessage, which includes both positive and negative acknowledgements.

4.2.7. 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 DDS 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

If the DATA submessage contains Publications (w), then Subscriptions (r) or Liveliness assertions (m) are also specified in the columns view.

4.2.7.1. 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.

4.2.8. 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.

4.2.9. 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)

4.2.10. 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

4.2.11. 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

4.2.12. 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)

4.2.13. 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

4.2.14. 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

4.2.15. PAD (0x01)

A PAD submessage allows you to introduce any padding necessary to meet any 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.