5.3.4. Discovery Server Settings

This mechanism is based on a client-server discovery paradigm, i.e. the metatraffic (message exchange among DomainParticipants to identify each other) is managed by one or several server DomainParticipants (left figure), as opposed to simple discovery (right figure), where metatraffic is exchanged using a message broadcast mechanism like an IP multicast protocol. A Discovery-Server tool is available to ease Discovery Server setup and testing.

../../_images/discovery-server.svg

Comparison of Discovery Server and Simple discovery mechanisms

5.3.4.1. Key concepts

In this architecture there are several key concepts to understand:

  • The Discovery Server mechanism reuses the RTPS discovery messages structure, as well as the standard DDS DataWriters and DataReaders.

  • Discovery Server DomainParticipants may be clients or servers. The only difference between them is how they handle meta-traffic. The user traffic, that is, the traffic among the DataWriters and DataReaders they create, is role-independent.

  • All server and client discovery information will be shared with linked clients. Note that a server may act as a client for other servers.

  • Clients require a beforehand knowledge of the servers to which they want to link. Basically it is reduced to the server identity (henceforth called GuidPrefix_t) and a list of locators where the server is listening. These locators also define the transport protocol (UDP or TCP) the client will use to contact the server.

    • The GuidPrefix_t is the RTPS standard RTPSParticipant unique identifier, a 12-byte chain. This identifier allows clients to assess whether they are receiving messages from the right server, as each standard RTPS message contains this piece of information.

      The GuidPrefix_t is used because the server’s IP address may not be a reliable enough server identifier, since several servers can be hosted in the same machine, thus having the same IP, and also because multicast addresses are acceptable addresses.

  • Servers do not require any beforehand knowledge of their clients, but their GuidPrefix_t and locator list (where they are listening) must match the one provided to the clients. In order to gather client discovery information, the following handshake strategy is followed:

    • Clients send discovery messages to the servers at regular intervals (ping period) until they receive message reception acknowledgement.

    • Servers receive discovery messages from the clients, but they do not start processing them until a time interval has elapsed, which starts at the moment the server is instantiated.

In order to clarify this discovery setup, either on compile time (sources) or runtime (XML files), this explanation is divided into two sections: on focusing on the main concepts (setup by concept), and another one focusing on the main setting structures and XML tags (setup by QoS).

5.3.4.2. Discovery Server setup by concept

Concept

Description

Discovery protocol

Make a participant a client or a server.

Server unique id

Link a clients to servers.

Seting up transport

Specify which transport to use and make servers reachable.

Pinging period

Fine tune discovery server handshake.

Matching period

Fine tune server deliver efficiency.

5.3.4.2.1. Choosing between Client and Server

It is set by the Discovery Protocol general setting. A participant can only play a role (despite the fact that a server may act as a client of other server). It’s mandatory to fill this value because it defaults to simple. The values associated with the Discovery Server are specified in discovery settings section. The examples below show how to manage the corresponding enum and XML tag.

C++

DomainParticipantQos pqos;

pqos.wire_protocol().builtin.discovery_config.discoveryProtocol =
        DiscoveryProtocol_t::CLIENT;
pqos.wire_protocol().builtin.discovery_config.discoveryProtocol =
        DiscoveryProtocol_t::SERVER;
pqos.wire_protocol().builtin.discovery_config.discoveryProtocol =
        DiscoveryProtocol_t::BACKUP;

XML

<participant profile_name="participant_discovery_protocol_alt" >
  <rtps>
    <builtin>
        <discovery_config>
          <discoveryProtocol>CLIENT</discoveryProtocol>
          <!-- alternatives
          <discoveryProtocol>SERVER</discoveryProtocol>
          <discoveryProtocol>BACKUP</discoveryProtocol>
          -->
        </discovery_config>
    </builtin>
  </rtps>
</participant>

5.3.4.2.2. The GuidPrefix as the server unique identifier

The GuidPrefix_t attribute belongs to the RTPS specification and univocally identifies each RTPSParticipant. It consists on 12 bytes and in Fast DDS is a key for the DomainParticipant used in the DDS domain. Fast DDS defines the DomainParticipant GuidPrefix_t as a public data member of the WireProtocolConfigQos class. In the Discovery Server, it has the purpose to link a server to its clients. It must be mandatorily specified in: server and client setups.

Server side setup

The examples below show how to manage the corresponding enum data member and XML tag.

C++ - Option 1: Manual setting of the unsigned char in ASCII format.

using namespace eprosima::fastrtps::rtps;

