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.

Note

DDS Domain concept does not apply when enabling the Discovery Server mechanism.

../../_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 discovery 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.

  • A SERVER is a participant to which the clients (and maybe other servers) send their discovery information. The role of the server is to re-distribute the clients (and servers) discovery information to their known clients and servers. A server may connect to other servers to receive information about their clients. Known servers will receive all the information known by the server. Known clients will only receive the information they need to establish communication, i.e. the information about the DomainParticipants, DataWriters, and DataReaders to which they match. This means that the server runs a “matching” algorithm to sort out which information is required by which client.

  • A BACKUP server is a server that persists its discovery database into a file. This type of server can load the network graph from a file on start-up without the need of receiving any client’s information. It can be used to persist the server knowledge about the network between runs, thus securing the server’s information in case of unexpected shutdowns. It is important to note that the discovery times will be negatively affected when using this type of server, since periodically writing to a file is an expensive operation.

  • A CLIENT is a participant that connects to one or more servers from which it receives only the discovery information they require to establish communication with matching endpoints.

  • Clients require prior knowledge of the servers to which they want to link. Basically it is reduced to the servers identity (henceforth called GuidPrefix_t) and a list of locators where the servers are 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.

  • A SUPER_CLIENT is a client that receives the discovery information known by the server, in opposition to clients, which only receive the information they need.

    Note

    A SUPER_CLIENT does not behave as a Server as it only receives the discovery information through the Server to which it is connected. Any DomainParticipant discovered by the Server with no endpoints will not be known by the SUPER_CLIENT.

  • Servers do not require any prior knowledge of their clients, but their GuidPrefix_t and locator list (where they are listening) must match the one provided to the clients. Clients send discovery messages to the servers at regular intervals (ping period) until they receive message reception acknowledgement. From then on, the server knows about the client and will inform it of the relevant discovery information. The same principle applies to a server connecting to another server.

5.3.4.2. Choosing between Client and Server

It is set by the Discovery Protocol general setting. A participant can only play one role (despite the fact that a server may connect to other servers). It is mandatory to fill this value because it defaults to SIMPLE. The examples below shows how to set this parameter both programmatically and using XML.

C++

DomainParticipantQos pqos;

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

XML

<?xml version="1.0" encoding="UTF-8" ?>
<profiles xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles">
    <participant profile_name="participant_discovery_protocol_alt" >
        <rtps>
            <builtin>
                <discovery_config>
                    <discoveryProtocol>CLIENT</discoveryProtocol>
                    <!-- alternatives
                    <discoveryProtocol>SERVER</discoveryProtocol>
                    <discoveryProtocol>SUPER_CLIENT</discoveryProtocol>
                    <discoveryProtocol>BACKUP</discoveryProtocol>
                    -->
                    </discovery_config>
            </builtin>
        </rtps>
    </participant>
</profiles>

5.3.4.3. 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 specified in server and client setups.

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

eprosima::fastrtps::rtps::GuidPrefix_t serverGuidPrefix;
serverGuidPrefix.value[0] = eprosima::fastrtps::rtps::octet(0x44);
serverGuidPrefix.value[1] = eprosima::fastrtps::rtps::octet(0x53);
serverGuidPrefix.value[2] = eprosima::fastrtps::rtps::octet(0x00);
serverGuidPrefix.value[3] = eprosima::fastrtps::rtps::octet(0x5f);
serverGuidPrefix.value[4] = eprosima::fastrtps::rtps::octet(0x45);
serverGuidPrefix.value[5] = eprosima::fastrtps::rtps::octet(0x50);
serverGuidPrefix.value[6] = eprosima::fastrtps::rtps::octet(0x52);
serverGuidPrefix.value[7] = eprosima::fastrtps::rtps::octet(0x4f);
serverGuidPrefix.value[8] = eprosima::fastrtps::rtps::octet(0x53);
serverGuidPrefix.value[9] = eprosima::fastrtps::rtps::octet(0x49);
serverGuidPrefix.value[10] = eprosima::fastrtps::rtps::octet(0x4d);
serverGuidPrefix.value[11] = eprosima::fastrtps::rtps::octet(0x41);

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

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

