3. TypeObject v2 and TypeLookup Service

3.1. Overview

The RTPS dissector in Wireshark supports two mechanisms for discovering types:

  • TypeObject v1 – Types are propagated inline with discovery packets (DATA(r) and DATA(w)) using the PID_TYPE_OBJECT parameter. This is the mechanism described in User Data Dissection.

  • TypeObject v2 with the TypeLookup Service – Types are exchanged using the TypeLookup Service, a builtin DDS service that allows participants to request and receive types on demand.

TypeObject v2 is the default type propagation mechanism starting with Connext 7.7.0. The RTPS dissector automatically detects whether a capture contains v1 or v2 types and dissects them appropriately. No additional configuration is needed.

Note

This chapter focuses on working with the TypeLookup Service in the RTPS dissector. For complete information about the TypeLookup Service in Connext, see TypeLookup Service in the RTI Core Libraries User’s Manual.

3.2. How TypeLookup Service Works

With TypeObject v2, discovery packets (DATA(r) and DATA(w)) include a TypeInformation parameter (PID_TYPE_INFORMATION) instead of the full TypeObject. TypeInformation contains:

  • A minimal TypeIdentifierWithDependencies – Contains only the information needed for type compatibility checking.

  • A complete TypeIdentifierWithDependencies – Contains the full type information, including member names and annotations, needed to fully reconstruct the type.

A dependent type is a type that is referenced by another type. For example, if a struct contains a member whose type is another struct or an enum, those inner types are dependent types. Plain types (such as primitives and strings) are fully described by their TypeIdentifier alone and do not require a separate TypeObject, so they are not considered dependencies.

Each TypeIdentifierWithDependencies includes an Equivalence Hash that uniquely identifies the type and a Dependent Type Count. The Dependent Type Count indicates how many dependent types exist for the given type. A value of -1 means the remote participant does not specify this count, and the only way to discover the dependent types is by sending a GetTypeDependencies request. Any nonnegative value specifies the exact number of dependent types.

Figure 3.1 shows an example PID_TYPE_INFORMATION in a DATA(r) submessage. In this example, the minimal Equivalence Hash is 0fefe2188c129a45dfade66a98cc, and the complete Equivalence Hash is d56f5822cc7ba62c3d67e43ba967. Both have a Dependent Type Count of -1, indicating that the number of dependent types is unspecified.

PID_TYPE_INFORMATION in a DATA(r) submessage

Figure 3.1 PID_TYPE_INFORMATION in a DATA(r) submessage showing minimal and complete TypeIdentifierWithDependencies.

These TypeIdentifiers uniquely identify the data type but do not contain the full type definition. If a participant does not already have the TypeObject for a given TypeIdentifier, it uses the TypeLookup Service to request it. When participants already have the type announced by the remote endpoints or do not have any local endpoints created on the same topics, no TypeLookup Service traffic will be observed.

There are two kinds of TypeLookup Service operations:

  • GetTypeDependencies – Requests the dependent TypeIdentifiers for a given type. This is used to discover all the types that a complex type depends on.

  • GetTypes – Requests the full TypeObject for one or more TypeIdentifiers. The reply contains the TypeObject for each requested TypeIdentifier.

The workflow for a typical exchange is outlined below:

  • When a participant discovers a remote endpoint with a Dependent Type Count of -1, it does not know what dependencies exist for the type, so it sends a GetTypeDependencies request to find out.

  • Immediately after, as a Connext-only optimization, it sends a GetTypes request for the top-level type because it does not yet have the TypeObject for it.

  • If the GetTypeDependencies reply contains TypeIdentifiers for types the participant does not already have, it sends additional GetTypes requests for those types as well. If the participant already has all the dependent types, no further requests are needed.

Figure 3.2 shows an example DATA(trq) containing a GetTypeDependencies request. The writerEntityId (highlighted) confirms this is a TypeLookup Service request, and the guidPrefix in PID_DIRECTED_WRITE (highlighted) identifies the participant the request is directed to. The request contains the complete Equivalence Hash d56f5822cc7ba62c3d67e43ba967, which corresponds to the type advertised in the DATA(r) shown in Figure 3.1.

DATA(trq) GetTypeDependencies request

Figure 3.2 A DATA(trq) submessage containing a GetTypeDependencies request for the complete Equivalence Hash from the DATA(r) in Figure 3.1.

Figure 3.3 shows the reply to the GetTypeDependencies request. The reply contains the Equivalence Hashes of the 3 non-plain types that the top-level type depends on. Plain types do not appear in this list because their TypeIdentifiers already fully describe the type; TypeObjects do not exist for plain types. Note that the reply does not indicate which top-level type generated the response. However, replies can be matched to their requests using the sample identity, as described in Matching TypeLookup Requests and Replies.

DATA(trp) GetTypeDependencies reply

Figure 3.3 A DATA(trp) submessage containing the GetTypeDependencies reply with the Equivalence Hashes of the 3 non-plain dependent types.

Figure 3.4 shows the GetTypes request for the same Equivalence Hash, sent immediately after the GetTypeDependencies request.

DATA(trq) GetTypes request

Figure 3.4 A DATA(trq) submessage containing a GetTypes request for the same complete Equivalence Hash.

Figure 3.5 shows the DATA(trp) reply to the GetTypes request. The reply contains the TypeObject for the requested type, which is a struct with five members. Members 0, 1, 3, and 4 are plain types (their type definitions are fully described inline). Member 2, however, is not a plain type and therefore has its own Equivalence Hash (highlighted), indicating that an additional GetTypes request would be needed to obtain its full type definition.