GuidPrefix_t serverGuidPrefix;
serverGuidPrefix.value[0] = octet(0x77);
serverGuidPrefix.value[1] = octet(0x73);
serverGuidPrefix.value[2] = octet(0x71);
serverGuidPrefix.value[3] = octet(0x85);
serverGuidPrefix.value[4] = octet(0x69);
serverGuidPrefix.value[5] = octet(0x76);
serverGuidPrefix.value[6] = octet(0x95);
serverGuidPrefix.value[7] = octet(0x66);
serverGuidPrefix.value[8] = octet(0x65);
serverGuidPrefix.value[9] = octet(0x82);
serverGuidPrefix.value[10] = octet(0x82);
serverGuidPrefix.value[11] = octet(0x79);

DomainParticipantQos serverQos;
serverQos.wire_protocol().prefix = serverGuidPrefix;

C++ - Option 2: Using the >> operator and the std::ostream type.

DomainParticipantQos serverQos;
std::istringstream("4d.49.47.55.45.4c.5f.42.41.52.52.4f") >> serverQos.wire_protocol().prefix;

XML

<participant profile_name="participant_server_guidprefix" >
  <rtps>
        <prefix>
            4D.49.47.55.45.4c.5f.42.41.52.52.4f
        </prefix>
  </rtps>
</participant>

Note that a server can act as a client of other servers. Thus, the following section may also apply.

Client side setup

Each client must keep a list of the servers to which it wants to link. Each single element represents an individual server and a GuidPrefix_t must be provided. The server list must be populated with RemoteServerAttributes objects with a valid GuidPrefix_t data member. In XML the server list and its elements are simultaneously specified. Note that prefix is an element of the RemoteServer tag.

C++

RemoteServerAttributes server;
server.ReadguidPrefix("4D.49.47.55.45.4c.5f.42.41.52.52.4f");

DomainParticipantQos clientQos;
clientQos.wire_protocol().builtin.discovery_config.m_DiscoveryServers.push_back(server);

XML

<participant profile_name="participant_profile_discovery_client_prefix">
    <rtps>
    <builtin>
        <discovery_config>
          <discoveryServersList>
            <RemoteServer prefix="4D.49.47.55.45.4c.5f.42.41.52.52.4f">
                  <metatrafficUnicastLocatorList>
                    <locator/>
                  </metatrafficUnicastLocatorList>
            </RemoteServer>
          </discoveryServersList>
        </discovery_config>
    </builtin>
  </rtps>
</participant>

5.3.4.2.3. The server locator list

Each server must specify valid locators where it can be reached. Any client must be given proper locators to reach each of its servers. As in the above section, here there is a server and a client side setup.

Server side setup

The examples below show how to setup the server locator list and XML tag.

C++

Locator_t locator;
IPLocator::setIPv4(locator, 192, 168, 1, 133);
locator.port = 64863;

DomainParticipantQos serverQos;
serverQos.wire_protocol().builtin.metatrafficUnicastLocatorList.push_back(locator);

XML

<participant profile_name="participant_profile_discovery_server_server_metatraffic">
       <rtps>
        <builtin>
            <metatrafficUnicastLocatorList>
                <locator>
                    <udpv4>
                    <!-- placeholder server UDP address -->
                        <address>192.168.1.113</address>
                        <port>64863</port>
                    </udpv4>
                </locator>
            </metatrafficUnicastLocatorList>
        </builtin>
    </rtps>
</participant>

Note that a server can act as a client of other servers, thus, the following section may also apply.

Client side setup

Each client must keep a list of locators associated to the servers to which it wants to link. Each server specifies its own locator list and must be populated with RemoteServerAttributes objects with a valid metatrafficUnicastLocatorList or metatrafficMulticastLocatorList. In XML the server list and its elements are simultaneously specified. Note the metatrafficUnicastLocatorList or metatrafficMulticastLocatorList are elements of the RemoteServer tag.

C++

Locator_t locator;
IPLocator::setIPv4(locator, 192, 168, 1, 133);
locator.port = 64863;
RemoteServerAttributes server;
server.metatrafficUnicastLocatorList.push_back(locator);

DomainParticipantQos clientQos;
clientQos.wire_protocol().builtin.discovery_config.m_DiscoveryServers.push_back(server);

XML