DomainParticipantQos serverQos;
std::istringstream("44.53.00.5f.45.50.52.4f.53.49.4d.41") >> serverQos.wire_protocol().prefix;

XML

<?xml version="1.0" encoding="UTF-8" ?>
<profiles xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles">
    <participant profile_name="participant_server_guidprefix" >
        <rtps>
            <prefix>44.53.00.5f.45.50.52.4f.53.49.4d.41</prefix>
        </rtps>
    </participant>
</profiles>

Note that a server can connect to other servers. Thus, the following section may also apply.

Important

When selecting a GUID prefix for the server, it is important to take into account that Fast DDS also uses this parameter to identify participants in the same process and enable intra-process communications. Setting two DomainParticipant GUID prefixes as intra-process compatible will result in no communication if the DomainParticipants run in separate processes. For more information, please refer to GUID Prefix considerations for intra-process delivery.

Warning

Launching more than one server using the same GUID prefix is undefined behavior.

5.3.4.3.2. 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("44.53.00.5f.45.50.52.4f.53.49.4d.41");

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

XML

<?xml version="1.0" encoding="UTF-8" ?>
<profiles xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles">
    <participant profile_name="participant_profile_discovery_client_prefix">
        <rtps>
            <builtin>
                <discovery_config>
                    <discoveryServersList>
                        <RemoteServer prefix="44.53.00.5f.45.50.52.4f.53.49.4d.41">
                            <!-- Metatraffic locators -->
                        </RemoteServer>
                    </discoveryServersList>
                </discovery_config>
            </builtin>
        </rtps>
    </participant>
</profiles>

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

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

<?xml version="1.0" encoding="UTF-8" ?>
<profiles xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles">
    <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>
</profiles>

Note that a server can connect to other servers, thus, the following section may also apply.

5.3.4.4.2. 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 which 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

<?xml version="1.0" encoding="UTF-8" ?>
<profiles xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles">
    <participant profile_name="participant_profile_discovery_server_client_metatraffic">
       <rtps>
            <builtin>
                <discovery_config>
                    <discoveryServersList>
                        <RemoteServer prefix="44.53.00.5f.45.50.52.4f.53.49.4d.41">
                            <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>
</profiles>

5.3.4.5. Fine tuning discovery server handshake

As explained above the clients send discovery messages to the servers at regular intervals (ping period) until they receive message reception acknowledgement. Mind that this period also applies for those servers which connect to other servers. The default value for this period is 450 ms.

C++

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

XML

<?xml version="1.0" encoding="UTF-8" ?>
<profiles xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles">
    <participant profile_name="participant_profile_ping" >
        <rtps>
            <builtin>
                <discovery_config>
                    <clientAnnouncementPeriod>
                        <!-- change default to 250 ms -->
                        <nanosec>250000000</nanosec>
                    </clientAnnouncementPeriod>
                </discovery_config>
            </builtin>
        </rtps>
    </participant>
</profiles>

5.3.4.6. Modifying remote servers list at run time

Once a server or client is running, it is possible to programmatically modify the participant’s list of remote servers to which the running server or client should connect. This is done by calling DomainParticipant::set_qos() with a DomainParticipantQos which has a modified WireProtocolConfigQos (see WireProtocolConfigQos). This feature allows to include a new remote server into the Discovery Server network or modify the remote server locator in case that the remote server is relaunched with a different listening locator.

Important

The list of remote servers can only be modified to either add more servers, or modify the remote server locator, but not to remove any of the existing ones. This means that the new list passed to DomainParticipant::set_qos() must be a superset of the existing one.

Note

The remote server list can also be modified using the ROS_DISCOVERY_SERVER environment variable. Please refer to FASTDDS_ENVIRONMENT_FILE for more information.

Warning

It is strongly advised to use either the API or the environment file. Using both at the same time may cause undefined behavior.

C++

// Get existing QoS for the server or client
DomainParticipantQos client_or_server_qos;
client_or_server->get_qos(client_or_server_qos);