DATA(trp) GetTypes reply

Figure 3.5 A DATA(trp) submessage containing the GetTypes reply with the TypeObject for the requested type. The Equivalence Hash of the non-plain member is highlighted.

3.3. Matching TypeLookup Requests and Replies

Each TypeLookup request and its corresponding reply include a Sample Identity, enabling the application to correlate the response with the original request. The DDS RPC specification defines the request and reply headers as follows:

struct SampleIdentity {
    GUID_t writer_guid;
    SequenceNumber_t sequence_number;
};

struct RequestHeader {
    SampleIdentity requestId;
    InstanceName instanceName;
};

struct ReplyHeader {
    SampleIdentity relatedRequestId;
    RemoteExceptionCode_t remoteEx;
};

The requestId in a TypeLookup request header identifies that specific request with a unique combination of the writer’s GUID and a sequence number. The relatedRequestId in the corresponding reply header contains the same sample identity, linking the reply back to the original request.

In Wireshark, the sample identity components appear as:

  • rtps.type_lookup.guidPrefix – The GUID prefix of the TypeLookup writer that sent the request.

  • rtps.type_lookup.seqNumber – The sequence number assigned to the request by the associated writer.

To match a reply to its request, compare the rtps.type_lookup.guidPrefix and rtps.type_lookup.seqNumber fields in both packets. The reply’s values (from relatedRequestId) will match the request’s values (from requestId).

Figure 3.6 shows a GetTypes request with the Sample Identity fields highlighted. Figure 3.7 shows the corresponding reply, where the relatedRequestId contains the same GUID prefix and sequence number, confirming it is the reply to that request.

GetTypes request with Sample Identity highlighted

Figure 3.6 A GetTypes request showing the sample identity (GUID prefix and sequence number) used to match it with its reply.

GetTypes reply with related Sample Identity highlighted

Figure 3.7 The GetTypes reply corresponding to the request in Figure 3.6. The relatedRequestId contains the same GUID prefix and sequence number.

3.4. TypeLookup Service in Wireshark

TypeLookup Service traffic appears in Wireshark as DATA submessages with special designations:

  • DATA(trq) – TypeLookup Service requests

  • DATA(trp) – TypeLookup Service replies

These designations are determined by the endpoint entity IDs used for the TypeLookup Service. The TypeLookup Service endpoints are advertised in the PID_BUILTIN_ENDPOINT_SET of the participant discovery packet (DATA(p)), as shown in Figure 3.8.

TypeLookup Service endpoints in PID_BUILTIN_ENDPOINT_SET

Figure 3.8 TypeLookup Service endpoints (highlighted) in PID_BUILTIN_ENDPOINT_SET of a DATA(p) submessage.

The endpoint entity IDs for the TypeLookup Service are:

Table 3.1 TypeLookup Service Endpoints

Endpoint

Entity ID

TypeLookup Request Writer

0x000300c3

TypeLookup Request Reader

0x000300c4

TypeLookup Reply Writer

0x000301c3

TypeLookup Reply Reader

0x000301c4

When DDS Security is enabled, the TypeLookup Service uses secure variants of these endpoints, advertised in the PID_AVAILABLE_BUILTIN_ENDPOINTS_EXT of the DATA(p), as shown in Figure 3.9.

Secure TypeLookup Service endpoints in PID_AVAILABLE_BUILTIN_ENDPOINTS_EXT

Figure 3.9 Secure TypeLookup Service endpoints in PID_AVAILABLE_BUILTIN_ENDPOINTS_EXT of a DATA(p) submessage.

The secure endpoint entity IDs are:

Table 3.2 Secure TypeLookup Service Endpoints

Endpoint

Entity ID

Secure TypeLookup Request Writer

0xff0300c3

Secure TypeLookup Request Reader

0xff0300c4

Secure TypeLookup Reply Writer

0xff0301c3

Secure TypeLookup Reply Reader

0xff0301c4

3.5. Differences from TypeObject v1

Table 3.3 TypeObject v1 vs. v2

Aspect

TypeObject v1

TypeObject v2

Types in discovery

Full TypeObject sent inline in DATA(r)/DATA(w) via PID_TYPE_OBJECT

TypeInformation (TypeIdentifiers only) sent in DATA(r)/DATA(w) via PID_TYPE_INFORMATION

Type exchange mechanism

None needed; type is fully contained in discovery

TypeLookup Service (GetTypes and GetTypeDependencies request/reply)

Additional traffic

None

DATA(trq) and DATA(trp) submessages for TypeLookup Service

Default in Connext

Before release 7.7.0

Release 7.7.0 and later

3.6. Debug Information

The screenshots in this section do not show XCDR2 serialization metadata such as DHEADER and EMHEADER fields. The RTPS dissector includes a preference called Enable Debug Information that displays this metadata when enabled. This can be useful for troubleshooting serialization issues.

To enable it, go to Edit > Preferences > Protocols > RTPS and select Enable Debug Information. Alternatively, right-click on any RTPS packet and select Protocol Preferences > Real-Time Publish-Subscribe Wire Protocol from the popup menu. This option is disabled by default.

For comparison, Figure 3.10 shows the same GetTypeDependencies request from Figure 3.2 with debug information enabled. Note the additional DHEADER, EMHEADER, and NEXTINT fields visible in the dissection tree.

GetTypeDependencies request with debug information enabled

Figure 3.10 The same GetTypeDependencies request as Figure 3.2 with Enable Debug Information turned on, showing DHEADER, EMHEADER, and NEXTINT fields.