5.7. Discovery

This section discusses the implementation of discovery plugins in RTI Connext Micro. For a general overview of discovery in RTI Connext Micro, see What is Discovery?.

Connext Micro discovery traffic is conducted through transports. Please see the Transports section for more information about registering and configuring transports.

5.7.1. What is Discovery?

Discovery is the behind-the-scenes way in which RTI Connext Micro objects (DomainParticipants, DataWriters, and DataReaders) on different nodes find out about each other. Each DomainParticipant maintains a database of information about all the active DataReaders and DataWriters that are in the same DDS domain. This database is what makes it possible for DataWriters and DataReaders to communicate. To create and refresh the database, each application follows a common discovery process.

This section describes the default discovery mechanism known as the Simple Discovery Protocol, which includes two phases: Simple Participant Discovery and Simple Endpoint Discovery.

The goal of these two phases is to build, for each DomainParticipant, a complete picture of all the entities that belong to the remote participants that are in its peers list. The peers list is the list of nodes with which a participant may communicate. It starts out the same as the initial_peers list that you configure in the DISCOVERY QosPolicy. If the accept_unknown_peers flag in that same QosPolicy is TRUE, then other nodes may also be added as they are discovered; if it is FALSE, then the peers list will match the initial_peers list, plus any peers added using the DomainParticipant’s add_peer() operation.

The following section discusses how Connext Micro objects on different nodes find out about each other using the default Simple Discovery Protocol (SDP). It describes the sequence of messages that are passed between Connext Micro on the sending and receiving sides.

The discovery process occurs automatically, so you do not have to implement any special code. For more information about advanced topics related to Discovery, please refer to the Discovery chapter in the RTI Connext DDS Core Libraries User’s Manual (available here if you have Internet access).

5.7.1.1. Simple Participant Discovery

This phase of the Simple Discovery Protocol is performed by the Simple Participant Discovery Protocol (SPDP).

During the Participant Discovery phase, DomainParticipants learn about each other. The DomainParticipant’s details are communicated to all other DomainParticipants in the same DDS domain by sending participant declaration messages, also known as participant DATA submessages. The details include the DomainParticipant’s unique identifying key (GUID or Globally Unique ID described below), transport locators (addresses and port numbers), and QoS. These messages are sent on a periodic basis using best-effort communication.

Participant DATAs are sent periodically to maintain the liveliness of the DomainParticipant. They are also used to communicate changes in the DomainParticipant’s QoS. Only changes to QosPolicies that are part of the DomainParticipant’s built-in data need to be propagated.

When receiving remote participant discovery information, RTI Connext Micro determines if the local participant matches the remote one. A ‘match’ between the local and remote participant occurs only if the local and remote participant have the same Domain ID and Domain Tag. This matching process occurs as soon as the local participant receives discovery information from the remote one. If there is no match, the discovery DATA is ignored, resulting in the remote participant (and all its associated entities) not being discovered.

When a DomainParticipant is deleted, a participant DATA (delete) submessage with the DomainParticipant’s identifying GUID is sent.

The GUID is a unique reference to an entity. It is composed of a GUID prefix and an Entity ID. By default, the GUID prefix is calculated from the IP address and the process ID. The entityID is set by Connext Micro (you may be able to change it in a future version).

Once a pair of remote participants have discovered each other, they can move on to the Endpoint Discovery phase, which is how DataWriters and DataReaders find each other.

5.7.1.2. Simple Endpoint Discovery

This phase of the Simple Discovery Protocol is performed by the Simple Endpoint Discovery Protocol (SEDP).

During the Endpoint Discovery phase, RTI Connext Micro matches DataWriters and DataReaders. Information (GUID, QoS, etc.) about your application’s DataReaders and DataWriters is exchanged by sending publication/subscription declarations in DATA messages that we will refer to as publication DATAs and subscription DATAs. The Endpoint Discovery phase uses reliable communication.

These declaration or DATA messages are exchanged until each DomainParticipant has a complete database of information about the participants in its peers list and their entities. Then the discovery process is complete and the system switches to a steady state. During steady state, participant DATAs are still sent periodically to maintain the liveliness status of participants. They may also be sent to communicate QoS changes or the deletion of a DomainParticipant.

When a remote DataWriter/DataReader is discovered, Connext Micro determines if the local application has a matching DataReader/DataWriter. A ‘match’ between the local and remote entities occurs only if the DataReader and DataWriter have the same Topic, same data type, and compatible QosPolicies. Furthermore, if the DomainParticipant has been set up to ignore certain DataWriters/DataReaders, those entities will not be considered during the matching process.

This ‘matching’ process occurs as soon as a remote entity is discovered, even if the entire database is not yet complete: that is, the application may still be discovering other remote entities.

