The current standard in section 8.5 specifies a non-centralized, distributed simple discovery mechanism for RTPS. This mechanism was devised to allow interoperability among independent vendor-specific implementations but is not expected to be optimal in every environment. There are several scenarios were the simple discovery mechanism is unsuitable or plainly cannot be applied:
- a high number of endpoint entities are continuously entering and exiting a large network.
- a network without multicasting capabilities.
In order to cope with the above issues, the Fast-RTPS discovery mechanism was extended with a client-server functionality. Besides, to simplify the management and testing of this new functionality a discovery-server application was devised.
- Linux
- Windows
In order to use discovery server, its necessary have a compatible version of Fast-RTPS installed (over release 1.9.0).
Fast-RTPS v1.10 adoption of DDS API introduces xml and ABI incompatibilities with discovery server tests and examples with version number below v1.2.
Fast RTPS dependencies as tinyxml must be accessible, either because Fast RTPS was build-installed defining THIRDPARTY=ON or because those libraries have been specifically installed.
The well known cross-platform tool colcon was chosen to simplify the installation of the several mutually dependent CMake projects. In order to use colcon, python and CMake must be first installed as detailed in the corresponding hyperlinks.
A discovery-server.repos file is available in order to profit from vcstool capabilities to download the needed repositories. Once vcstool python package is installed download the sources is as easy as download the discovery-server.repos and call:
Linux:
[SOURCES]$ vcs import --input discovery-server.reposWindows:
[SOURCES]> vcs import --input discovery-server.reposon the [SOURCES] directory where the user wants to keep the repositories.
In order to avoid using vcstool the following repositories should be downloaded from github into [SOURCES]:
| PACKAGE | URL | BRANCH |
|---|---|---|
| eProsima/Fast-CDR: | https://github.com/eProsima/Fast-CDR.git | master |
| eProsima/Fast-RTPS: | https://github.com/eProsima/Fast-RTPS.git | master |
| eProsima/Discovery-Server: | https://github.com/eProsima/Discovery-Server.git | master |
| eProsima/foonathan_memory_vendor: | https://github.com/eProsima/foonathan_memory_vendor.git | master |
| leethomason/tinyxml2: | https://github.com/leethomason/tinyxml2.git | master |
We also assume that the user wants to keep the build, log and installation files in a separate directory called
[BUILD]. If this is not the case, flag --base-paths [SOURCES] can be ignored in what follows.
Valid placeholders for the Linux example may be:
| PLACEHOLDER | EXAMPLE PATHS |
|---|---|
| [SOURCES] | /home/username/Documents/colcon_sources |
| [BUILD] | /home/username/Documents/colcon_build |
-
Create directory [BUILD] where we want to keep the build, install and log compilation results.
-
Compile using the colcon tool. Choose the build configuration by declaring CMAKE_BUILD_TYPE as Debug or Release. In this example we've chosen Debug which would be the choice of advance users for debugging purposes:
[BUILD]$ colcon build --base-paths [SOURCES] --packages-up-to discovery-server --cmake-args -DTHIRDPARTY=ON -DLOG_LEVEL_INFO=ON -DCOMPILE_EXAMPLES=ON -DINTERNALDEBUG=ON -DCMAKE_BUILD_TYPE=Debug- In order to run the tests use the following command:
[BUILD]$ colcon test --base-paths [SOURCES] --packages-select discovery-servernote that only the test matching the build (step 2) configuration would run.
- To run the example navigate to directory [BUILD]/install/discovery-server/examples/HelloWorldExampleDS/bin. The configuration bash file located in the install folder must be run first in order to set the required environment variables:
[BUILD]/install/discovery-server/examples/C++/HelloWorldExampleDS/bin$ . ../../../../../local_setup.bashIn order to test the helloworld example open three terminals and run the above command. Then launch the application with different arguments:
[BUILD]/install/discovery-server/examples/HelloWorldExampleDS/bin$ ./HelloWorldExampleDS publisher
[BUILD]/install/discovery-server/examples/HelloWorldExampleDS/bin$ ./HelloWorldExampleDS subscriber
[BUILD]/install/discovery-server/examples/HelloWorldExampleDS/bin$ ./HelloWorldExampleDS serverValid placeholders for the Windows example may be:
| PLACEHOLDER | EXAMPLE PATHS |
|---|---|
| [SOURCES] | C:\Users\username\Documents\colcon_sources |
| [BUILD] | C:\Users\username\Documents\colcon_build |
-
Create directory [BUILD] where you want to keep the build, install and log compilation results.
-
If the generator (compiler) of choice is Visual Studio, launch colcon from a visual studio console. Any console can be setup into a visual studio one by executing a batch file. For example in VS2017 is usually C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat
-
Compile using the colcon tool. If using a multi-configuration generator like Visual Studio we recommend to build both in debug and release modes:
[BUILD]> colcon build --base-paths [SOURCES] --packages-up-to discovery-server --cmake-args -DTHIRDPARTY=ON -DLOG_LEVEL_INFO=ON -DCOMPILE_EXAMPLES=ON -DINTERNALDEBUG=ON -DCMAKE_BUILD_TYPE=Debug
[BUILD]> colcon build --base-paths [SOURCES] --packages-up-to discovery-server --cmake-args -DTHIRDPARTY=ON -DCOMPILE_EXAMPLES=ON -DCMAKE_BUILD_TYPE=ReleaseIf you are using a single configuration tool just make above call with your configuration of choice.
- In order to run the tests in a multi-configuration generator like Visual Studio use the following command:
[BUILD]> colcon test --base-paths [SOURCES] --packages-select discovery-server --ctest-args -C Debughere --ctest-args allows to specify the configuration (Debug or Release) of interest (names are case sensitive). If using a single configuration tool this flag has no effect, as only the test matching the build (step 3) configuration would run.
- In order to run the example, navigate to the directory [BUILD]/install/discovery-server/examples/HelloWorldExampleDS/bin and run the executable, running first the configuration bat file located within install folder in order to set required environment variables:
[BUILD]\install\discovery-server\examples\C++\HelloWorldExampleDS\bin>..\..\..\..\..\local_setup.batTo test the helloworld example open three consoles, run the above bat file and launch the application with different arguments:
[BUILD]\install\discovery-server\examples\C++\HelloWorldExampleDS\bin> HelloWorldExampleDS publisher
[BUILD]\install\discovery-server\examples\C++\HelloWorldExampleDS\bin> HelloWorldExampleDS subscriber
[BUILD]\install\discovery-server\examples\C++\HelloWorldExampleDS\bin> HelloWorldExampleDS serverUnder the new client-server discovery paradigm, the metatraffic (message exchange among participants to identify each other) is centralized in one or several server participants (right figure), as opposed to simple discovery (left figure), where metatraffic is exchanged using a message broadcast mechanism like an IP multicast protocol.
Clients must be aware of how to reach the server, usually by specifying an IP address and a transport protocol like UDP or TCP. Servers don't need any beforehand knowledge of clients but, we must specify where they may be reached by them, usually by specifying a listening IP address and transport protocol.
One of the design goals of the current implementation was to keep both the discovery messages structure and standard
RTPS writer and reader behavior unchanged. In order to do so, clients must be aware of their server's GuidPrefix.
GuidPrefix is the RTPS standard participant unique identifier (basically 12 octets), which allows clients to assess
whether they are receiving messages from the right server, as each standard RTPS message contains this piece of
information. Note that the server's IP address may not be a reliable server's identifier because several can be specified
and multicast addresses are acceptable. In future implementations, any other more convenient and non-standard identifier
may substitute the GuidPrefix at the expense of adding non-standard members to the RTPS discovery messages structure.
Several Fast-RTPS configuration structures have been updated in order to deal with the new client-server discovery strategy. Note that the following elements belong exclusively to fast RTPS builtin discovery architecture and that the discovery server application just profits from the capabilities provided by Fast-RTPS library.
- A
GuidPrefix_t guidPrefixmember specifies the server's identity. This member has only significance ifdiscovery_config.discoveryProtocolis SERVER or BACKUP. There is aReadguidPrefixmethod to easily fill in this member from a string formatted like"4D.49.47.55.45.4c.5f.42.41.52.52.4f"(note that each octet must be a valid hexadecimal figure).
-
All discovery related info is gathered in a
DiscoverySettings discovery_configmember. -
In order to receive client metatraffic,
metatrafficUnicastLocatorListormetatrafficMulticastLocatorListmust be populated with the addresses that were given to the clients.
-
A
DiscoveryProtocol_t discoveryProtocolspecifies the participant's discovery kind:- SIMPLE generates a standard participant with complete backward compatibility with any other RTPS implementation.
- CLIENT generates a client participant, which relies on a server to be notified of other clients presence. This participant can create publishers and subscribers of any topic (static or dynamic) as ordinary participants do.
- SERVER generates a server participant, which receives, manages and spreads its linked clients metatraffic assuring any single one is aware of the others. This participant can create publishers and subscribers of any topic (static or dynamic) as ordinary participants do. Servers can link to other servers in order to share its clients information.
- BACKUP generates a server participant with additional functionality over SERVER. Specifically, it uses a database to backup its client information, so that if for whatever reason it disappears, it can be automatically restored and continue spreading metatraffic to late joiners. A SERVER in the same scenario ought to collect client information again, introducing a recovery delay.
-
A
RemoteServerList_t m_DiscoveryServerslists the servers linked to the participant. This member has only significance ifdiscoveryProtocolis CLIENT, SERVER or BACKUP. These member elements areRemoteServerAttributesobjects that identify each server and report where the servers can be reached:GuidPrefix_t guidPrefixis the RTPS unique identifier of the server participant we want to link to. There is aReadguidPrefixmethod to easily fill in this member from a string formatted like"4D.49.47.55.45.4c.5f.42.41.52.52.4f"(note that each octet must be a valid hexadecimal figure).metatrafficUnicastLocatorListandmetatrafficMulticastLocatorListare ordinaryLocatorList_t(see Fast-RTPS documentation) where the server's locators must be specified. At least one of them should be populated.Duration_t discoveryServer_client_syncperiodspecifies the time span between PDP metatraffic exchange and has only significance ifdiscoveryProtocolis CLIENT, SERVER or BACKUP. The default value is half a second.
Each of the attributes in Fast-RTPS has an echo in the XML profiles. XML profiles make it possible to avoid tiresome hard-coded settings within applications sources using XML configuration files. The fast XML schema was duly updated to accommodate the new client-server attributes:
- The participant profile builtin tag contains a discovery_config tag where all discovery-related info is
gathered. This new tag contains the following new elements:
- a discoveryProtocol tag, where the discovery type can be specified through the
DiscoveryProtocol_tenumeration. - a discoveryServersList tag, where the server or servers linked with a participant can be specified.
- a clientAnnouncementPeriod tag, where the time span between PDP metatraffic exchange can be specified.
- a discoveryProtocol tag, where the discovery type can be specified through the
Below we provide an example XML participant profile using these new tags:
<participant profile_name="UDP 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>
</discovery_config>
</builtin>
</rtps>
</participant>
<participant profile_name="UDP server">
<rtps>
<prefix>
4D.49.47.55.45.4c.5f.42.41.52.52.4f
</prefix>
<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>The discovery server binary (named after the pattern discovery-server-X.X.X(d) where X.X.X is the version
number and the optional d denotes a debug builds) is set up from one or several XML config files passed as command-line
arguments. There are two modes of execution:
-
Processing mode. In this mode a single config file answering to the discovery-server.xsd schema. This schema is basically an extension of the Fast-RTPS one that simplifies the creation of custom servers and provides tools for easily testing specific discovery scenarios.
When using the discovery server with testing purposes one may:
-
immediately validate when test execution is finished. This is the usual case when testing a single process scenario.
-
not validate the test results and generate an XML file with the test results. This results file follows a specific ds-snapshot.xsd schema. This mode is activated by passing a filename in the input config XML. It's the usual case when testing a multiprocess or multimachine scenario. Each process or machine will generate a snapshot XML file (with each one's discovery information record) and all of them would be validated later by running the discovery server binary in validation mode.
> discovery-server-X.X.X(d).exe config_file.xml-
Validation mode. Only for testing purposes. In this mode one or more XML snapshot files generated on Processing mode must be passed as arguments.
Those files would be compared to each other in other to assess if all discovery information was properly propagated by the server or servers involved in the testing.
> discovery-server-X.X.X(d).exe results_file_1.xml results_file_2.xml results_file_3.xml ...-
Merging mode. Only for testing purposes. In this mode one or more XML snapshot files generated on Processing mode, together, with an output file, sign out using an -out flag, must be passed as arguments.
Those files would be merged in a single snapshot file. This single snapshot file it's easier to review that several ones and can be validated using the validation mode above described.
> discovery-server-X.X.X(d).exe -out aggregate_file.xml results_file_1.xml results_file_2.xml results_file_3.xml ...Note that if the colcon deployment strategy described in section Installation was followed, before using the binary we must setup the appropriate environmental variables using colcon generated scripts:
Linux:
[BUILD]/install/discovery-server/bin$ . ../../local_setup.bashWindows:
[BUILD]\install\discovery-server\bin>..\..\local_setup.batwhere:
- the
local_setupbatch sets up the environment variables for the binary execution. - the discovery-server binary name depends on build configuration (debug introduces
dpostfix) and version number. - the config_file.xml is a placeholder for any XML config file that follows the discovery-server.xsd.
The Fast-RTPS HelloWorldExample has been updated to illustrate the client-server functionality. Its installation details are explained in section Installation above. Basically, the publisher and subscriber participants are now clients and can only discover each other when a server participant is created.
As usual, we launch publishers and subscribers by running HelloWorldExampleDS.exe with the corresponding publisher or subscriber argument. Each publisher and subscriber is launched within its own participant, but now the HelloWorldPublisher::init() and HelloWorldSubscriber::init() methods are modified to create clients and add the server address specify by command line see examples.
In order to use UDP, we can rely on the default transport where the locators are actual ports and IP addresses.
RemoteServerAttributes ratt;
ratt.ReadguidPrefix("4D.49.47.55.45.4c.5f.42.41.52.52.4f");
ParticipantAttributes PParam;
PParam.rtps.builtin.discovery_config.discoveryProtocol = DiscoveryProtocol_t::CLIENT;
PParam.rtps.builtin.discovery_config.leaseDuration = c_TimeInfinite;
PParam.rtps.setName("Participant_pub");
// placeholder values for the server address
Locator_t server_address(LOCATOR_KIND_UDPv4, 64863);
IPLocator::setIPv4(server_address, 192, 168, 1, 113);
ratt.metatrafficUnicastLocatorList.push_back(server_address);
PParam.rtps.builtin.discovery_config.m_DiscoveryServers.push_back(ratt);
mp_participant = Domain::createParticipant(PParam);Note that according to former attributes explanation we must populate the DiscoverySettings discovery_config specifying we want to create a DiscoveryProtocol_t::CLIENT and adding a new RemoteServerAttributes object to the m_DiscoveryServers list. In this case, the UDP port 64863 is hardcoded as is the server prefix.
ParticipantAttributes PParam;
PParam.rtps.builtin.discovery_config.discoveryProtocol = DiscoveryProtocol_t::SERVER;
PParam.rtps.ReadguidPrefix("4D.49.47.55.45.4c.5f.42.41.52.52.4f");
PParam.rtps.builtin.discovery_config.leaseDuration = c_TimeInfinite;
PParam.rtps.setName("Participant_server");
// Placeholder values for the server address
Locator_t server_address(LOCATOR_KIND_UDPv4, 64863);
IPLocator::setIPv4(server_address, 192, 168, 1, 113);
PParam.rtps.builtin.metatrafficUnicastLocatorList.push_back(server_address);
mp_participant = Domain::createParticipant(PParam);Note that according with former attributes explanation we must populate the DiscoverySettings discovery_config specifying we want to create a DiscoveryProtocol_t::SERVER and adding a new listening locator to any BuiltinAttributes metatraffic lists (this locator or locators must be known by the clients). In this case the UDP port 64863 is hard-coded as is the server prefix.
For TCP transport is mandatory to disable the default transport setting the RTPSParticipantAttributes::useBuiltinTransports as false and creating a new transport descriptor thus fast RTPS framework might create a suitable transport object.
RemoteServerAttributes ratt;
ratt.ReadguidPrefix("4D.49.47.55.45.4c.5f.42.41.52.52.4f");
ParticipantAttributes PParam;
PParam.rtps.builtin.discovery_config.discoveryProtocol = DiscoveryProtocol_t::CLIENT;
PParam.rtps.builtin.discovery_config.leaseDuration = c_TimeInfinite;
PParam.rtps.setName("Participant_pub");
// Placeholder values for the server address
Locator_t server_address;
server_address.kind = LOCATOR_KIND_TCPv4;
IPLocator::setLogicalPort(server_address, 64863);
IPLocator::setPhysicalPort(server_address, 9843);
IPLocator::setIPv4(server_address, 192, 168, 1, 113);
ratt.metatrafficUnicastLocatorList.push_back(server_address);
PParam.rtps.builtin.discovery_config.m_DiscoveryServers.push_back(ratt);
PParam.rtps.useBuiltinTransports = false;
std::shared_ptr<TCPv4TransportDescriptor> descriptor = std::make_shared<TCPv4TransportDescriptor>();
// Generate a listening port for the client
std::default_random_engine gen(System::GetPID());
std::uniform_int_distribution<int> rdn(49152, 65535);
descriptor->add_listener_port(rdn(gen)); // IANA ephemeral port number
descriptor->wait_for_tcp_negotiation = false;
PParam.rtps.userTransports.push_back(descriptor);
mp_participant = Domain::createParticipant(PParam);The DiscoverySettings discovery_config is almost the same as in the analogous UDP case. Note that here the server_address locator specifies 64863 as a logical port and 9843 as a physical one. The reason behind this is that TCP transport was devised in order to allow a single TCP connection tunnel several participants traffic through it. In order to differentiate each participant sharing the connection, a logical port concept was introduced. The transport will understand that must connect to the physical port (using TCP protocol) and relay meta traffic to the logical port 64863 which is the meta traffic mailbox of the server we are interested in.
A new TCPv4TransportDescriptor must be created and a physical listening port selected. In this case, each HelloWorldExample instance creates a single participant thus the linked process ID is a suitable seed to make up a listening port number (this way each time a new client is created a different port is selected).
ParticipantAttributes PParam;
PParam.rtps.builtin.discovery_config.discoveryProtocol = DiscoveryProtocol_t::SERVER;
PParam.rtps.ReadguidPrefix("4D.49.47.55.45.4c.5f.42.41.52.52.4f");
PParam.rtps.builtin.discovery_config.leaseDuration = c_TimeInfinite;
PParam.rtps.setName("Participant_server");
// Placeholder values for the server address
Locator_t server_address;
server_address.kind = LOCATOR_KIND_TCPv4;
IPLocator::setLogicalPort(server_address, 64863);
IPLocator::setIPv4(server_address, 192, 168, 1, 113);
PParam.rtps.builtin.metatrafficUnicastLocatorList.push_back(server_address);
std::shared_ptr<TCPv4TransportDescriptor> descriptor = std::make_shared<TCPv4TransportDescriptor>();
descriptor->wait_for_tcp_negotiation = false;
descriptor->add_listener_port(9843);
PParam.rtps.useBuiltinTransports = false;
PParam.rtps.userTransports.push_back(descriptor);
mp_participant = Domain::createParticipant(PParam);The DiscoverySettings discovery_config is almost the same as in the analogous UDP case. Note that here the server_address locator specifies 64863 as a logical port instead of a physical one.
A new TCPv4TransportDescriptor must be created and a physical listening port selected. Unlike the client code, this listening port (9843 in the example) must be known beforehand for all clients in order to successfully deliver meta traffic to the server.
Assuming the current directory is the example binary one, the execution steps would be:
- Windows:
Console 1:
>..\..\..\..\..\local_setup.bat
> HelloWorldExampleDS publisherConsole 2:
>..\..\..\..\..\local_setup.bat
> HelloWorldExampleDS subscriberConsole 3:
>..\..\..\..\..\local_setup.bat
> HelloWorldExampleDS server- Linux:
Terminal 1:
$ . ../../../../../local_setup.bash
$ ./HelloWorldExampleDS publisherTerminal 2:
$ . ../../../../../local_setup.bash
$ ./HelloWorldExampleDS subscriberTerminal 3:
$ . ../../../../../local_setup.bash
$ ./HelloWorldExampleDS serverWe need to now the server address and physical port. In our example it would be 192.186.1.113:64863. Defaults to UDP if we want
to use TCP add the --tcp (or the abbreviated -t) flag to the following commands.
- Windows:
Console 1:
>..\..\..\..\..\local_setup.bat
> HelloWorldExampleDS publisher --count=0 --ip=192.168.1.113:64863by specifying --count=0 the publisher keeps publishing samples forever.
Console 2:
>..\..\..\..\..\local_setup.bat
> HelloWorldExampleDS subscriber --ip=192.168.1.113:64863Console 3:
>..\..\..\..\..\local_setup.bat
> HelloWorldExampleDS server --ip=0.0.0.0:64863Note that by using 0.0.0.0 we are hinting the server to publish all the local interfaces as metatraffic (192.168.1.133
would be one of them in this example). The clients once received the server metadata would choose the faster among the server
interfaces. Of course we can force the use of a single interface by doing --ip=192.168.1.133:64863. If we specify
localhost as the interface (by doing --ip=127.0.0.1:64863) only local clients would be able to reach the server (we
strongly discourage this).
Note also that if not port number is provided a default one is used.
Information exchange between publisher and subscriber should take place when the server begins running.
- Linux:
Terminal 1:
$ . ../../../../../local_setup.bash
$ ./HelloWorldExampleDS publisher --count=0 --ip=192.168.1.113:64863Terminal 2:
$ . ../../../../../local_setup.bash
$ ./HelloWorldExampleDS subscriber --ip=192.168.1.113:64863Terminal 3:
$ . ../../../../../local_setup.bash
$ ./HelloWorldExampleDS server --ip=0.0.0.0:64863Discovery testing is done resorting to discover-server configuration files. Each test uses a specific XML file that tests a single or several discovery features. To automatically launch the tests using colcon, please check section Installation. To manually launch a test, use the following procedure:
Linux:
[BUILD]/install/discovery-server/bin$ . ../../local_setup.bash
[BUILD]/install/discovery-server/bin$ ./discovery-server-X.Y.Z(d) [SOURCES]/discovery-server/resources/xml/test_XXX.xmlWindows:
[BUILD]\install\discovery-server\bin>..\..\local_setup.bat
[BUILD]\install\discovery-server\bin>discovery-server-X.Y.Z(d) [SOURCES]\discovery-server\resources\xml\test_XXX.xmlTo view the full discovery information messages and snapshots in debug configuration, run colcon with the additional
flag -DLOG_LEVEL_INFO=ON.
A brief description of each test is given below. Note that a detailed explanation of the XML syntax is given in section Documentation.
This is the most simple scenario: a single server manages the discovery information of four clients. The server prefix and listening ports are given in the profiles UDP server and UDP client. A snapshot is taken after 3 seconds to assess that all clients are aware of the existence of each other.
<servers>
<server name="server" profile_name="UDP server" />
</servers>
<clients>
<client name="client1" profile_name="UDP client"/>
<client name="client2" profile_name="UDP client"/>
<client name="client3" profile_name="UDP client"/>
<client name="client4" profile_name="UDP client"/>
</clients>
<snapshots>
<snapshot time="3">Check all clients met the server and know each other</snapshot>
</snapshots>The snapshot information output would be something like:
2020-04-24 15:52:58.162 [DISCOVERY_SERVER Info] Snapshot taken at 2020-04-24 15:52:58.157 or 3003 ms since process startup. Description: Check all clients met the server and know each other
Snapshot process startup at 2020-04-24 15:52:55.153
Last PDP callback at 2020-04-24 15:52:55.834 or 680 ms since process startup.
Last EDP callback at 2020-04-24 15:52:55.153 or 0 ms since process startup.
5 participants report the following discovery info:
Participant 1.f.26.69.a0.4e.0.0.2.0.0.0|0.0.1.c1 discovered 4 participants, 0 publishers and 0 subscribers:
Participant client2 1.f.26.69.a0.4e.0.0.3.0.0.0|0.0.1.c1
Participant client3 1.f.26.69.a0.4e.0.0.4.0.0.0|0.0.1.c1
Participant client4 1.f.26.69.a0.4e.0.0.5.0.0.0|0.0.1.c1
Participant server 4d.49.47.55.45.4c.5f.42.41.52.52.4f|0.0.1.c1
Participant 1.f.26.69.a0.4e.0.0.3.0.0.0|0.0.1.c1 discovered 4 participants, 0 publishers and 0 subscribers:
Participant client1 1.f.26.69.a0.4e.0.0.2.0.0.0|0.0.1.c1
Participant client3 1.f.26.69.a0.4e.0.0.4.0.0.0|0.0.1.c1
Participant client4 1.f.26.69.a0.4e.0.0.5.0.0.0|0.0.1.c1
Participant server 4d.49.47.55.45.4c.5f.42.41.52.52.4f|0.0.1.c1
Participant 1.f.26.69.a0.4e.0.0.4.0.0.0|0.0.1.c1 discovered 4 participants, 0 publishers and 0 subscribers:
Participant client1 1.f.26.69.a0.4e.0.0.2.0.0.0|0.0.1.c1
Participant client2 1.f.26.69.a0.4e.0.0.3.0.0.0|0.0.1.c1
Participant client4 1.f.26.69.a0.4e.0.0.5.0.0.0|0.0.1.c1
Participant server 4d.49.47.55.45.4c.5f.42.41.52.52.4f|0.0.1.c1
Participant 1.f.26.69.a0.4e.0.0.5.0.0.0|0.0.1.c1 discovered 4 participants, 0 publishers and 0 subscribers:
Participant client1 1.f.26.69.a0.4e.0.0.2.0.0.0|0.0.1.c1
Participant client2 1.f.26.69.a0.4e.0.0.3.0.0.0|0.0.1.c1
Participant client3 1.f.26.69.a0.4e.0.0.4.0.0.0|0.0.1.c1
Participant server 4d.49.47.55.45.4c.5f.42.41.52.52.4f|0.0.1.c1
Participant 4d.49.47.55.45.4c.5f.42.41.52.52.4f|0.0.1.c1 discovered 4 participants, 0 publishers and 0 subscribers:
Participant client1 1.f.26.69.a0.4e.0.0.2.0.0.0|0.0.1.c1
Participant client2 1.f.26.69.a0.4e.0.0.3.0.0.0|0.0.1.c1
Participant client3 1.f.26.69.a0.4e.0.0.4.0.0.0|0.0.1.c1
Participant client4 1.f.26.69.a0.4e.0.0.5.0.0.0|0.0.1.c1
-> Function eprosima::discovery_server::DSManager::validateAllSnapshots
We'll only get this with the Debug binary. On Release mode, we can resort to provide a filename to the snapshots tag. Then an XML file will be generated with the same info (note that generating an XML automatically disables validation thus it cannot be used in singleton tests).
<DS_Snapshots>
<DS_Snapshot timestamp="1587739729185" process_time="3001" last_pdp_callback_time="667" last_edp_callback_time="0" someone="true">
<description>Check all clients met the server and know each other</description>
<ptdb guid_prefix="1.f.26.69.1c.36.0.0.2.0.0.0" guid_entity="0.0.1.c1">
<ptdi guid_prefix="1.f.26.69.1c.36.0.0.3.0.0.0" guid_entity="0.0.1.c1" server="false" alive="true" name="client2" discovered_timestamp="659"/>
<ptdi guid_prefix="1.f.26.69.1c.36.0.0.4.0.0.0" guid_entity="0.0.1.c1" server="false" alive="true" name="client3" discovered_timestamp="667"/>
<ptdi guid_prefix="1.f.26.69.1c.36.0.0.5.0.0.0" guid_entity="0.0.1.c1" server="false" alive="true" name="client4" discovered_timestamp="663"/>
<ptdi guid_prefix="4d.49.47.55.45.4c.5f.42.41.52.52.4f" guid_entity="0.0.1.c1" server="true" alive="true" name="server" discovered_timestamp="619"/>
</ptdb>
<ptdb guid_prefix="1.f.26.69.1c.36.0.0.3.0.0.0" guid_entity="0.0.1.c1">
<ptdi guid_prefix="1.f.26.69.1c.36.0.0.2.0.0.0" guid_entity="0.0.1.c1" server="false" alive="true" name="client1" discovered_timestamp="662"/>
<ptdi guid_prefix="1.f.26.69.1c.36.0.0.4.0.0.0" guid_entity="0.0.1.c1" server="false" alive="true" name="client3" discovered_timestamp="665"/>
<ptdi guid_prefix="1.f.26.69.1c.36.0.0.5.0.0.0" guid_entity="0.0.1.c1" server="false" alive="true" name="client4" discovered_timestamp="659"/>
<ptdi guid_prefix="4d.49.47.55.45.4c.5f.42.41.52.52.4f" guid_entity="0.0.1.c1" server="true" alive="true" name="server" discovered_timestamp="618"/>
</ptdb>
<ptdb guid_prefix="1.f.26.69.1c.36.0.0.4.0.0.0" guid_entity="0.0.1.c1">
<ptdi guid_prefix="1.f.26.69.1c.36.0.0.2.0.0.0" guid_entity="0.0.1.c1" server="false" alive="true" name="client1" discovered_timestamp="667"/>
<ptdi guid_prefix="1.f.26.69.1c.36.0.0.3.0.0.0" guid_entity="0.0.1.c1" server="false" alive="true" name="client2" discovered_timestamp="659"/>
<ptdi guid_prefix="1.f.26.69.1c.36.0.0.5.0.0.0" guid_entity="0.0.1.c1" server="false" alive="true" name="client4" discovered_timestamp="663"/>
<ptdi guid_prefix="4d.49.47.55.45.4c.5f.42.41.52.52.4f" guid_entity="0.0.1.c1" server="true" alive="true" name="server" discovered_timestamp="619"/>
</ptdb>
<ptdb guid_prefix="1.f.26.69.1c.36.0.0.5.0.0.0" guid_entity="0.0.1.c1">
<ptdi guid_prefix="1.f.26.69.1c.36.0.0.2.0.0.0" guid_entity="0.0.1.c1" server="false" alive="true" name="client1" discovered_timestamp="663"/>
<ptdi guid_prefix="1.f.26.69.1c.36.0.0.3.0.0.0" guid_entity="0.0.1.c1" server="false" alive="true" name="client2" discovered_timestamp="659"/>
<ptdi guid_prefix="1.f.26.69.1c.36.0.0.4.0.0.0" guid_entity="0.0.1.c1" server="false" alive="true" name="client3" discovered_timestamp="666"/>
<ptdi guid_prefix="4d.49.47.55.45.4c.5f.42.41.52.52.4f" guid_entity="0.0.1.c1" server="true" alive="true" name="server" discovered_timestamp="618"/>
</ptdb>
<ptdb guid_prefix="4d.49.47.55.45.4c.5f.42.41.52.52.4f" guid_entity="0.0.1.c1">
<ptdi guid_prefix="1.f.26.69.1c.36.0.0.2.0.0.0" guid_entity="0.0.1.c1" server="false" alive="true" name="client1" discovered_timestamp="571"/>
<ptdi guid_prefix="1.f.26.69.1c.36.0.0.3.0.0.0" guid_entity="0.0.1.c1" server="false" alive="true" name="client2" discovered_timestamp="529"/>
<ptdi guid_prefix="1.f.26.69.1c.36.0.0.4.0.0.0" guid_entity="0.0.1.c1" server="false" alive="true" name="client3" discovered_timestamp="588"/>
<ptdi guid_prefix="1.f.26.69.1c.36.0.0.5.0.0.0" guid_entity="0.0.1.c1" server="false" alive="true" name="client4" discovered_timestamp="556"/>
</ptdb>
</DS_Snapshot>
</DS_Snapshots>Here we see how all participants reported the discovery of all the others. Note that, because there is no Fast-RTPS discovery callback from a participant to report its own discovery, participants do not report themselves. This must be taken into account when a snapshot is checked. Note, however, that participants do discover themselves when they create a publisher or subscriber because there are callbacks associated with those cases.
Resembles the previous scenario but uses TCP transport instead of the default UDP one. A single server manages the discovery info of four clients. The server prefix and listening ports are given in the profiles TCP server and TCP client. A snapshot is taken after 3 seconds to assess that all clients are aware of the existence of each other.
Specific transport descriptor must be created for server and clients:
<transport_descriptor>
<transport_id>TCPv4_SERVER</transport_id>
<type>TCPv4</type>
<listening_ports>
<port>48661</port>
</listening_ports>
<calculate_crc>false</calculate_crc>
<check_crc>false</check_crc>
</transport_descriptor>
<transport_descriptor>
<transport_id>TCPv4_CLIENT</transport_id>
<type>TCPv4</type>
<calculate_crc>false</calculate_crc>
<check_crc>false</check_crc>
</transport_descriptor>Client and server participant profiles must reference this transport and discard builtin ones.
<participant profile_name="TCP client" >
<rtps>
<userTransports>
<transport_id>TCPv4_CLIENT</transport_id>
</userTransports>
<useBuiltinTransports>false</useBuiltinTransports>
...
</rtps>
</participant>
<participant profile_name="TCP server" >
<rtps>
....
<userTransports>
<transport_id>TCPv4_SERVER</transport_id>
</userTransports>
<useBuiltinTransports>false</useBuiltinTransports>
...
</rtps>
</participant>Here we test the discovery capacity of handling late joiners. A single server is created, which manages the discovery information of four clients with different lifespans. The server prefix and listening ports are given in the profiles UDP server and UDP client. A snapshot is taken whenever there is a participant creation or removal to assess all entities are aware of it.
<servers>
<server name="server" profile_name="UDP server" />
</servers>
<clients>
<client name="client1" profile_name="UDP client" removal_time="8"/>
<client name="client2" profile_name="UDP client" creation_time="2" removal_time="10" />
<client name="client3" profile_name="UDP client" creation_time="4" removal_time="12" />
<client name="client4" profile_name="UDP client" creation_time="6" removal_time="14" />
</clients>
<snapshots>
<snapshot time="1">Check server and client1 known each other</snapshot>
<snapshot time="3">Check server and client1 acknowledge client2 creation</snapshot>
<snapshot time="5">Check server, client1 and client2 acknowledge client3 creation</snapshot>
<snapshot time="7">Check server, client1, client2 and client3 acknowledge client4 creation</snapshot>
<snapshot time="9">Check client1 removal is acknowledge by all remaining</snapshot>
<snapshot time="11">Check client2 removal is acknowledge by all remaining</snapshot>
<snapshot time="13">Check client3 removal is acknowledge by all remaining</snapshot>
<snapshot time="15">Check client4 removal is acknowledge by all remaining</snapshot>
</snapshots>Here we test the capability of one server to exchange information with another one. Two servers are created and each one has two associated clients. We take a snapshot to assess all clients are aware of the other server's clients existence. Note that we don't need to modify the previous tests profiles, as we can rely on the server and client tag attributes to avoid create redundant boilerplate profiles:
- server prefix attribute is used to supersede the profile specified one and uniquely identifies each server.
- server ListeningPorts and ServerList tags allow us to link servers between them without creating specific server profiles.
- client server attribute is used to link a client with its server without using a new profile or a ServerList.
<servers>
<server name="server1" prefix="4D.49.47.55.45.4c.5f.42.41.52.52.4f" profile_name="UDP server" />
<server name="server2" prefix="4D.49.47.55.45.4c.7e.42.41.52.52.4f" profile_name="UDP server">
<ListeningPorts>
<metatrafficUnicastLocatorList>
<locator>
<udpv4>
<address>127.0.0.1</address>
<port>65221</port>
</udpv4>
</locator>
</metatrafficUnicastLocatorList>
</ListeningPorts>
<ServersList>
<RServer prefix="4D.49.47.55.45.4c.5f.42.41.52.52.4f" />
</ServersList>
</server>
</servers>
<clients>
<client name="client1" profile_name="UDP client" server="4D.49.47.55.45.4c.5f.42.41.52.52.4f"/>
<client name="client2" profile_name="UDP client" server="4D.49.47.55.45.4c.7e.42.41.52.52.4f" />
<client name="client3" profile_name="UDP client" server="4D.49.47.55.45.4c.7e.42.41.52.52.4f" />
<client name="client4" profile_name="UDP client" server="4D.49.47.55.45.4c.7e.42.41.52.52.4f" />
</clients>
<snapshots>
<snapshot time="3">Check all clients known each other</snapshot>
</snapshots>These tests introduce dummy publishers and subscribers to assess proper EDP discovery operation over UDP and TCP transport. A server and two clients are created, and each participant (server included) creates publishers and subscribers with different types and topics. In the end, a snapshot is taken to verify all publishers and subscribers have been reported by all participants. Note that the tags publisher and subscriber have attributes to supersede topics specified in profiles.
<servers>
<server name="server" profile_name="UDP server">
<subscriber topic="topic 1" />
<publisher topic="topic 2" />
</server>
</servers>
<clients>
<client name="client1" profile_name="UDP client">
<subscriber /> <!-- defaults to helloworld type -->
<subscriber topic="topic 2" />
<subscriber profile_name="Sub 1" />
<publisher profile_name="Pub 2" />
</client>
<client name="client2" profile_name="UDP client">
<publisher /> <!-- defaults to helloworld type -->
<publisher topic="topic 1" />
<publisher profile_name="Pub 1" />
<subscriber profile_name="Sub 2" />
</client>
</clients>
<snapshots>
<snapshot time="3">Check all publishers and subscribers are properly discovered by everybody</snapshot>
</snapshots>Snapshots with EDP information are more verbose:
2020-04-24 17:20:46.820 [DISCOVERY_SERVER Info] Snapshot taken at 2020-04-24 17:20:46.816 or 3014 ms since process startup. Description: Check all publishers and subscribers are properly discovered by everybody
Snapshot process startup at 2020-04-24 17:20:43.801
Last PDP callback at 2020-04-24 17:20:44.548 or 746 ms since process startup.
Last EDP callback at 2020-04-24 17:20:45.030 or 1229 ms since process startup.
3 participants report the following discovery info:
Participant 1.f.26.69.58.1f.0.0.2.0.0.0|0.0.1.c1 discovered 3 participants, 5 publishers and 5 subscribers:
Participant 1.f.26.69.58.1f.0.0.2.0.0.0|0.0.1.c1 has:
1 publishers:
Publisher 1.f.26.69.58.1f.0.0.2.0.0.0|0.0.1.3 TypeName: sample_type_2 TopicName: topic_2
3 subscribers:
Subscriber 1.f.26.69.58.1f.0.0.2.0.0.0|0.0.2.4 TypeName: HelloWorld TopicName: HelloWorldTopicliveliness, alive_count: 0 not_alive_count: 0
Subscriber 1.f.26.69.58.1f.0.0.2.0.0.0|0.0.3.4 TypeName: sample_type_2 TopicName: topic_2liveliness, alive_count: 0 not_alive_count: 0
Subscriber 1.f.26.69.58.1f.0.0.2.0.0.0|0.0.4.4 TypeName: sample_type_1 TopicName: topic_1liveliness, alive_count: 0 not_alive_count: 0
Participant client2 1.f.26.69.58.1f.0.0.3.0.0.0|0.0.1.c1 has:
3 publishers:
Publisher 1.f.26.69.58.1f.0.0.3.0.0.0|0.0.1.3 TypeName: HelloWorld TopicName: HelloWorldTopic
Publisher 1.f.26.69.58.1f.0.0.3.0.0.0|0.0.2.3 TypeName: sample_type_1 TopicName: topic_1
Publisher 1.f.26.69.58.1f.0.0.3.0.0.0|0.0.3.3 TypeName: sample_type_1 TopicName: topic_1
1 subscribers:
Subscriber 1.f.26.69.58.1f.0.0.3.0.0.0|0.0.4.4 TypeName: sample_type_2 TopicName: topic_2liveliness, alive_count: 0 not_alive_count: 0
Participant server 4d.49.47.55.45.4c.5f.42.41.52.52.4f|0.0.1.c1 has:
1 publishers:
Publisher 4d.49.47.55.45.4c.5f.42.41.52.52.4f|0.0.1.3 TypeName: sample_type_2 TopicName: topic_2
1 subscribers:
Subscriber 4d.49.47.55.45.4c.5f.42.41.52.52.4f|0.0.2.4 TypeName: sample_type_1 TopicName: topic_1liveliness, alive_count: 0 not_alive_count: 0
Participant 1.f.26.69.58.1f.0.0.3.0.0.0|0.0.1.c1 discovered 3 participants, 5 publishers and 5 subscribers:
Participant client1 1.f.26.69.58.1f.0.0.2.0.0.0|0.0.1.c1 has:
1 publishers:
Publisher 1.f.26.69.58.1f.0.0.2.0.0.0|0.0.1.3 TypeName: sample_type_2 TopicName: topic_2
3 subscribers:
Subscriber 1.f.26.69.58.1f.0.0.2.0.0.0|0.0.2.4 TypeName: HelloWorld TopicName: HelloWorldTopicliveliness, alive_count: 0 not_alive_count: 0
Subscriber 1.f.26.69.58.1f.0.0.2.0.0.0|0.0.3.4 TypeName: sample_type_2 TopicName: topic_2liveliness, alive_count: 0 not_alive_count: 0
Subscriber 1.f.26.69.58.1f.0.0.2.0.0.0|0.0.4.4 TypeName: sample_type_1 TopicName: topic_1liveliness, alive_count: 0 not_alive_count: 0
Participant 1.f.26.69.58.1f.0.0.3.0.0.0|0.0.1.c1 has:
3 publishers:
Publisher 1.f.26.69.58.1f.0.0.3.0.0.0|0.0.1.3 TypeName: HelloWorld TopicName: HelloWorldTopic
Publisher 1.f.26.69.58.1f.0.0.3.0.0.0|0.0.2.3 TypeName: sample_type_1 TopicName: topic_1
Publisher 1.f.26.69.58.1f.0.0.3.0.0.0|0.0.3.3 TypeName: sample_type_1 TopicName: topic_1
1 subscribers:
Subscriber 1.f.26.69.58.1f.0.0.3.0.0.0|0.0.4.4 TypeName: sample_type_2 TopicName: topic_2liveliness, alive_count: 0 not_alive_count: 0
Participant server 4d.49.47.55.45.4c.5f.42.41.52.52.4f|0.0.1.c1 has:
1 publishers:
Publisher 4d.49.47.55.45.4c.5f.42.41.52.52.4f|0.0.1.3 TypeName: sample_type_2 TopicName: topic_2
1 subscribers:
Subscriber 4d.49.47.55.45.4c.5f.42.41.52.52.4f|0.0.2.4 TypeName: sample_type_1 TopicName: topic_1liveliness, alive_count: 0 not_alive_count: 0
Participant 4d.49.47.55.45.4c.5f.42.41.52.52.4f|0.0.1.c1 discovered 3 participants, 5 publishers and 5 subscribers:
Participant client1 1.f.26.69.58.1f.0.0.2.0.0.0|0.0.1.c1 has:
1 publishers:
Publisher 1.f.26.69.58.1f.0.0.2.0.0.0|0.0.1.3 TypeName: sample_type_2 TopicName: topic_2
3 subscribers:
Subscriber 1.f.26.69.58.1f.0.0.2.0.0.0|0.0.2.4 TypeName: HelloWorld TopicName: HelloWorldTopicliveliness, alive_count: 0 not_alive_count: 0
Subscriber 1.f.26.69.58.1f.0.0.2.0.0.0|0.0.3.4 TypeName: sample_type_2 TopicName: topic_2liveliness, alive_count: 0 not_alive_count: 0
Subscriber 1.f.26.69.58.1f.0.0.2.0.0.0|0.0.4.4 TypeName: sample_type_1 TopicName: topic_1liveliness, alive_count: 0 not_alive_count: 0
Participant client2 1.f.26.69.58.1f.0.0.3.0.0.0|0.0.1.c1 has:
3 publishers:
Publisher 1.f.26.69.58.1f.0.0.3.0.0.0|0.0.1.3 TypeName: HelloWorld TopicName: HelloWorldTopic
Publisher 1.f.26.69.58.1f.0.0.3.0.0.0|0.0.2.3 TypeName: sample_type_1 TopicName: topic_1
Publisher 1.f.26.69.58.1f.0.0.3.0.0.0|0.0.3.3 TypeName: sample_type_1 TopicName: topic_1
1 subscribers:
Subscriber 1.f.26.69.58.1f.0.0.3.0.0.0|0.0.4.4 TypeName: sample_type_2 TopicName: topic_2liveliness, alive_count: 0 not_alive_count: 0
Participant 4d.49.47.55.45.4c.5f.42.41.52.52.4f|0.0.1.c1 has:
1 publishers:
Publisher 4d.49.47.55.45.4c.5f.42.41.52.52.4f|0.0.1.3 TypeName: sample_type_2 TopicName: topic_2
1 subscribers:
Subscriber 4d.49.47.55.45.4c.5f.42.41.52.52.4f|0.0.2.4 TypeName: sample_type_1 TopicName: topic_1liveliness, alive_count: 0 not_alive_count: 0
-> Function eprosima::discovery_server::DSManager::validateAllSnapshots
Here we test how the discovery handles EDP late joiners. It's the same scenario with a server and two clients with different lifespans. Each participant (server included) creates publishers and subscribers with different lifespans, types, and topics. Snapshots are taken whenever an endpoint is created or destroyed to assess every participant shares the same discovery info.
<servers>
<server name="server" profile_name="UDP server" creation_time="1" >
<subscriber topic="topic 1" creation_time="3" />
<publisher topic="topic 2" creation_time="5" />
</server>
</servers>
<clients>
<client name="client1" profile_name="UDP client" removal="16">
<subscriber creation_time="7" removal_time="14" /> <!-- defaults to helloworld type -->
<subscriber topic="topic 2" creation_time="7" removal_time="14" />
<subscriber profile_name="Sub 1" creation_time="7" removal_time="14" />
<publisher profile_name="Pub 2" creation_time="12" />
</client>
<client name="client2" profile_name="UDP client" creation_time="9">
<publisher creation_time="10" /> <!-- defaults to helloworld type -->
<publisher topic="topic 1" creation_time="10" />
<publisher profile_name="Pub 1" creation_time="10" />
<subscriber profile_name="Sub 2" creation_time="10" />
</client>
</clients>
<snapshots>
<snapshot time="2">Check client1 detects the server</snapshot>
<snapshot time="4">Check client1 detects server's subscriber</snapshot>
<snapshot time="6">Check client1 detects server's publisher</snapshot>
<snapshot time="8">Check server detects client1's subscribers</snapshot>
<snapshot time="11">Check server and client1 detects client2's and its entities</snapshot>
<snapshot time="13">Check everybody detects new client1's publisher</snapshot>
<snapshot time="15">Check everybody detects client1's subscribers' removal</snapshot>
<snapshot time="17">Check server and client2 detects client1 removal</snapshot>
</snapshots>Here we test how the discovery handles server shutdown and reboot. This is a clean shutdown made from the Fast-RTPS API
:code:Domain::removeParticipant. Each time the server dies it notifies this fact to all its clients which
automatically begin pinging on the server again trying to reconnect when its rebooted. Snapshots check that clients are
aware of server absence after shutdown and presence after reboot.
<servers>
<server name="server" profile_name="UDP server" removal_time="2" />
<server name="server" profile_name="UDP server" creation_time="4" removal_time="6" />
<server name="server" profile_name="UDP server" creation_time="8" removal_time="10" />
</servers>
<clients>
<client name="client1" profile_name="UDP client" />
<client name="client2" profile_name="UDP client" />
<client name="client3" profile_name="UDP client" />
<client name="client4" profile_name="UDP client" />
</clients>
<snapshots>
<snapshot time="1">Check server-clients awareness</snapshot>
<snapshot time="3">Check server demise has been reported to all clients</snapshot>
<snapshot time="5">Check server-clients awareness has been recovered</snapshot>
<snapshot time="7">Check server demise has been reported to all clients</snapshot>
<snapshot time="9">Check server-clients awareness has been recovered</snapshot>
<snapshot time="11">Check server demise has been reported to all clients</snapshot>
</snapshots>Standard lease duration mechanism no longer makes sense on the client-server architecture. Clients no longer multicast
DATA(p) messages in order to make all other clients aware of its presence as in PDP standard mechanism, thus,
this periodical messages can no longer be used to assert participant liveliness. In the client-server architecture:
- clients only track its server liveliness by sending periodical messages to them. If a server dies because of lease-duration its client must resume pinging on it in order to reconnect.
- servers track clients and linked servers liveliness by sending periodical messages to them. If a client dies the
server must propagate a
DATA(p[UD])for that client over its PDP network. This way all server's clients have a shared lease duration capability.
In order to test this a python script is used to launch two discovery-servers instances:
-
A server with several clients. These instances will take a snapshot at the beginning and another at the end.
-
A client who references the server on the first instance. This process would be killed from python between the snapshots.
The first snapshot must show how all clients (remote one included) known each other. After killing process 2 (and its client) the server must kill its proxy by lease duration time out and report it to all other clients. The second snapshot must show how all participants have removed the remote client from its discovery database.
According to the RTPS standard the WLP (Writer Liveliness Protocol) defines the required information exchange between two Participants in order to assert the liveliness of Writers contained by the Participants. This test assess this mechanism proper operation under client-server discovery. Basically two discovery-servers instances are launched:
1 - A server with several clients that create subscribers of a common topic. This instances will take an snapshot at the beginning and another at the end.
2 - A client which references the server on the first instance and creates a publisher for the common topic. This process would be killed from python between the snapshots. It's noteworthy that the lease-duration has been increased int the profiles to prevent the server from noticing that the client has disappeared.
Both snapshots must show how all clients (remote one included) known each other and the user publishers and
subscribers. Subscribers though are notified by the WLP that the crashed publisher is not responsive. By parsing the
second snapshot we are able to verify that alive_count="0" there, that is, the subscribers were duly notified.
This test assess simple discovery proper operation by creating several simple participants with several endpoints each.
These participants and its endpoints are not created simultaneously and several snapshots are taken in order to validate
that all participants share the same info at the different test stages.
The syntax resembles the client-server participants. A simples collection of simple objects.
<simples>
<simple name="simple1" removal_time="10" profile_name="OtherDomain">
<subscriber />
...
</simple>
<simple name="simple2" removal_time="10" profile_name="OtherDomain">
<subscriber />
...
</simple>
...
</simples>It's noteworthy that:
-
The builtin transport is disabled in order to add whitelisting. The whitelist allows to restrict traffic to the given interfaces. In our case to avoid polluting the network and restrict the UDP messages to localhost.
-
Domain is modified to one randomly generated on CMake generator stage. This way interference with another tests is further downgraded.
The other tests only possible collision with each other was try to reserve the very same ports on the TCP and UDP protocols. Those ports were also randomly generated on CMake generator stage over the IANA ephemeral range, thus, collision is improbable.
<transport_descriptors>
<transport_descriptor>
<transport_id>wifi_only_transport</transport_id>
<type>UDPv4</type>
<interfaceWhiteList>
<address>127.0.0.1</address>
</interfaceWhiteList>
</transport_descriptor>
</transport_descriptors>
<participant profile_name="OtherDomain">
<domainId>27</domainId>
<rtps>
<userTransports>
<transport_id>wifi_only_transport</transport_id>
</userTransports>
<useBuiltinTransports>false</useBuiltinTransports>
</rtps>
</participant>This test verifies that the discovery info is properly serialized and deserialized by a backup server. The server is created twice by running twice the test_11_BACKUP_server.xml file:
- The first time the discovery data is serialized to a backup file.
- Then this server crashes but the backup file prevails.
- The second time the discovery data is deserialized from the backup file because the leaseDuration doesn't allow the clients to detect server's demise.
By comparing the client and last server snapshot it can be verified that the server's discovery info was properly stored and retrieved.
Using the client-server discovery directly from the fast-RTPS library is possible, as shown in section Usage, but is far more convenient to use the discovery-server application, especially for testing purposes.
If the colcon deployment strategy described in section Installation was followed, the discovery-server binary can be executed as:
Linux:
[BUILD]/install/discovery-server/bin$ . ../../local_setup.bash
[BUILD]/install/discovery-server/bin$ ./discovery-server-1.0.0 config_file.xmlWindows:
[BUILD]\install\discovery-server\bin>..\..\local_setup.bat
[BUILD]\install\discovery-server\bin>discovery-server-1.0.0 config_file.xmlwhere:
- the local_setup batch sets up the environment variables for the binary execution.
- the discovery-server binary name depends on build configuration (debug introduces d postfix) an version number.
- the config_file.xml is a placeholder for any XML config file that follows the discovery-server.xsd.
Discovery-server operation is managed from an XML config file that follows the discovery-server.xsd schema located in [SOURCES]/discovery-server/resources/xsd (this is an extension of the Fast-RTPS XML schema). The discovery-server main goals are:
-
Simplify the configuration of Fast-RTPS servers. Using a Fast-RTPS participant profile for each server is tiresome, given the large number of boilerplate code to move around. New XML syntax extensions are introduced to ease this task.
-
Provide a flexible testing tool for the client-server discovery implementation. Testing the discovery involves creating a large number of participants, publishers, subscribers that use specific topics and types (static or dynamic ones) over different transports. Besides, all these entities may appear or disappear at different times, and we need to be able to check the discovery status (collective participant knowledge) at any of these times.
The outermost XML tag is DS. It admits an optional boolean attribute called user_shutdown that defaults to
true. By default, the discover-server binary runs indefinitely until the user decides to shutdown. This default
behavior is suitable for practical applications but not for testing. Test XML files use user_shutdown="false",
which grants that the discovery server is closed as soon as the test is fulfilled. The DS tag can contain the
following tags:
-
profiles is plainly the Fast-RTPS profiles. We can use them to fine-tune the server operation. The associated documentation can be found here, note the updates introduced in section Usage.
-
servers is a list of servers that the discovery-server must create and setup. Must contain at least a server tag. Each server admits the following attributes:
- name non-mandatory but advisable for debugging purposes.
- prefix server unique identifier. It's optional because it may be specified in the profile but using this attribute we can avoid generating server profiles that only differ in prefix.
- profile_name identifies the profile associated with this server is a mandatory one.
- persist specifies if the participant is a SERVER or a BACKUP.
- creation_time introduced for testing purposes specifies in seconds when a server must be created.
- removal_time introduced for testing purposes specifies in seconds when a server must be destroyed.
Each server element admits the following tags:
- ListeningPorts contains lists of locators where this server will listen for incoming client metatraffic.
- ServersList contains at least one RServer tag that references the servers this one wants to link to. RServer only has a prefix attribute. Based on this prefix the discover-server parser would search for the corresponding server locators within the config file.
- publisher introduced for testing purposes. Creates a dummy publisher characterized by profile_name, topic, creation_time, and removal_time.
- subscriber introduced for testing purposes. Creates a dummy publisher characterized by profile_name, topic, creation_time, and removal_time.
-
clients introduced for testing purposes. It's a list of dummy clients that the discovery-server must create and setup. Must contain at least a client tag. Each client admits the following attributes:
- name non-mandatory but advisable for debugging purposes.
- profile_name identifies the profile associated with this client is a mandatory one.
- server specifies the prefix of the server we want to link to. This optional attribute saves us the nuisance of creating a ServerList (only if this client references a single server). Based on this prefix the discover-server parser would search for the corresponding server locators within the config file.
- listening_port specifies a physical port where to listen for incoming traffic. This attribute is mandatory in TCP transport (client wouldn't receive other clients traffic without it). When using the TCPv4 the format is: [XXX.XXX.XXX.XXX:]XXXX where the IP address is the client's WAN address that must be specified if we want the client to be reachable from outside a local NAT.
- creation_time introduced for testing purposes specifies in seconds when a client must be created.
- removal_time introduced for testing purposes specifies in seconds when a client must be destroyed.
Each client element admits the following tags:
- ServersList contains at least one RServer tag that references the servers this one wants to link to. RServer only has a prefix attribute. Based on this prefix the discover-server parser would search for the corresponding server locators within the config file.
- publisher introduced for testing purposes. Creates a publisher characterized by profile_name, topic, creation_time and removal_time.
- subscriber introduced for testing purposes. Creates a publisher characterized by profile_name, topic, creation_time and removal_time.
-
simples introduced for testing purposes. It's a list of dummy participants using simple discovery that the discovery-server must create set up. Must contain at least a simple tag. Each simple admits the following attributes:
- name non-mandatory but advisable for debugging purposes.
- profile_name identifies the profile associated with this participant is a mandatory one.
- creation_time introduced for testing purposes specifies in seconds when a client must be created.
- removal_time introduced for testing purposes specifies in seconds when a client must be destroyed.
Each simple element admits the following tags:
- publisher introduced for testing purposes. Creates a publisher characterized by profile_name, topic, creation_time, and removal_time.
- subscriber introduced for testing purposes. Creates a publisher characterized by profile_name, topic, creation_time, and removal_time.
-
types is plainly the Fast-RTPS types. It's introduced here for testing purposes to check how topic and type discovery info is handled by EDP. The associated documentation can be found here.
-
snapshots contains snapshot tags. Whenever a discovery-server creates a participant (client or a server) it becomes its listener in the sense that all discovery info received by the participant is relayed to him. This reported discovery info is stored in a database. A snapshot is a commit of this database in a given time point. The snapshots element has a file attribute that must be filled with the filename of the XML results file if immediate validation is not desired.
Snapshots are useful because within is recorded how much information each participant is aware of. If a participant reported no info or incomplete one there is a discovery failure. When the discovery server has finished processing the config file (creating and destroying entities or taking snapshots) then all snapshots taken are checked. If any of them shows discovery info leakages discovery server returns -1 and the unsuccessful snapshot is logged to the standard error. Note:
- this validation can be avoided using the file attribute of the snapshots collection.
- there is a particular case that requires special treatment by using snapshot's attribute someone. By default someone is true and no discovery info reported by any participant is regarded as a failure, yet in some tests, we want to validate the absence of discovery if settings are wrong so someone may be set false then.
snapshot tag has a single mandatory attribute time which specifies when the snapshot must be taken and an optional someone whose functionality is explained above. The text content of the tag is regarded as a description where the user can specify which event may require validation (participant creation or removal, etc...).
The tests are probably the best examples of the above XML definitions put into practice.
If you need support you can reach us by mail at support@eProsima.com or by phone at +34 91 804 34 48.