<participant profile_name="participant_profile_discovery_server_client_metatraffic">
       <rtps>
        <builtin>
            <discovery_config>
                <discoveryServersList>
                    <RemoteServer prefix="4D.49.47.55.45.4c.5f.42.41.52.52.4f">
                        <metatrafficUnicastLocatorList>
                            <locator>
                                <udpv4>
                                <!-- placeholder server UDP address -->
                                    <address>192.168.1.113</address>
                                    <port>64863</port>
                                </udpv4>
                            </locator>
                        </metatrafficUnicastLocatorList>
                    </RemoteServer>
                </discoveryServersList>
            </discovery_config>
        </builtin>
    </rtps>
</participant>

5.3.4.2.4. Client ping period

As explained above the clients send discovery messages to the servers at regular intervals (ping period) until they receive message reception acknowledgement.

C++

DomainParticipantQos clientQos;
clientQos.wire_protocol().builtin.discovery_config.discoveryServer_client_syncperiod =
        Duration_t(0, 250000000);

XML

<participant profile_name="participant_profile_client_ping" >
  <rtps>
    <builtin>
        <discovery_config>
          <clientAnnouncementPeriod>
            <!-- change default to 250 ms -->
            <nanosec>250000000</nanosec>
          </clientAnnouncementPeriod>
        </discovery_config>
    </builtin>
  </rtps>
</participant>

5.3.4.2.5. Server match period

As explained above, the servers receive discovery messages from new clients to join the communication. However, the servers do not start processing them until a time interval, defined by this period, has elapsed, which starts at the moment the server is instantiated. Therefore, this member specifies a time interval in which the server’s DataReader| is disabled and incoming messages are not processed. It is a time interval intended to allow the server to initialize its resources.

C++

DomainParticipantQos serverQos;
serverQos.wire_protocol().builtin.discovery_config.discoveryServer_client_syncperiod =
        Duration_t(0, 250000000);

XML

<participant profile_name="participant_profile_server_ping" >
  <rtps>
    <builtin>
        <discovery_config>
          <clientAnnouncementPeriod>
            <!-- change default to 250 ms -->
            <nanosec>250000000</nanosec>
          </clientAnnouncementPeriod>
        </discovery_config>
    </builtin>
  </rtps>
</participant>

5.3.4.3. Discovery Server setup by Qos

The settings related with Discovery Server are:

Name

Description

WireProtocolConfigQos
(WireProtocolConfigQos)

Specifies wire protocol settings for a DomainParticipant.
Some of it data members must be modified in order to properly configure a Server.
An example is the prefix data member.

RTPS BuiltinAttributes
(builtin)

It is a public data member of the above WireProtocolConfigQos class.
Allows to specify some mandatory server discovery settings like the addresses were it
listens for clients discovery information.

DiscoverySettings

It is a member of the above BuiltinAttributes structure.
Allows to specify some mandatory and optional Discovery Server settings such as
whether the DomainParticipant is a client or a server, the list of servers it is linked to,
the client-ping, and the server-match frequencies.

5.3.4.3.1. WireProtocolConfigQos

The prefix data member of the WireProtocolConfigQos class specifies the server’s identity. This member has only significance if discovery_config.discoveryProtocol is SERVER or BACKUP.

C++

using namespace eprosima::fastrtps::rtps;

GuidPrefix_t serverGuidPrefix;
serverGuidPrefix.value[0] = octet(0x77);
serverGuidPrefix.value[1] = octet(0x73);
serverGuidPrefix.value[2] = octet(0x71);
serverGuidPrefix.value[3] = octet(0x85);
serverGuidPrefix.value[4] = octet(0x69);
serverGuidPrefix.value[5] = octet(0x76);
serverGuidPrefix.value[6] = octet(0x95);
serverGuidPrefix.value[7] = octet(0x66);
serverGuidPrefix.value[8] = octet(0x65);
serverGuidPrefix.value[9] = octet(0x82);
serverGuidPrefix.value[10] = octet(0x82);
serverGuidPrefix.value[11] = octet(0x79);

DomainParticipantQos serverQos;
serverQos.wire_protocol().prefix = serverGuidPrefix;

XML

<participant profile_name="participant_profile_discovery_client_prefix">
    <rtps>
    <builtin>
        <discovery_config>
          <discoveryServersList>
            <RemoteServer prefix="4D.49.47.55.45.4c.5f.42.41.52.52.4f">
                  <metatrafficUnicastLocatorList>
                    <locator/>
                  </metatrafficUnicastLocatorList>
            </RemoteServer>
          </discoveryServersList>
        </discovery_config>
    </builtin>
  </rtps>
</participant>

5.3.4.3.2. RTPS BuiltinAttributes

All discovery related information is gathered in the BuiltinAttributes discovery_config data member.

In order to receive client metatraffic, metatrafficUnicastLocatorList or metatrafficMulticastLocatorList must be populated with the addresses (IP and port) that were given to the clients.

