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 on 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 a beforehand 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 all the discovery information known by the server, in opposition to clients, which only receive the information they need.

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

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">
                            <metatrafficUnicastLocatorList>
                                <locator/>
                            </metatrafficUnicastLocatorList>
                        </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.

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. Full example

The following constitutes a full example on how to configure server and client both programmatically and using XML.

5.3.4.6.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.6.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>