A DataReader and DataWriter can only communicate with each other if each one’s application has hooked up its local entity with the matching remote entity. That is, both sides must agree to the connection.

Please refer to the section on Discovery Implementation in the RTI Connext DDS Core Libraries User’s Manual for more details about the discovery process (available here if you have Internet access).

5.7.2. Configuring Participant Discovery Peers

An RTI Connext Micro DomainParticipant must be able to send participant discovery announcement messages for other DomainParticipants to discover itself, and it must receive announcements from other DomainParticipants to discover them.

To do so, each DomainParticipant will send its discovery announcements to a set of locators known as its peer list, where a peer is the transport locator of one or more potential other DomainParticipants to discover.

5.7.2.1. peer_desc_string

A peer descriptor string of the initial_peers string sequence conveys the interface and address of the locator to which to send, as well as the indices of participants to which to send. For example:

DDS_StringSeq_set_maximum(&dp_qos.discovery.initial_peers, 3);
DDS_StringSeq_set_length(&dp_qos.discovery.initial_peers, 3);

*DDS_StringSeq_get_reference(&dp_qos.discovery.initial_peers, 0) =
     DDS_String_dup("_udp://239.255.0.1");

*DDS_StringSeq_get_reference(&dp_qos.discovery.initial_peers, 1) =
     DDS_String_dup("[1-4]@_udp://10.10.30.101");

*DDS_StringSeq_get_reference(&dp_qos.discovery.initial_peers, 2) =
     DDS_String_dup("[2]@_udp://10.10.30.102");

The peer descriptor format is:

