Skip to content

Commit

Permalink
TCP support for Discovery server CLI and env var and example (#599)
Browse files Browse the repository at this point in the history
* Refs #20021: CLI update with TCP support

Signed-off-by: cferreiragonz <carlosferreira@eprosima.com>

* Refs #20021: TCP support for env. variable

Signed-off-by: cferreiragonz <carlosferreira@eprosima.com>

* Refs #20021: New TCP w/ Disc.Server example

Signed-off-by: cferreiragonz <carlosferreira@eprosima.com>

* Refs #20021:update use of DNS with IPv6

Signed-off-by: cferreiragonz <carlosferreira@eprosima.com>

* Refs #20021: fix XML example

Signed-off-by: cferreiragonz <carlosferreira@eprosima.com>

* Refs #20021: correct tests

Signed-off-by: cferreiragonz <carlosferreira@eprosima.com>

* Refs #20021: Apply Revision's changes

Signed-off-by: cferreiragonz <carlosferreira@eprosima.com>

* Refs #20021: Update use case and CLI

Signed-off-by: cferreiragonz <carlosferreira@eprosima.com>

---------

Signed-off-by: cferreiragonz <carlosferreira@eprosima.com>
  • Loading branch information
cferreiragonz committed Dec 14, 2023
1 parent ee4c9b0 commit 194bd18
Show file tree
Hide file tree
Showing 6 changed files with 365 additions and 18 deletions.
56 changes: 56 additions & 0 deletions code/DDSCodeTester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6080,6 +6080,62 @@ void tcp_use_cases()
eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->create_participant(0, pqos);
//!
}

{
//TCP-AND-DISCOVERY-SERVER-SERVER
eprosima::fastdds::dds::DomainParticipantQos qos = PARTICIPANT_QOS_DEFAULT;

// Configure the current participant as SERVER
qos.wire_protocol().builtin.discovery_config.discoveryProtocol = eprosima::fastrtps::rtps::DiscoveryProtocol_t::SERVER;

// Add custom user transport with TCP port 12345
auto data_transport = std::make_shared<eprosima::fastdds::rtps::TCPv4TransportDescriptor>();
data_transport->add_listener_port(12345);
qos.transport().user_transports.push_back(data_transport);

// Define the listening locator to be on interface 192.168.10.57 and port 12345
constexpr uint16_t tcp_listening_port = 12345;
eprosima::fastrtps::rtps::Locator_t listening_locator;
eprosima::fastrtps::rtps::IPLocator::setIPv4(listening_locator, "192.168.10.57");
eprosima::fastrtps::rtps::IPLocator::setPhysicalPort(listening_locator, tcp_listening_port);
eprosima::fastrtps::rtps::IPLocator::setLogicalPort(listening_locator, tcp_listening_port);
qos.wire_protocol().builtin.metatrafficUnicastLocatorList.push_back(listening_locator);

// Set the GUID prefix to identify this server
std::istringstream("44.53.00.5f.45.50.52.4f.53.49.4d.41") >> qos.wire_protocol().prefix;
//!--
}

{
//TCP-AND-DISCOVERY-SERVER-CLIENT
eprosima::fastdds::dds::DomainParticipantQos qos = PARTICIPANT_QOS_DEFAULT;

// Configure the current participant as SERVER
qos.wire_protocol().builtin.discovery_config.discoveryProtocol = eprosima::fastrtps::rtps::DiscoveryProtocol_t::CLIENT;

// Add custom user transport with TCP port 0 (automatic port assignation)
auto data_transport = std::make_shared<eprosima::fastdds::rtps::TCPv4TransportDescriptor>();
data_transport->add_listener_port(0);
qos.transport().user_transports.push_back(data_transport);

// Define the server locator to be on interface 192.168.10.57 and port 12345
constexpr uint16_t server_port = 12345;
eprosima::fastrtps::rtps::Locator_t server_locator;
eprosima::fastrtps::rtps::IPLocator::setIPv4(server_locator, "192.168.10.57");
eprosima::fastrtps::rtps::IPLocator::setPhysicalPort(server_locator, server_port);
eprosima::fastrtps::rtps::IPLocator::setLogicalPort(server_locator, server_port);

// Define the server attributes
eprosima::fastrtps::rtps::RemoteServerAttributes remote_server_att;
remote_server_att.metatrafficUnicastLocatorList.push_back(server_locator);

// Set the GUID prefix to identify this server
std::istringstream("44.53.00.5f.45.50.52.4f.53.49.4d.41") >> remote_server_att.guidPrefix;

// Add the server
qos.wire_protocol().builtin.discovery_config.m_DiscoveryServers.push_back(remote_server_att);
//!--
}
}