/* Create a new server entry to which the client or server should connect */
RemoteServerAttributes remote_server_att;

// Set server's GUID prefix
remote_server_att.ReadguidPrefix("44.53.00.5f.45.50.52.4f.53.49.4d.42");

// Set server's listening locator for PDP
Locator_t locator;
IPLocator::setIPv4(locator, 127, 0, 0, 1);
locator.port = 11812;
remote_server_att.metatrafficUnicastLocatorList.push_back(locator);

/* Update list of remote servers for this client or server */
client_or_server_qos.wire_protocol().builtin.discovery_config.m_DiscoveryServers.push_back(remote_server_att);
if (ReturnCode_t::RETCODE_OK != client_or_server->set_qos(client_or_server_qos))
{
    // Error
    return;
}

5.3.4.7. Configure Discovery Server locators using names

All the examples provided in Discovery Server Settings use IPv4 addresses to specify the servers’ listening locators. However, Fast DDS also allows to specify locator addresses using names.

5.3.4.8. Full example

The following constitutes a full example on how to configure server and client both programmatically and using XML. You may also have a look at the eProsima Fast DDS Github repository, which contains an example similar to the one discussed in this section, as well as multiple other examples for different use cases.

5.3.4.8.1. Server side setup

C++

// Get default participant QoS
DomainParticipantQos server_qos = PARTICIPANT_QOS_DEFAULT;

// Set participant as SERVER
server_qos.wire_protocol().builtin.discovery_config.discoveryProtocol =
        DiscoveryProtocol_t::SERVER;

// Set SERVER's GUID prefix
std::istringstream("44.53.00.5f.45.50.52.4f.53.49.4d.41") >> server_qos.wire_protocol().prefix;

// Set SERVER's listening locator for PDP
Locator_t locator;
IPLocator::setIPv4(locator, 127, 0, 0, 1);
locator.port = 11811;
server_qos.wire_protocol().builtin.metatrafficUnicastLocatorList.push_back(locator);

/* Add a remote serve to which this server will connect */
// Set remote SERVER's GUID prefix
RemoteServerAttributes remote_server_att;
remote_server_att.ReadguidPrefix("44.53.01.5f.45.50.52.4f.53.49.4d.41");

// Set remote SERVER's listening locator for PDP
Locator_t remote_locator;
IPLocator::setIPv4(remote_locator, 127, 0, 0, 1);
remote_locator.port = 11812;
remote_server_att.metatrafficUnicastLocatorList.push_back(remote_locator);

// Add remote SERVER to SERVER's list of SERVERs
server_qos.wire_protocol().builtin.discovery_config.m_DiscoveryServers.push_back(remote_server_att);

// Create SERVER
DomainParticipant* server =
        DomainParticipantFactory::get_instance()->create_participant(0, server_qos);
if (nullptr == server)
{
    // Error
    return;
}

XML

<?xml version="1.0" encoding="UTF-8" ?>
<profiles xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles">
    <participant profile_name="participant_profile_server_full_example">
        <rtps>
            <!-- Set SERVER's GUID prefix -->
            <prefix>44.53.00.5f.45.50.52.4f.53.49.4d.41</prefix>
            <builtin>
                <!-- Set participant as SERVER -->
                <discovery_config>
                    <discoveryProtocol>SERVER</discoveryProtocol>
                    <!--
                        Set a list of remote servers to which this server connects.
                        This list may contain one or more <RemoteServer> tags
                    -->
                    <discoveryServersList>
                        <!--
                            Set remote server configuration:
                                - Prefix
                                - PDP listening locator
                        -->
                        <RemoteServer prefix="44.53.01.5f.45.50.52.4f.53.49.4d.41">
                            <metatrafficUnicastLocatorList>
                                <!-- Set SERVER's listening locator for PDP -->
                                <locator>
                                    <udpv4>
                                        <address>127.0.0.1</address>
                                        <port>11812</port>
                                    </udpv4>
                                </locator>
                            </metatrafficUnicastLocatorList>
                        </RemoteServer>
                    </discoveryServersList>
                </discovery_config>
                <!-- Set SERVER's listening locator for PDP -->
                <metatrafficUnicastLocatorList>
                    <locator>
                        <udpv4>
                            <address>127.0.0.1</address>
                            <port>11811</port>
                        </udpv4>
                    </locator>
                </metatrafficUnicastLocatorList>
            </builtin>
        </rtps>
    </participant>