[index@][interface://]address

Remember that every DomainParticipant has a participant index that is unique within a DDS domain. The participant index (also referred to as the participant ID), together with the DDS domain ID, is used to calculate the network port on which DataReaders of that participant will receive messages. Thus, by specifying the participant index, or a range of indices, for a peer locator, that locator becomes a port to which messages will be sent only if addressed to the entities of a particular DomainParticipant. Specifying indices restricts the number of participant announcements sent to a locator where other DomainParticipants exist and, thus, should be considered to minimize network bandwidth usage.

In the above example, the first peer, “_udp://239.255.0.1,” has the default UDPv4 multicast peer locator. Note that there is no [index@] associated with a multicast locator.

The second peer, “[1-4]@_udp://10.10.30.101,” has a unicast address. It also has indices in brackets, [1-4]. These represent a range of participant indices, 1 through 4, to which participant discovery messages will be sent.

Lastly, the third peer, “[2]@_udp://10.10.30.102,” is a unicast locator to a single participant with index 2.

5.7.3. Configuring Initial Peers and Adding Peers

DiscoveryQosPolicy_initial_peers is the list of peers a DomainParticipant sends its participant announcement messages, when it is enabled, as part of the discovery process.

DiscoveryQosPolicy_initial_peers is an empty sequence by default, so while DiscoveryQosPolicy_enabled_transports by default includes the DDS default loopback and multicast (239.255.0.1) addresses, initial_peers must be configured to include them.

Peers can also be added to the list, before and after a DomainParticipant has been enabled, by using DomainParticipant_add_peer.

The DomainParticipant will start sending participant announcement messages to the new peer as soon as it is enabled.

5.7.4. Discovery Plugins

When a DomainParticipant receives a participant discovery message from another DomainParticipant, it will engage in the process of exchanging information of user-created DataWriter and DataReader endpoints.

RTI Connext Micro provides two ways of determinig endpoint information of other DomainParticipants: Dynamic Discovery Plugin and Static Discovery Plugin.

5.7.4.1. Dynamic Discovery Plugin

Dynamic endpoint discovery uses builtin discovery DataWriters and DataReader to exchange messages about user created DataWriter and DataReaders. A DomainParticipant using dynamic participant, dynamic endpoint (DPDE) discovery will have a pair of builtin DataWriters for sending messages about its own user created DataWriters and DataReaders, and a pair of builtin DataReaders for receiving messages from other DomainParticipants about their user created DataWriters and DataReaders.

Given a DomainParticipant with a user DataWriter, receiving an endpoint discovery message for a user DataReader allows the DomainParticipant to get the type, topic, and QoS of the DataReader that determine whether the DataReader is a match. When a matching DataReader is discovered, the DataWriter will include that DataReader and its locators as destinations for its subsequent writes.

5.7.4.2. Static Discovery Plugin

Static endpoint discovery uses function calls to statically assert information about remote endpoints belonging to remote DomainParticipants. An application with a DomainParticipant using dynamic participant, static endpoint (DPSE) discovery has control over which endpoints belonging to particular remote DomainParticipants are discoverable.

Whereas dynamic endpoint-discovery can establish matches for all endpoint-discovery messages it receives, static endpoint-discovery establishes matches only for the endpoint that have been asserted programmatically.

With DPSE, a user needs to know a priori the configuration of the entities that will need to be discovered by its application. The user must know the names of all DomainParticipants within the DDS domain and the exact QoS of the remote DataWriters and DataReaders.

Please refer to the C API Reference and C++ API Reference for the following remote entity assertion APIs:

5.7.4.2.1. Remote Participant Assertion

Given a local DomainParticipant, static discovery requires first the names of remote DomainParticipants to be asserted, in order for endpoints on them to match. This is done by calling DPSE_RemoteParticipant_assert with the name of a remote DomainParticipant. The name must match the name contained in the participant discovery announcement produced by that DomainParticipant. This has to be done reciprocally between two DomainParticipants so that they may discover one another.

For example, a DomainParticipant has entity name “participant_1”, while another DomainParticipant has name “participant_2.” participant_1 should call DPSE_RemoteParticipant_assert(“participant_2”) in order to discover participant_2. Similarly, participant_2 must also assert participant_1 for discovery between the two to succeed.

/* participant_1 is asserting (remote) participant_2 */
retcode = DPSE_RemoteParticipant_assert(participant_1,
                                        "participant_2");
if (retcode != DDS_RETCODE_OK) {
    printf("participant_1 failed to assert participant_2\n");
    goto done;
}

5.7.4.2.2. Remote Publication and Subscription Assertion

Next, a DomainParticipant needs to assert the remote endpoints it wants to match that belong to an already asserted remote DomainParticipant. The endpoint assertion function is used, specifying an argument which contains all the QoS and configuration of the remote endpoint. Where DPDE gets remote endpoint QoS information from received endpoint-discovery messages, in DPSE, the remote endpoint’s QoS must be configured locally. With remote endpoints asserted, the DomainParticipant then waits until it receives a participant discovery announcement from an asserted remote DomainParticipant. Once received that, all endpoints that have been asserted for that remote DomainParticipant are considered discovered and ready to be matched with local endpoints.

Assume participant_1 contains a DataWriter, and participant_2 has a DataReader, both communicating on topic HelloWorld. participant_1 needs to assert the DataReader in participant_2 as a remote subscription. The remote subscription data passed to the operation must match exactly the QoS actually used by the remote DataReader:

/* Set participant_2's reader's QoS in remote subscription data  */
rem_subscription_data.key.value[DDS_BUILTIN_TOPIC_KEY_OBJECT_ID] = 200;
rem_subscription_data.topic_name = DDS_String_dup("Example HelloWorld");
rem_subscription_data.type_name = DDS_String_dup("HelloWorld");
rem_subscription_data.reliability.kind = DDS_RELIABLE_RELIABILITY_QOS;

/* Assert reader as a remote subscription belonging to (remote) participant_2 */
retcode = DPSE_RemoteSubscription_assert(participant_1,
                                         "participant_2",
                                         &rem_subscription_data,
                                         HelloWorld_get_key_kind(HelloWorldTypePlugin_get(), NULL));
if (retcode != DDS_RETCODE_OK)
{
    printf("failed to assert remote subscription\n");
    goto done;
}

Reciprocally, participant_2 must assert participant_1’s DataWriter as a remote publication, also specifying matching QoS parameters:

/* Set participant_1's writer's QoS in remote publication data  */
rem_publication_data.key.value[DDS_BUILTIN_TOPIC_KEY_OBJECT_ID] = 100;
rem_publication_data.key.value.topic_name = DDS_String_dup("Example HelloWorld");
rem_publication_data.key.value.type_name = DDS_String_dup("HelloWorld");
rem_publication_data.key.value.reliability.kind = DDS_RELIABLE_RELIABILITY_QOS;

/* Assert writer as a remote publication belonging to (remote) participant_1 */
retcode = DPSE_RemotePublication_assert(participant_2,
                                        "participant_1",
                                        &rem_publication_data,
                                        HelloWorld_get_key_kind(HelloWorldTypePlugin_get(), NULL));
if (retcode != DDS_RETCODE_OK)
{
    printf("failed to assert remote publication\n");
    goto done;
}

When participant_1 receives a participant discovery message from participant_2, it is aware of participant_2, based on its previous assertion, and it knows participant_2 has a matching DataReader, also based on the previous assertion of the remote endpoint. It therefore establishes a match between its DataWriter and participant_2’s DataReader. Likewise, participant_2 will match participant_1’s DataWriter with its local DataRead, upon receiving one of participant_1’s participant discovery messages.

Note, with DPSE, there is no runtime check of QoS consistency between DataWriters and DataReaders, because no endpoint discovery messages are exchanged. This makes it extremely important that users of DPSE ensure that the QoS set for a local DataWriter and DataReader is the same QoS being used by another DomainParticipant to assert it as a remote DataWriter or DataReader.