bool dds_permissions_test(
Expand Down
103 changes: 103 additions & 0 deletions code/XMLTester.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3787,6 +3787,109 @@
</dds>
-->
<!--><-->

<!-->TCP-AND-DISCOVERY-SERVER-SERVER<-->
<!--
<?xml version="1.0" encoding="UTF-8" ?>
<dds xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles">
<profiles>
-->
<transport_descriptors>
<transport_descriptor>
<transport_id>server_tcp_transport</transport_id>
<type>TCPv4</type>
<!--
Set listening port for the transport.
This port is where the clients will connect.
-->
<listening_ports>
<port>12345</port>
</listening_ports>
</transport_descriptor>
</transport_descriptors>
<participant profile_name="TCP_SERVER" is_default_profile="true">
<rtps>
<builtin>
<discovery_config>
<discoveryProtocol>SERVER</discoveryProtocol>
</discovery_config>
<metatrafficUnicastLocatorList>
<locator>
<tcpv4>
<address>192.168.10.57</address>
<port>12345</port>
<physical_port>12345</physical_port>
</tcpv4>
</locator>
</metatrafficUnicastLocatorList>
</builtin>
<prefix>44.53.00.5f.45.50.52.4f.53.49.4d.41</prefix>
<useBuiltinTransports>false</useBuiltinTransports>
<userTransports>
<transport_id>server_tcp_transport</transport_id>
</userTransports>
</rtps>
</participant>
<!--
</profiles>
</dds>
-->
<!--><-->

<!-->TCP-AND-DISCOVERY-SERVER-CLIENT<-->
<!--
<?xml version="1.0" encoding="UTF-8" ?>
<dds xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles">
<profiles>
-->
<transport_descriptors>
<transport_descriptor>
<transport_id>client_tcp_transport</transport_id>
<type>TCPv4</type>
<!--
Set listening port for the transport to 0.
This automatically assigns a port.
-->
<listening_ports>
<port>0</port>
</listening_ports>
</transport_descriptor>
</transport_descriptors>
<participant profile_name="TCP_CLIENT" is_default_profile="true">
<rtps>
<builtin>
<discovery_config>
<discoveryProtocol>CLIENT</discoveryProtocol>
<discoveryServersList>
<RemoteServer prefix="44.53.00.5f.45.50.52.4f.53.49.4d.41">
<!--
Server locator specifying where it is listening
-->
<metatrafficUnicastLocatorList>
<locator>
<tcpv4>
<address>192.168.10.57</address>
<port>12345</port>
<physical_port>12345</physical_port>
</tcpv4>
</locator>
</metatrafficUnicastLocatorList>
</RemoteServer>
</discoveryServersList>
</discovery_config>
</builtin>
<useBuiltinTransports>false</useBuiltinTransports>
<userTransports>
<transport_id>client_tcp_transport</transport_id>
</userTransports>
</rtps>
</participant>
<!--
</profiles>
</dds>
-->
<!--><-->

</profiles>

<!-->CONF-LIBRARY-SETTINGS<-->
Expand Down
36 changes: 25 additions & 11 deletions docs/fastdds/env_vars/env_vars.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,31 +68,44 @@ For more information about XML profiles, please refer to :ref:`xml_profiles`.
Setting this variable configures the :ref:`DomainParticipant<dds_layer_domainParticipant>` to connect to one or more
*servers* using the :ref:`Discovery Server<discovery_server>` discovery mechanism.

* If ``ROS_DISCOVERY_SERVER`` is defined, and the ``DomainParticipant``'s :ref:`discovery protocol<discovery_protocol>`,
* If ``ROS_DISCOVERY_SERVER`` is defined, and the ``DomainParticipant``'s :ref:`discovery protocol<discovery_protocol>`
is set to |SIMPLE|, then Fast DDS will instead configure it as |CLIENT| of the given *server*.
* If ``ROS_DISCOVERY_SERVER`` is defined, and the ``DomainParticipant``'s :ref:`discovery protocol<discovery_protocol>`
is |SERVER| or |BACKUP|, then the variable is used to add remote *servers* to the given *server*, leaving the
is set to |SERVER| or |BACKUP|, then the variable is used to add remote *servers* to the given *server*, leaving the
:ref:`discovery protocol<discovery_protocol>` as |SERVER| or |BACKUP| respectively.

* The value of the variable must list the locator of the server in the form of:

+ An IPv4 address like ``192.168.2.23``. The UDP port can be appended using `:` as in ``192.168.2.23:35665``.
+ An IPv6 address that follows RFC3513_ address convention like ``1080::8:800:200C:417A``. Again a UDP port can be
appended like in ``[1080::8:800:200C:417A]:35665``. Note the use of square brackets to avoid ambiguities.
+ An IPv4 address like ``192.168.2.23``. The UDP protocol is used by default. The UDP port can be appended using `:`
as in ``192.168.2.23:35665``.
+ An IPv6 address that follows RFC3513_ address convention like ``1080::8:800:200C:417A``. Again, it uses the UDP
protocol by default. An UDP port can be appended like in ``[1080::8:800:200C:417A]:35665``. Note the use of square
brackets to avoid ambiguities.
+ TCPv4 specifier + IPv4 address like ``TCPv4:[127.0.0.1]``. The TCP protocol is used to communicate with the server.
The TCP port can be appended using `:` as in ``TCPv4:[127.0.0.1]:42100``.
+ TCPv6 specifier + IPv6 address like ``TCPv6:[::1]``. The TCP protocol is used to communicate with the server. The
TCP port can be appended using `:` as in ``TCPv6:[::1]:42100``.
+ A DNS name can be specified. This name will be used to query known hosts and available DNS servers to try to
resolve valid IP addresses. Several formats are acceptable:

- Plain domain name: ``eprosima.com``. This will include all available IP addresses.
- Domain name + port: ``eprosima.com:35665``. As above but using a specific port.
- UDPv4 specifier + domain name: ``UDPv4:[eprosima.com]``. Only the first IPv4 address resolved will be used.
- UDPv4 specifier + domain name + port: ``UDPv4:[eprosima.com]:35665``. As above but using a specific port.
- UDPv6 specifier + domain name: ``UDPv6:[eprosima.com]``. Only the first IPv6 address resolved will be used.
- UDPv6 specifier + domain name + port: ``UDPv6:[eprosima.com]:35665``. As above but using a specific port.

* If no port is specified, the default port 11811 is used.
- UDPv6 specifier + domain name: ``UDPv6:[<dns>]``. Only the first IPv6 address resolved will be used.
- UDPv6 specifier + domain name + port: ``UDPv6:[<dns>]:35665``. As above but using a specific port.
- TCPv4 specifier + domain name: ``TCPv4:[eprosima.com]``. Only the first IPv4 address resolver will be used.
- TCPv4 specifier + domain name + port: ``TCPv4:[eprosima.com]:42100``. As above but using a specific port.
- TCPv6 specifier + domain name: ``TCPv6:[<dns>]``. Only the first IPv4 address resolver will be used.
- TCPv6 specifier + domain name + port: ``TCPv6:[<dns>]:42100``. As above but using a specific port.

* If no port is specified when using default UDP transport, the default port 11811 is used.
* If no port is specified when using TCP transport, the default port 42100 is used.
* To set more than one *server*'s address, they must be separated by semicolons.
* The server's ID is determined by their position in the list.
Two semicolons together means the corresponding ID is free.
* When using IPv6 with DNS, the specified domain name space (*<dns>*) must be able to resolve to an IPv6
address. Otherwise an error will be raised.

The following example shows how to set the address of two remote discovery servers with addresses
'84.22.259.329:8888' and 'localhost:1234' and IDs 0 and 2 respectively.
Expand All @@ -113,8 +126,9 @@ The following example shows how to set the address of two remote discovery serve

.. important::
IP addresses specified in ``ROS_DISCOVERY_SERVER`` must be either valid IPv4/IPv6 addresses or domain names.
If a name can be resolved into several addresses it is possible to either use them all or restrict the selection to
the first IPv4 or IPv6 address using the `UDPv4:` and `UDPv6:` prefixes respectively.
If a name can be resolved into several addresses, it is possible to either use them all or restrict the selection to
the first IPv4 using the `UDPv4:` or `TCPv4` prefixes or to the first IPv6 address using the `UDPv6:` or `TCPv6`
prefixes.

.. important::
This environment variable is meant to be used in combination with :ref:`Fast DDS discovery CLI<cli_discovery>`.
Expand Down
8 changes: 5 additions & 3 deletions docs/fastdds/use_cases/tcp/tcp_use_case.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ links.
The configuration of the TCP transport typically involves an *a priori* knowledge of the deployment in order
to set :ref:`Simple Initial Peers` for :ref:`discovery`, which may not always be possible and creates difficulties when
reallocating nodes of the distributed applications, as the entire discovery configuration needs to be changed.
To overcome this problem, this use case presents an approach for leveraging the Fast DDS' TCP transport capabilities
To overcome this problem, these use cases present an approach for leveraging the Fast DDS' TCP transport capabilities
while at the same time not requiring configuration modifications when the deployment changes over time.
It does so by configuring the participant discovery phase (see :ref:`disc_phases`) to occur over UDP multicast, while
the application data delivery occurs over TCP.
One option is to configure the participant discovery phase (see :ref:`disc_phases`) to occur over UDP multicast, while
the application data delivery occurs over TCP. Also, it is possible to enable TCP communication while using
:ref:`discovery-server-use-case` to manage :ref:`discovery`.

.. toctree::
:maxdepth: 2

/fastdds/use_cases/tcp/tcp_with_multicast_discovery.rst
/fastdds/use_cases/tcp/tcp_with_discovery_server.rst
98 changes: 98 additions & 0 deletions docs/fastdds/use_cases/tcp/tcp_with_discovery_server.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
.. include:: ../../../03-exports/aliases.include
.. include:: ../../../03-exports/aliases-api.include

.. _use-case-tcp-discovery-server:

TCP Communication with Discovery Server
==========================================

*Fast DDS* :ref:`discovery-server-use-case` consists on a client-server discovery mechanism, in which a server
|DomainParticipant| operates as the central point of communication. It collects and processes the metatraffic
sent by the client DomainParticipants, and then distributes the appropriate information among the rest of
the clients. An extended description of the feature can be found at :ref:`discovery_server`.

To use TCP communication along with Discovery Server, both the server participant and the client participant
need to use custom user transports. There exists several ways of configuring the server participant, being
*Fast DDS* :ref:`ffastddscli_cli` the fastest solution:

.. tabs::

.. tab:: Fast DDS CLI

It can be configured to work over a TCP transport layer by using the arguments ``-t`` and ``-q`` to set
up the IP address and the TCP port, respectively. After sourcing the environment, the following command
can be used to instantiate a server listening on localhost and port 12345 (see :ref:`ffastddscli_cli`).

.. code-block:: bash
fastdds discovery -i 0 -t 127.0.0.1 -q 12345
.. tab:: C++

The following snippet can be used to instantiate a server on IP 192.168.10.57 listening on port 12345.

.. literalinclude:: ../../../../code/DDSCodeTester.cpp
:language: c++
:dedent: 8
:start-after: //TCP-AND-DISCOVERY-SERVER-SERVER
:end-before: //!

.. tab:: XML

The following snippet can be used to instantiate a server on IP 192.168.10.57 listening on port 12345.

.. literalinclude:: /../code/XMLTester.xml
:language: xml
:start-after: <!-->TCP-AND-DISCOVERY-SERVER-SERVER<-->
:end-before: <!--><-->
:lines: 2-4, 6-41, 43-44

.. tab:: Fast DDS Discovery Server Example

It can be configured to work over a TCP transport layer by using the argument ``--transport tcpv4``. The IP
address and the TCP port can be set up with arguments ``--listening-address`` and ``--listening-port``,
respectively. From the *DiscoveryServerExample* folder, the following command can be used to instantiate a
server listening on localhost and port 12345.

.. code-block:: bash
./DiscoveryServerExample server --transport tcpv4 --listening-address 127.0.0.1 --listening-port 12345
The client participant can be configured by either using the ``ROS_DISCOVERY_SERVER`` environment variable (see
:ref:`env_vars_ros_discovery_server`) or by manually setting it.

.. tabs::

.. tab:: Environment Variable

To configure a client participant to communicate over the TCP transport layer with the
``ROS_DISCOVERY_SERVER`` environment variable, the prefix `TCPv4` needs to be used. The following command
can be used to configure the variable to set up a client using TCP communication and connecting to a
server on localhost and port 12345.

.. code-block:: bash
export ROS_DISCOVERY_SERVER=TCPv4:[127.0.0.1]:12345
.. tab:: C++

The following snippet can be used to instantiate a client that will try to connect to a server on IP
192.168.10.57 and port 12345, that is, the server instantiated above.

.. literalinclude:: ../../../../code/DDSCodeTester.cpp
:language: c++
:dedent: 8
:start-after: //TCP-AND-DISCOVERY-SERVER-CLIENT
:end-before: //!

.. tab:: XML

The following snippet can be used to instantiate a client that will try to connect to a server on IP
192.168.10.57 and port 12345, that is, the server instantiated above.

.. literalinclude:: /../code/XMLTester.xml
:language: xml
:start-after: <!-->TCP-AND-DISCOVERY-SERVER-CLIENT<-->
:end-before: <!--><-->
:lines: 2-4, 6-47, 49-50

0 comments on commit 194bd18

Please sign in to comment.