</profiles>

5.3.4.8.2. Client side setup

C++

// Get default participant QoS
DomainParticipantQos client_qos = PARTICIPANT_QOS_DEFAULT;

// Set participant as CLIENT
client_qos.wire_protocol().builtin.discovery_config.discoveryProtocol =
        DiscoveryProtocol_t::CLIENT;

// Set SERVER's GUID prefix
RemoteServerAttributes remote_server_att;
remote_server_att.ReadguidPrefix("44.53.00.5f.45.50.52.4f.53.49.4d.41");

// Set SERVER's listening locator for PDP
Locator_t locator;
IPLocator::setIPv4(locator, 127, 0, 0, 1);
locator.port = 11811;
remote_server_att.metatrafficUnicastLocatorList.push_back(locator);

// Add remote SERVER to CLIENT's list of SERVERs
client_qos.wire_protocol().builtin.discovery_config.m_DiscoveryServers.push_back(remote_server_att);

// Set ping period to 250 ms
client_qos.wire_protocol().builtin.discovery_config.discoveryServer_client_syncperiod =
        Duration_t(0, 250000000);

// Create CLIENT
DomainParticipant* client =
        DomainParticipantFactory::get_instance()->create_participant(0, client_qos);
if (nullptr == client)
{
    // Error
    return;
}

XML

<?xml version="1.0" encoding="UTF-8" ?>
<profiles xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles">
    <participant profile_name="participant_profile_client_full_example">
        <rtps>
            <builtin>
                <discovery_config>
                    <!-- Set participant as CLIENT -->
                    <discoveryProtocol>CLIENT</discoveryProtocol>
                    <!--
                        Set list of remote servers. This list may contain one or
                        more <RemoteServer> tags
                    -->
                    <discoveryServersList>
                        <!--
                            Set remote server configuration:
                                - Prefix
                                - PDP listening locator
                        -->
                        <RemoteServer prefix="44.53.00.5f.45.50.52.4f.53.49.4d.41">
                            <metatrafficUnicastLocatorList>
                                <!-- Set SERVER's listening locator for PDP -->
                                <locator>
                                    <udpv4>
                                        <address>127.0.0.1</address>
                                        <port>11811</port>
                                    </udpv4>
                                </locator>
                            </metatrafficUnicastLocatorList>
                        </RemoteServer>
                    </discoveryServersList>
                    <!-- Set ping period to 250 ms -->
                    <clientAnnouncementPeriod>
                        <nanosec>250000000</nanosec>
                    </clientAnnouncementPeriod>
                </discovery_config>
            </builtin>
        </rtps>
    </participant>
</profiles>

5.3.4.9. Security

Configuring Security on servers and clients is done the same way as for any other participant. This section depicts the limitations imposed by the security enforcement on the communication between clients and servers, and which discovery information is propagated by a server depending on the security configuration of the clients and servers to which it is connected.

It is important to note that for enabling a secure discovery when using Discovery Server, Fast DDS must be compiled with security support (see CMake options), and the Domain Governance Document must explicitly encrypt the discovery.

As in SDP, when using this feature, the Domain Governance Document of all clients and servers connecting to a server must match that of the server, which implies that all DomainParticipants belonging to the same Discovery Sever network must configure the discovery protection in the same manner.

Although the server mediates the discovery process and creates connections between clients, the clients themselves still go through the PKI (Public Key Infrastructure) exchange in order to have a secure communication between them.

Important

In order to keep the behavior consistent with the QoS Policies, the server does not check the DomainParticipant Permissions Document of the DomainParticipants that it is connecting.

Important

Security support for Discovery Server is only supported from Fast DDS v2.10.0 onward.