C++

Locator_t locator;
IPLocator::setIPv4(locator, 192, 168, 1, 133);
locator.port = 64863;

DomainParticipantQos serverQos;
serverQos.wire_protocol().builtin.metatrafficUnicastLocatorList.push_back(locator);

XML

<participant profile_name="participant_profile_discovery_server_metatraffic">
       <rtps>
        <builtin>
            <discovery_config>
              <discoveryProtocol>SERVER</discoveryProtocol>
            </discovery_config>
            <metatrafficUnicastLocatorList>
                <locator>
                    <udpv4>
                    <!-- placeholder server UDP address -->
                        <address>192.168.1.113</address>
                        <port>64863</port>
                    </udpv4>
                </locator>
            </metatrafficUnicastLocatorList>
        </builtin>
    </rtps>
</participant>

5.3.4.3.3. DiscoverySettings

The DiscoveryProtocol_t enum data member (discoveryProtocol) specifies the participant’s discovery kind. As was explained before, to setup the Discovery Server it may be:

enum value

Description

SERVER

Generates a client DomainParticipant, which relies on a server (or servers) to be notified of other clients
presence. This DomainParticipant can create DataWriters and DataReaders of any topic (static or dynamic)
as ordinary DomainParticipants do.

CLIENT

Generates a server DomainParticipant, which receives, manages and spreads its matched client’s metatraffic
assuring any single one is aware of the others. This DomainParticipant can create DataWriters and
DataReaders of any topic (static or dynamic) as ordinary DomainParticipants do.
Servers can link to other servers in order to share its clients information.

BACKUP

Generates a server DomainParticipant with additional functionality over SERVER. Specifically, it uses a
database to backup its client information, so that this information can be automatically restored at any
moment and continue spreading metatraffic to late joiners. A SERVER in the same scenario ought to
collect client information again, introducing a recovery delay.

A m_DiscoveryServers lists the servers linked to a client DomainParticipant. This member has only significance if discoveryProtocol is CLIENT, SERVER or BACKUP. These member elements are RemoteServerAttributes objects that identify each server and report where the servers can be reached:

Data members

Description

guidPrefix

Is the RTPS unique identifier of the remote server DomainParticipant.

metatrafficUnicastLocatorList
metatrafficMulticastLocatorList

Are ordinary LocatorList_t (see LocatorListType) where the server’s
locators must be specified. At least one of them should be populated.

discoveryServer_client_syncperiod

Has only significance if discoveryProtocol is CLIENT, SERVER or
BACKUP. For a client it specifies the pinging period as explained in
key concepts. When a client has not yet established a
reliable connection to a server it pings until the server notices it and
establishes the connection.
For a server it specifies the match period as explained in key concepts.
When a server discovers new clients it only starts exchanging information with them
at regular intervals as a mechanism to bundle discovery information and optimize delivery.
The default value is half a second.

C++

RemoteServerAttributes server;
server.ReadguidPrefix("4D.49.47.55.45.4c.5f.42.41.52.52.4f");

Locator_t locator;
IPLocator::setIPv4(locator, 192, 168, 1, 133);
locator.port = 64863;
server.metatrafficUnicastLocatorList.push_back(locator);

DomainParticipantQos clientQos;
clientQos.wire_protocol().builtin.discovery_config.discoveryProtocol =
        eprosima::fastrtps::rtps::DiscoveryProtocol_t::CLIENT;
clientQos.wire_protocol().builtin.discovery_config.m_DiscoveryServers.push_back(server);
clientQos.wire_protocol().builtin.discovery_config.discoveryServer_client_syncperiod =
        Duration_t(0, 250000000);

XML

<participant profile_name="participant_profile_client" >
  <rtps>
    <builtin>
        <discovery_config>
          <discoveryProtocol>CLIENT</discoveryProtocol>
          <discoveryServersList>
            <RemoteServer prefix="4D.49.47.55.45.4c.5f.42.41.52.52.4f">
              <metatrafficUnicastLocatorList>
                <locator>
                  <udpv4>
                  <!-- placeholder server UDP address -->
                    <address>192.168.1.113</address>
                    <port>64863</port>
                  </udpv4>
                </locator>
              </metatrafficUnicastLocatorList>
            </RemoteServer>
          </discoveryServersList>
          <clientAnnouncementPeriod>
            <!-- change default to 250 ms -->
            <nanosec>250000000</nanosec>
          </clientAnnouncementPeriod>
        </discovery_config>
    </builtin>
  </rtps>
</participant>