diff --git a/examples/cpp/dds/DiscoveryServerExample/DiscoveryServerPublisher.cpp b/examples/cpp/dds/DiscoveryServerExample/DiscoveryServerPublisher.cpp index dc049a7acc..32c6770f1a 100644 --- a/examples/cpp/dds/DiscoveryServerExample/DiscoveryServerPublisher.cpp +++ b/examples/cpp/dds/DiscoveryServerExample/DiscoveryServerPublisher.cpp @@ -120,6 +120,34 @@ bool HelloWorldPublisher::init( break; } + case TransportKind::TCPv4: + { + auto descriptor_tmp = std::make_shared(); + // descriptor_tmp->interfaceWhiteList.push_back(ip_server_address); + // One listening port must be added either in the pub or the sub + descriptor_tmp->add_listener_port(0); + descriptor = descriptor_tmp; + + server_locator.kind = LOCATOR_KIND_TCPv4; + eprosima::fastrtps::rtps::IPLocator::setLogicalPort(server_locator, server_port); + eprosima::fastrtps::rtps::IPLocator::setIPv4(server_locator, ip_server_address); + break; + } + + case TransportKind::TCPv6: + { + auto descriptor_tmp = std::make_shared(); + // descriptor_tmp->interfaceWhiteList.push_back(ip_server_address); + // One listening port must be added either in the pub or the sub + descriptor_tmp->add_listener_port(0); + descriptor = descriptor_tmp; + + server_locator.kind = LOCATOR_KIND_TCPv6; + eprosima::fastrtps::rtps::IPLocator::setLogicalPort(server_locator, server_port); + eprosima::fastrtps::rtps::IPLocator::setIPv6(server_locator, ip_server_address); + break; + } + default: break; } diff --git a/examples/cpp/dds/DiscoveryServerExample/DiscoveryServerServer.cpp b/examples/cpp/dds/DiscoveryServerExample/DiscoveryServerServer.cpp index 8f9ee30c84..8a5099320a 100644 --- a/examples/cpp/dds/DiscoveryServerExample/DiscoveryServerServer.cpp +++ b/examples/cpp/dds/DiscoveryServerExample/DiscoveryServerServer.cpp @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include "DiscoveryServerServer.h" @@ -136,6 +138,38 @@ bool DiscoveryServer::init( break; } + case TransportKind::TCPv4: + { + auto descriptor_tmp = std::make_shared(); + // descriptor_tmp->interfaceWhiteList.push_back(ip_listening_address); + descriptor_tmp->add_listener_port(server_port); + descriptor = descriptor_tmp; + + listening_locator.kind = LOCATOR_KIND_TCPv4; + eprosima::fastrtps::rtps::IPLocator::setLogicalPort(listening_locator, server_port); + eprosima::fastrtps::rtps::IPLocator::setIPv4(listening_locator, ip_listening_address); + connection_locator.kind = LOCATOR_KIND_TCPv4; + eprosima::fastrtps::rtps::IPLocator::setIPv4(connection_locator, ip_connection_address); + eprosima::fastrtps::rtps::IPLocator::setLogicalPort(connection_locator, connection_server_port); + break; + } + + case TransportKind::TCPv6: + { + auto descriptor_tmp = std::make_shared(); + // descriptor_tmp->interfaceWhiteList.push_back(ip_listening_address); + descriptor_tmp->add_listener_port(server_port); + descriptor = descriptor_tmp; + + listening_locator.kind = LOCATOR_KIND_TCPv6; + eprosima::fastrtps::rtps::IPLocator::setLogicalPort(listening_locator, server_port); + eprosima::fastrtps::rtps::IPLocator::setIPv6(listening_locator, ip_listening_address); + connection_locator.kind = LOCATOR_KIND_TCPv6; + eprosima::fastrtps::rtps::IPLocator::setIPv6(connection_locator, ip_connection_address); + eprosima::fastrtps::rtps::IPLocator::setLogicalPort(connection_locator, connection_server_port); + break; + } + default: break; } diff --git a/examples/cpp/dds/DiscoveryServerExample/DiscoveryServerSubscriber.cpp b/examples/cpp/dds/DiscoveryServerExample/DiscoveryServerSubscriber.cpp index 0a49a74a94..9051bac5b5 100644 --- a/examples/cpp/dds/DiscoveryServerExample/DiscoveryServerSubscriber.cpp +++ b/examples/cpp/dds/DiscoveryServerExample/DiscoveryServerSubscriber.cpp @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include #include @@ -121,6 +123,34 @@ bool HelloWorldSubscriber::init( break; } + case TransportKind::TCPv4: + { + auto descriptor_tmp = std::make_shared(); + // descriptor_tmp->interfaceWhiteList.push_back(ip_server_address); + // One listening port must be added either in the pub or the sub + descriptor_tmp->add_listener_port(0); + descriptor = descriptor_tmp; + + server_locator.kind = LOCATOR_KIND_TCPv4; + eprosima::fastrtps::rtps::IPLocator::setLogicalPort(server_locator, server_port); + eprosima::fastrtps::rtps::IPLocator::setIPv4(server_locator, ip_server_address); + break; + } + + case TransportKind::TCPv6: + { + auto descriptor_tmp = std::make_shared(); + // descriptor_tmp->interfaceWhiteList.push_back(ip_server_address); + // One listening port must be added either in the pub or the sub + descriptor_tmp->add_listener_port(0); + descriptor = descriptor_tmp; + + server_locator.kind = LOCATOR_KIND_TCPv6; + eprosima::fastrtps::rtps::IPLocator::setLogicalPort(server_locator, server_port); + eprosima::fastrtps::rtps::IPLocator::setIPv4(server_locator, ip_server_address); + break; + } + default: break; } diff --git a/examples/cpp/dds/DiscoveryServerExample/DiscoveryServer_main.cpp b/examples/cpp/dds/DiscoveryServerExample/DiscoveryServer_main.cpp index df6b2324b7..c796692e05 100644 --- a/examples/cpp/dds/DiscoveryServerExample/DiscoveryServer_main.cpp +++ b/examples/cpp/dds/DiscoveryServerExample/DiscoveryServer_main.cpp @@ -173,9 +173,17 @@ int main( { transport = TransportKind::UDPv6; } + else if (transport_str == "tcpv4") + { + transport = TransportKind::TCPv4; + } + else if (transport_str == "tcpv6") + { + transport = TransportKind::TCPv6; + } else { - print_warning("udpv4|udpv6", opt.name); + print_warning("udpv4|udpv6|tcpv4|tcpv6", opt.name); } break; diff --git a/examples/cpp/dds/DiscoveryServerExample/README.md b/examples/cpp/dds/DiscoveryServerExample/README.md index df882892cb..5d3448e327 100644 --- a/examples/cpp/dds/DiscoveryServerExample/README.md +++ b/examples/cpp/dds/DiscoveryServerExample/README.md @@ -33,8 +33,8 @@ Publisher options: Server address (Default address: 127.0.0.1). -p --connection-port= Server listening port (Default port: 16166). - --transport= - Use Transport Protocol [udpv4|udpv6] (Default: udpv4). + --transport= + Use Transport Protocol [udpv4|udpv6|tcpv4|tcpv6] (Default: udpv4). -d --connection-discovery-server-id Id of the Discovery Server to connect with. GUID will be calculated from id (Default: 0). @@ -49,8 +49,8 @@ Subscriber options: Server address (Default address: 127.0.0.1). -p --connection-port= Server listening port (Default port: 16166). - --transport= - Use Transport Protocol [udpv4|udpv6] (Default: udpv4). + --transport= + Use Transport Protocol [udpv4|udpv6|tcpv4|tcpv6] (Default: udpv4). -d --connection-discovery-server-id Id of the Discovery Server to connect with. GUID will be calculated from id (Default: 0). @@ -63,8 +63,8 @@ DiscoveryServer options: GUID will be calculated from id (Default: 0). --listening-port= Server listening port (Default port: 16166). - --transport= - Use Transport Protocol [udpv4|udpv6] (Default: udpv4). + --transport= + Use Transport Protocol [udpv4|udpv6|tcpv4|tcpv6] (Default: udpv4). -c --connection-address= Server address (Default address: 127.0.0.1). -p --connection-port= diff --git a/examples/cpp/dds/DiscoveryServerExample/arg_configuration.h b/examples/cpp/dds/DiscoveryServerExample/arg_configuration.h index 50c349391c..29f1acdd40 100644 --- a/examples/cpp/dds/DiscoveryServerExample/arg_configuration.h +++ b/examples/cpp/dds/DiscoveryServerExample/arg_configuration.h @@ -140,7 +140,9 @@ struct Arg : public option::Arg if ( // transport == "shm" || transport == "udpv4" || - transport == "udpv6" + transport == "udpv6" || + transport == "tcpv4" || + transport == "tcpv6" ) { return option::ARG_OK; @@ -235,7 +237,7 @@ const option::Descriptor usage[] = { "", "transport", Arg::Transport, - " \t--transport \tUse Transport Protocol [udpv4|udpv6] (UDPv4 by default)." + " \t--transport \tUse Transport Protocol [udpv4|udpv6|tcpv4|tcpv6] (UDPv4 by default)." }, { CONNECTION_DISCOVERY_SERVER_ID, @@ -287,7 +289,7 @@ const option::Descriptor usage[] = { "", "transport", Arg::Transport, - " \t--transport \tUse Transport Protocol [udpv4|udpv6] (UDPv4 by default)." + " \t--transport \tUse Transport Protocol [udpv4|udpv6|tcpv4|tcpv6] (UDPv4 by default)." }, { CONNECTION_DISCOVERY_SERVER_ID, @@ -331,7 +333,7 @@ const option::Descriptor usage[] = { "", "transport", Arg::Transport, - " \t--transport \tUse Transport Protocol [udpv4|udpv6] (UDPv4 by default)." + " \t--transport \tUse Transport Protocol [udpv4|udpv6|tcpv4|tcpv6] (UDPv4 by default)." }, { CONNECTION_PORT, diff --git a/examples/cpp/dds/DiscoveryServerExample/common.h b/examples/cpp/dds/DiscoveryServerExample/common.h index 137197dd71..5ef51a62ff 100644 --- a/examples/cpp/dds/DiscoveryServerExample/common.h +++ b/examples/cpp/dds/DiscoveryServerExample/common.h @@ -27,6 +27,8 @@ enum class TransportKind { UDPv4, UDPv6, + TCPv4, + TCPv6, SHM, }; @@ -56,7 +58,7 @@ inline std::string get_ip_from_dns( std::pair, std::set> dns_response = eprosima::fastrtps::rtps::IPLocator::resolveNameDNS(domain_name); - if (kind == TransportKind::UDPv4) + if (kind == TransportKind::UDPv4 || kind == TransportKind::TCPv4) { if (dns_response.first.empty()) { @@ -70,7 +72,7 @@ inline std::string get_ip_from_dns( return solution; } } - else if (kind == TransportKind::UDPv6) + else if (kind == TransportKind::UDPv6 || kind == TransportKind::TCPv6) { if (dns_response.second.empty()) { diff --git a/include/fastdds/rtps/attributes/ServerAttributes.h b/include/fastdds/rtps/attributes/ServerAttributes.h index 0f1c42144d..c8fb9cd9ed 100644 --- a/include/fastdds/rtps/attributes/ServerAttributes.h +++ b/include/fastdds/rtps/attributes/ServerAttributes.h @@ -159,10 +159,12 @@ std::basic_ostream& operator <<( return output; } -// port use if the ros environment variable doesn't specified one +// port used if the ros environment variable doesn't specify one constexpr uint16_t DEFAULT_ROS2_SERVER_PORT = 11811; // default server base guidPrefix const char* const DEFAULT_ROS2_SERVER_GUIDPREFIX = "44.53.00.5f.45.50.52.4f.53.49.4d.41"; +// port used by default for tcp transport +constexpr uint16_t DEFAULT_TCP_SERVER_PORT = 42100; /* Environment variable to specify a semicolon-separated list of UDPv4 locators (ip:port) that define remote server * locators. diff --git a/include/fastdds/rtps/common/Locator.h b/include/fastdds/rtps/common/Locator.h index d36df559e5..3b670d5e79 100644 --- a/include/fastdds/rtps/common/Locator.h +++ b/include/fastdds/rtps/common/Locator.h @@ -371,7 +371,15 @@ inline std::ostream& operator <<( } // Stream port - output << "]:" << loc.port; + if (loc.kind == LOCATOR_KIND_TCPv4 || loc.kind == LOCATOR_KIND_TCPv6) + { + output << "]:" << std::to_string(IPLocator::getPhysicalPort(loc)) << "-" << std::to_string(IPLocator::getLogicalPort( + loc)); + } + else + { + output << "]:" << loc.port; + } return output; } diff --git a/src/cpp/rtps/RTPSDomain.cpp b/src/cpp/rtps/RTPSDomain.cpp index 1349168833..69eec2dd6c 100644 --- a/src/cpp/rtps/RTPSDomain.cpp +++ b/src/cpp/rtps/RTPSDomain.cpp @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include @@ -544,23 +546,95 @@ RTPSParticipant* RTPSDomainImpl::clientServerEnvironmentCreationOverride( RemoteServerList_t& server_list = client_att.builtin.discovery_config.m_DiscoveryServers; if (load_environment_server_info(server_list) && server_list.empty()) { - // it's not an error, the environment variable may not be set. Any issue with environment + // It's not an error, the environment variable may not be set. Any issue with environment // variable syntax is EPROSIMA_LOG_ERROR already return nullptr; } - // check if some server requires the UDPv6 transport + // Check if some server requires the UDPv6, TCPv4 or TCPv6 transport for (auto& server : server_list) { if (server.requires_transport()) { - // extend builtin transports with the UDPv6 transport + // Extend builtin transports with the UDPv6 transport auto descriptor = std::make_shared(); descriptor->sendBufferSize = client_att.sendSocketBufferSize; descriptor->receiveBufferSize = client_att.listenSocketBufferSize; client_att.userTransports.push_back(std::move(descriptor)); break; } + if (server.requires_transport()) + { + // Check if a TCPv4 transport exists. Otherwise create it + fastdds::rtps::TCPTransportDescriptor* pT = nullptr; + std::shared_ptr p4; + bool no_tcpv4 = true; + + for (auto sp : client_att.userTransports) + { + pT = dynamic_cast(sp.get()); + + if (pT != nullptr) + { + if (!p4) + { + if ((p4 = std::dynamic_pointer_cast(sp))) + { + // TCPv4 transport already exists + no_tcpv4 = false; + break; + } + } + } + } + if (no_tcpv4) + { + // Extend builtin transports with the TCPv4 transport + auto descriptor = std::make_shared(); + // Add automatic port + descriptor->add_listener_port(0); + descriptor->sendBufferSize = client_att.sendSocketBufferSize; + descriptor->receiveBufferSize = client_att.listenSocketBufferSize; + client_att.userTransports.push_back(std::move(descriptor)); + } + + } + if (server.requires_transport()) + { + // Check if a TCPv6 transport exists. Otherwise create it + fastdds::rtps::TCPTransportDescriptor* pT = nullptr; + std::shared_ptr p6; + bool no_tcpv6 = true; + + for (auto sp : client_att.userTransports) + { + pT = dynamic_cast(sp.get()); + + if (pT != nullptr) + { + if (!p6) + { + // try to find a descriptor matching the listener port setup + if ((p6 = std::dynamic_pointer_cast(sp))) + { + // TCPv6 transport already exists + no_tcpv6 = false; + break; + } + } + } + } + if (no_tcpv6) + { + // Extend builtin transports with the TCPv6 transport + auto descriptor = std::make_shared(); + // Add automatic port + descriptor->add_listener_port(0); + descriptor->sendBufferSize = client_att.sendSocketBufferSize; + descriptor->receiveBufferSize = client_att.listenSocketBufferSize; + client_att.userTransports.push_back(std::move(descriptor)); + } + } } EPROSIMA_LOG_INFO(DOMAIN, "Detected auto client-server environment variable." @@ -579,13 +653,13 @@ RTPSParticipant* RTPSDomainImpl::clientServerEnvironmentCreationOverride( RTPSParticipant* part = createParticipant(domain_id, enabled, client_att, listen); if (nullptr != part) { - // client successfully created + // Client successfully created EPROSIMA_LOG_INFO(DOMAIN, "Auto default server-client setup. Default client created."); part->mp_impl->client_override(true); return part; } - // unable to create auto server-client default participants + // Unable to create auto server-client default participants EPROSIMA_LOG_ERROR(DOMAIN, "Auto default server-client setup. Unable to create the client."); return nullptr; } diff --git a/src/cpp/rtps/builtin/discovery/participant/PDPClient.cpp b/src/cpp/rtps/builtin/discovery/participant/PDPClient.cpp index 7900017b0f..f337372cbf 100644 --- a/src/cpp/rtps/builtin/discovery/participant/PDPClient.cpp +++ b/src/cpp/rtps/builtin/discovery/participant/PDPClient.cpp @@ -987,7 +987,11 @@ bool load_environment_server_info( const static std::regex ROS2_IPV4_ADDRESSPORT_PATTERN(R"(^((?:[0-9]{1,3}\.){3}[0-9]{1,3})?:?(?:(\d+))?$)"); const static std::regex ROS2_IPV6_ADDRESSPORT_PATTERN( R"(^\[?((?:[0-9a-fA-F]{0,4}\:){0,7}[0-9a-fA-F]{0,4})?(?:\])?:?(?:(\d+))?$)"); - const static std::regex ROS2_DNS_DOMAINPORT_PATTERN(R"(^(UDPv[46]?:\[[\w\.-]{0,63}\]|[\w\.-]{0,63}):?(?:(\d+))?$)"); + // Regex to handle DNS and UDPv4/6 expressions + const static std::regex ROS2_DNS_DOMAINPORT_PATTERN(R"(^(UDPv[46]?:\[[\w\.:-]{0,63}\]|[\w\.-]{0,63}):?(?:(\d+))?$)"); + // Regex to handle TCPv4/6 expressions + const static std::regex ROS2_DNS_DOMAINPORT_PATTERN_TCP( + R"(^(TCPv[46]?:\[[\w\.:-]{0,63}\]):?(?:(\d+))?$)"); // Filling port info auto process_port = [](int port, Locator_t& server) @@ -1232,6 +1236,100 @@ bool load_environment_server_info( // add server to the list add_server2qos(server_id, std::move(flist), attributes); } + // try resolve TCP DNS + else if (std::regex_match(locator, mr, ROS2_DNS_DOMAINPORT_PATTERN_TCP, + std::regex_constants::match_not_null)) + { + std::forward_list flist; + + { + std::stringstream new_locator(locator, + std::ios_base::in | + std::ios_base::out | + std::ios_base::ate); + + // first try the formal notation, add default port if necessary + if (!mr[2].matched) + { + new_locator << ":" << DEFAULT_TCP_SERVER_PORT; + } + + new_locator >> server_locator; + } + + // Otherwise add all resolved locators + switch ( server_locator.kind ) + { + case LOCATOR_KIND_TCPv4: + case LOCATOR_KIND_TCPv6: + IPLocator::setLogicalPort(server_locator, static_cast(server_locator.port)); + flist.push_front(server_locator); + break; + case LOCATOR_KIND_INVALID: + { + std::smatch::iterator it = mr.cbegin(); + + // traverse submatches + if (++it != mr.cend()) + { + std::string domain_name = it->str(); + std::set ipv4, ipv6; + std::tie(ipv4, ipv6) = IPLocator::resolveNameDNS(domain_name); + + // get port if any + int port = DEFAULT_TCP_SERVER_PORT; + if (++it != mr.cend() && it->matched) + { + port = stoi(it->str()); + } + + for ( const std::string& loc : ipv4 ) + { + server_locator.kind = LOCATOR_KIND_TCPv4; + server_locator.set_Invalid_Address(); + IPLocator::setIPv4(server_locator, loc); + + if (IPLocator::isAny(server_locator)) + { + // A server cannot be reach in all interfaces, it's clearly a localhost call + IPLocator::setIPv4(server_locator, "127.0.0.1"); + } + + process_port( port, server_locator); + IPLocator::setLogicalPort(server_locator, static_cast(port)); + flist.push_front(server_locator); + } + + for ( const std::string& loc : ipv6 ) + { + server_locator.kind = LOCATOR_KIND_TCPv6; + server_locator.set_Invalid_Address(); + IPLocator::setIPv6(server_locator, loc); + + if (IPLocator::isAny(server_locator)) + { + // A server cannot be reach in all interfaces, it's clearly a localhost call + IPLocator::setIPv6(server_locator, "::1"); + } + + process_port( port, server_locator); + IPLocator::setLogicalPort(server_locator, static_cast(port)); + flist.push_front(server_locator); + } + } + } + } + + if (flist.empty()) + { + std::stringstream ss; + ss << "Wrong domain name passed into the server's list " << locator; + throw std::invalid_argument(ss.str()); + } + + // add server to the list + add_server2qos(server_id, std::move(flist), attributes); + } else { std::stringstream ss; diff --git a/test/blackbox/common/BlackboxTestsDiscovery.cpp b/test/blackbox/common/BlackboxTestsDiscovery.cpp index c469096f13..2f65079d2c 100644 --- a/test/blackbox/common/BlackboxTestsDiscovery.cpp +++ b/test/blackbox/common/BlackboxTestsDiscovery.cpp @@ -1391,7 +1391,7 @@ TEST(Discovery, ServerClientEnvironmentSetUp) Locator_t loc, loc6(LOCATOR_KIND_UDPv6, 0); // We are going to use several test string and check they are properly parsed and turn into RemoteServerList_t - // 1. single server address without specific port provided + // 1. Single server address without specific port provided string text = "192.168.36.34"; att.clear(); @@ -1406,7 +1406,7 @@ TEST(Discovery, ServerClientEnvironmentSetUp) ASSERT_TRUE(load_environment_server_info(text, output)); ASSERT_EQ(output, standard); - // 2. single server IPv6 address without specific port provided + // 2. Single server IPv6 address without specific port provided text = "2a02:26f0:dd:499::356e"; att.clear(); @@ -1421,7 +1421,7 @@ TEST(Discovery, ServerClientEnvironmentSetUp) ASSERT_TRUE(load_environment_server_info(text, output)); ASSERT_EQ(output, standard); - // 3. single server address specifying a custom listening port + // 3. Single server address specifying a custom listening port text = "192.168.36.34:14520"; att.clear(); @@ -1436,7 +1436,7 @@ TEST(Discovery, ServerClientEnvironmentSetUp) ASSERT_TRUE(load_environment_server_info(text, output)); ASSERT_EQ(output, standard); - // 4. single server IPv6 address specifying a custom listening port + // 4. Single server IPv6 address specifying a custom listening port text = "[2001:470:142:5::116]:14520"; att.clear(); @@ -1451,7 +1451,7 @@ TEST(Discovery, ServerClientEnvironmentSetUp) ASSERT_TRUE(load_environment_server_info(text, output)); ASSERT_EQ(output, standard); - // 5. check any locator is turned into localhost + // 5. Check any locator is turned into localhost text = "0.0.0.0:14520;[::]:14520"; att.clear(); @@ -1473,20 +1473,20 @@ TEST(Discovery, ServerClientEnvironmentSetUp) ASSERT_TRUE(load_environment_server_info(text, output)); ASSERT_EQ(output, standard); - // 6. check empty string scenario is handled + // 6. Check empty string scenario is handled text = ""; output.clear(); ASSERT_TRUE(load_environment_server_info(text, output)); ASSERT_TRUE(output.empty()); - // 7. check at least one server be present scenario is hadled + // 7. Check at least one server be present scenario is hadled text = ";;;;"; output.clear(); ASSERT_FALSE(load_environment_server_info(text, output)); - // 8. check several server scenario + // 8. Check several server scenario text = "192.168.36.34:14520;172.29.55.77:8783;172.30.80.1:31090"; output.clear(); @@ -1516,7 +1516,7 @@ TEST(Discovery, ServerClientEnvironmentSetUp) ASSERT_TRUE(load_environment_server_info(text, output)); ASSERT_EQ(output, standard); - // 9. check several server scenario with IPv6 addresses too + // 9. Check several server scenario with IPv6 addresses too text = "192.168.36.34:14520;[2a02:ec80:600:ed1a::3]:8783;172.30.80.1:31090"; output.clear(); @@ -1546,7 +1546,7 @@ TEST(Discovery, ServerClientEnvironmentSetUp) ASSERT_TRUE(load_environment_server_info(text, output)); ASSERT_EQ(output, standard); - // 10. check multicast addresses are identified as such + // 10. Check multicast addresses are identified as such text = "239.255.0.1;ff1e::ffff:efff:1"; output.clear(); @@ -1569,7 +1569,7 @@ TEST(Discovery, ServerClientEnvironmentSetUp) ASSERT_TRUE(load_environment_server_info(text, output)); ASSERT_EQ(output, standard); - // 11. check ignore some servers scenario + // 11. Check ignore some servers scenario text = ";192.168.36.34:14520;;172.29.55.77:8783;172.30.80.1:31090;"; output.clear(); @@ -1658,6 +1658,79 @@ TEST(Discovery, ServerClientEnvironmentSetUp) ASSERT_TRUE(load_environment_server_info(text, output)); ASSERT_EQ(output, standard); + + // TCP transport + + Locator_t loc_tcp(LOCATOR_KIND_TCPv4, 0); + Locator_t loc_tcp_6(LOCATOR_KIND_TCPv6, 0); + + // 15. Single TCPv4 address without specifying a custom listening port + + text = "TCPv4:[192.168.36.34]"; + + att.clear(); + output.clear(); + standard.clear(); + IPLocator::setIPv4(loc_tcp, "192.168.36.34"); + IPLocator::setPhysicalPort(loc_tcp, DEFAULT_TCP_SERVER_PORT); + IPLocator::setLogicalPort(loc_tcp, DEFAULT_TCP_SERVER_PORT); + att.metatrafficUnicastLocatorList.push_back(loc_tcp); + get_server_client_default_guidPrefix(0, att.guidPrefix); + standard.push_back(att); + + ASSERT_TRUE(load_environment_server_info(text, output)); + ASSERT_EQ(output, standard); + + // 16. Single TCPv6 address without specifying a custom listening port + + text = "TCPv6:[2a02:26f0:dd:499::356e]"; + + att.clear(); + output.clear(); + standard.clear(); + IPLocator::setIPv6(loc_tcp_6, "2a02:26f0:dd:499::356e"); + IPLocator::setPhysicalPort(loc_tcp_6, DEFAULT_TCP_SERVER_PORT); + IPLocator::setLogicalPort(loc_tcp_6, DEFAULT_TCP_SERVER_PORT); + att.metatrafficUnicastLocatorList.push_back(loc_tcp_6); + get_server_client_default_guidPrefix(0, att.guidPrefix); + standard.push_back(att); + + ASSERT_TRUE(load_environment_server_info(text, output)); + ASSERT_EQ(output, standard); + + // 17. Single TCPv4 address specifying a custom listening port + + text = "TCPv4:[192.168.36.34]:14520"; + + att.clear(); + output.clear(); + standard.clear(); + IPLocator::setIPv4(loc_tcp, "192.168.36.34"); + IPLocator::setPhysicalPort(loc_tcp, 14520); + IPLocator::setLogicalPort(loc_tcp, 14520); + att.metatrafficUnicastLocatorList.push_back(loc_tcp); + get_server_client_default_guidPrefix(0, att.guidPrefix); + standard.push_back(att); + + ASSERT_TRUE(load_environment_server_info(text, output)); + ASSERT_EQ(output, standard); + + // 18. Single TCPv6 address specifying a custom listening port + + text = "TCPv6:[2a02:26f0:dd:499::356e]:14520"; + + att.clear(); + output.clear(); + standard.clear(); + IPLocator::setIPv6(loc_tcp_6, "2a02:26f0:dd:499::356e"); + IPLocator::setPhysicalPort(loc_tcp_6, 14520); + IPLocator::setLogicalPort(loc_tcp_6, 14520); + att.metatrafficUnicastLocatorList.push_back(loc_tcp_6); + get_server_client_default_guidPrefix(0, att.guidPrefix); + standard.push_back(att); + + ASSERT_TRUE(load_environment_server_info(text, output)); + ASSERT_EQ(output, standard); } //! Tests the server-client setup using environment variable works fine using DNS @@ -1670,6 +1743,9 @@ TEST(Discovery, ServerClientEnvironmentSetUpDNS) RemoteServerAttributes att; Locator_t loc, loc6(LOCATOR_KIND_UDPv6, 0); + Locator_t loc_tcp(LOCATOR_KIND_TCPv4, 0); + Locator_t loc_tcp_6(LOCATOR_KIND_TCPv6, 0); + // 1. single server DNS address resolution without specific port provided std::string text = "www.acme.com.test"; @@ -1737,6 +1813,38 @@ TEST(Discovery, ServerClientEnvironmentSetUpDNS) ASSERT_TRUE(load_environment_server_info(text, output)); ASSERT_EQ(output, standard); + // TCPv4 + text = "TCPv4:[www.acme.com.test]"; + + att.clear(); + output.clear(); + standard.clear(); + IPLocator::setIPv4(loc_tcp, "216.58.215.164"); + IPLocator::setPhysicalPort(loc_tcp, DEFAULT_TCP_SERVER_PORT); + IPLocator::setLogicalPort(loc_tcp, DEFAULT_TCP_SERVER_PORT); + att.metatrafficUnicastLocatorList.push_back(loc_tcp); + get_server_client_default_guidPrefix(0, att.guidPrefix); + standard.push_back(att); + + ASSERT_TRUE(load_environment_server_info(text, output)); + ASSERT_EQ(output, standard); + + // TCPv6 + text = "TCPv6:[www.acme.com.test]"; + + att.clear(); + output.clear(); + standard.clear(); + IPLocator::setIPv6(loc_tcp_6, "2a00:1450:400e:803::2004"); + IPLocator::setPhysicalPort(loc_tcp_6, DEFAULT_TCP_SERVER_PORT); + IPLocator::setLogicalPort(loc_tcp_6, DEFAULT_TCP_SERVER_PORT); + att.metatrafficUnicastLocatorList.push_back(loc_tcp_6); + get_server_client_default_guidPrefix(0, att.guidPrefix); + standard.push_back(att); + + ASSERT_TRUE(load_environment_server_info(text, output)); + ASSERT_EQ(output, standard); + // 4. single server DNS address specifying a custom locator type and listening port // UDPv4 text = "UDPv4:[www.acme.com.test]:14520"; @@ -1768,8 +1876,40 @@ TEST(Discovery, ServerClientEnvironmentSetUpDNS) ASSERT_TRUE(load_environment_server_info(text, output)); ASSERT_EQ(output, standard); - // Any other Locator kind should fail - text = "TCPv4:[www.acme.com.test]"; + // TCPv4 + text = "TCPv4:[www.acme.com.test]:14520"; + + att.clear(); + output.clear(); + standard.clear(); + IPLocator::setIPv4(loc_tcp, "216.58.215.164"); + IPLocator::setPhysicalPort(loc_tcp, 14520); + IPLocator::setLogicalPort(loc_tcp, 14520); + att.metatrafficUnicastLocatorList.push_back(loc_tcp); + get_server_client_default_guidPrefix(0, att.guidPrefix); + standard.push_back(att); + + ASSERT_TRUE(load_environment_server_info(text, output)); + ASSERT_EQ(output, standard); + + // TCPv6 + text = "TCPv6:[www.acme.com.test]:14520"; + + att.clear(); + output.clear(); + standard.clear(); + IPLocator::setIPv6(loc_tcp_6, "2a00:1450:400e:803::2004"); + IPLocator::setPhysicalPort(loc_tcp_6, 14520); + IPLocator::setLogicalPort(loc_tcp_6, 14520); + att.metatrafficUnicastLocatorList.push_back(loc_tcp_6); + get_server_client_default_guidPrefix(0, att.guidPrefix); + standard.push_back(att); + + ASSERT_TRUE(load_environment_server_info(text, output)); + ASSERT_EQ(output, standard); + + // SHM Locator kind should fail + text = "SHM:[www.acme.com.test]"; output.clear(); ASSERT_FALSE(load_environment_server_info(text, output)); diff --git a/test/unittest/utils/LocatorTests.cpp b/test/unittest/utils/LocatorTests.cpp index 621b0f7ef9..17719a5b5c 100644 --- a/test/unittest/utils/LocatorTests.cpp +++ b/test/unittest/utils/LocatorTests.cpp @@ -1250,7 +1250,7 @@ TEST_F(IPLocatorTests, to_string) // TCPv4 IPLocator::createLocator(LOCATOR_KIND_TCPv4, "0.0.1.1", 2u, locator); - ASSERT_EQ(IPLocator::to_string(locator), "TCPv4:[0.0.1.1]:2"); + ASSERT_EQ(IPLocator::to_string(locator), "TCPv4:[0.0.1.1]:2-0"); // UDPv6 IPLocator::createLocator(LOCATOR_KIND_UDPv6, "200::", 3u, locator); @@ -1258,7 +1258,7 @@ TEST_F(IPLocatorTests, to_string) // TCPv6 IPLocator::createLocator(LOCATOR_KIND_TCPv6, "::2", 4u, locator); - ASSERT_EQ(IPLocator::to_string(locator), "TCPv6:[::2]:4"); + ASSERT_EQ(IPLocator::to_string(locator), "TCPv6:[::2]:4-0"); // SHM IPLocator::createLocator(LOCATOR_KIND_SHM, "", 5u, locator); @@ -1560,7 +1560,7 @@ TEST(LocatorTests, LocatorList_serialization) // Full list ss_filled << locator_list; - ASSERT_EQ(ss_filled.str(), "[UDPv4:[1.1.1.1]:1,TCPv4:[2.2.2.2]:2]"); + ASSERT_EQ(ss_filled.str(), "[UDPv4:[1.1.1.1]:1,TCPv4:[2.2.2.2]:2-0]"); } /* @@ -1872,7 +1872,7 @@ TEST(LocatorDNSTests, dns_locator) else { std::stringstream ss_address; - ss_address << type << ":[" << ip << "]:1024"; + ss_address << type << ":[" << ip << "]:1024-0"; std::stringstream ss_locator; ss_locator << locator; EXPECT_EQ(ss_address.str(), ss_locator.str()) << "Wrong translation " << ss_locator.str() diff --git a/tools/fds/server.cpp b/tools/fds/server.cpp index 58a155ab98..e170ac5dc6 100644 --- a/tools/fds/server.cpp +++ b/tools/fds/server.cpp @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include @@ -228,20 +230,20 @@ int fastdds_discovery_server( participantQos.wire_protocol().builtin.discovery_config.discoveryProtocol = DiscoveryProtocol::SERVER; } - // Set up listening locators. + // Set up listening UDP locators. /** * The metatraffic unicast locator list can be defined: * 1. By means of the CLI specifying a locator address (pOp != nullptr) and port (pO_port != nullptr) - * Locator: IPaddress:port + * Locator: UDPAddres:port * 2. By means of the CLI specifying only the locator address (pOp != nullptr) - * Locator: IPaddress:11811 + * Locator: UDPAddress:11811 * 3. By means of the CLI specifying only the port number (pO_port != nullptr) - * Locator: [0.0.0.0]:port + * Locator: UDPv4:[0.0.0.0]:port * 4. By means of the XML configuration file (options[XML_FILE] != nullptr) * 5. No information provided. - * Locator: [0.0.0.0]:11811 + * Locator: UDPv4:[0.0.0.0]:11811 * - * The CLI has priority over the XML file configuration. + * The UDP CLI has priority over the XML file configuration. */ // If the number of specify ports doesn't match the number of IPs the last port is used. @@ -250,9 +252,13 @@ int fastdds_discovery_server( Locator locator6(LOCATOR_KIND_UDPv6, rtps::DEFAULT_ROS2_SERVER_PORT); // Retrieve first UDP port - option::Option* pO_port = options[PORT]; + option::Option* pO_port = options[UDP_PORT]; if (nullptr != pO_port) { + // if (eprosima::fastdds::dds::check_udp_port(*pO_port, true) != option::ARG_OK) + // { + // return 1; + // } std::stringstream is; is << pO_port->arg; uint16_t id; @@ -271,23 +277,35 @@ int fastdds_discovery_server( IPLocator::setIPv6(locator6, 0, 0, 0, 0, 0, 0, 0, 0); // Retrieve first IP address - pOp = options[IPADDRESS]; + pOp = options[UDPADDRESS]; + option::Option* pO_tcp = options[TCPADDRESS]; + // Retrieve first TCP port + option::Option* pO_tcp_port = options[TCP_PORT]; /** * A locator has been initialized previously in [0.0.0.0] address using either the DEFAULT_ROS2_SERVER_PORT or the * port number set in the CLI. This locator must be used: - * - If there is no IP address defined in the CLI (pOp == nullptr) but the port has been defined - * (pO_port != nullptr) - * - If there is no locator information provided either by CLI or XML file (options[XML_FILE] == nullptr) + * a) If there is no IP address defined in the CLI (pOp == nullptr) but the port has been defined + * (pO_port != nullptr) and there is no TCP address nor port provided by the CLI + * b) If there is no locator information provided either by CLI (UDP and TCP) or XML file + * (options[XML_FILE] == nullptr) */ - if (nullptr == pOp && (nullptr == options[XML_FILE] || nullptr != pO_port)) + if (nullptr == pOp && (nullptr == options[XML_FILE] || nullptr != pO_port) && + (nullptr == pO_tcp && nullptr == pO_tcp_port)) { - // Add default locator + // Add default locator in cases a) and b) + participantQos.wire_protocol().builtin.metatrafficUnicastLocatorList.clear(); + participantQos.wire_protocol().builtin.metatrafficUnicastLocatorList.push_back(locator4); + } + else if (nullptr == pOp && nullptr != pO_port) + { + // UDP port AND TCP port/address has been specified without specifying UDP address participantQos.wire_protocol().builtin.metatrafficUnicastLocatorList.clear(); participantQos.wire_protocol().builtin.metatrafficUnicastLocatorList.push_back(locator4); } else if (nullptr != pOp) { + // UDP address has been specified participantQos.wire_protocol().builtin.metatrafficUnicastLocatorList.clear(); while (pOp) { @@ -378,6 +396,153 @@ int fastdds_discovery_server( } } + // Add TCP default locators addresses + Locator locator_tcp_4(LOCATOR_KIND_TCPv4, rtps::DEFAULT_TCP_SERVER_PORT); + Locator locator_tcp_6(LOCATOR_KIND_TCPv6, rtps::DEFAULT_TCP_SERVER_PORT); + bool default_port = true; + + // Manage TCP port + if (nullptr != pO_tcp_port) + { + std::stringstream is; + is << pO_tcp_port->arg; + uint16_t id; + default_port = false; + + if (!(is >> id + && is.eof() + && IPLocator::setPhysicalPort(locator_tcp_4, id) + && IPLocator::setLogicalPort(locator_tcp_4, id) + && IPLocator::setPhysicalPort(locator_tcp_6, id) + && IPLocator::setLogicalPort(locator_tcp_6, id))) + { + std::cout << "Invalid listening locator port specified:" << id << std::endl; + return 1; + } + } + else + { + IPLocator::setPhysicalPort(locator_tcp_4, rtps::DEFAULT_TCP_SERVER_PORT); + IPLocator::setLogicalPort(locator_tcp_4, rtps::DEFAULT_TCP_SERVER_PORT); + IPLocator::setPhysicalPort(locator_tcp_6, rtps::DEFAULT_TCP_SERVER_PORT); + IPLocator::setLogicalPort(locator_tcp_6, rtps::DEFAULT_TCP_SERVER_PORT); + } + + if (nullptr != pO_tcp || nullptr != pO_tcp_port) + { + if (nullptr == pO_tcp) + { + // Only the TCP port has been specified. Use localhost as default interface for TCP + IPLocator::setIPv4(locator_tcp_4, "127.0.0.1"); + participantQos.wire_protocol().builtin.metatrafficUnicastLocatorList.push_back(locator_tcp_4); + } + else if (nullptr != pO_tcp) + { + // Add tcp locator address + while (pO_tcp) + { + // Get next address + std::string address = std::string(pO_tcp->arg); + int type = LOCATOR_PORT_INVALID; + + // Trial order IPv4, IPv6 & DNS + if (IPLocator::isIPv4(address) && IPLocator::setIPv4(locator_tcp_4, address)) + { + type = LOCATOR_KIND_TCPv4; + } + else if (IPLocator::isIPv6(address) && IPLocator::setIPv6(locator_tcp_6, address)) + { + type = LOCATOR_KIND_TCPv6; + } + else + { + auto response = IPLocator::resolveNameDNS(address); + + // Add the first valid IPv4 address that we can find + if (response.first.size() > 0) + { + address = response.first.begin()->data(); + if (IPLocator::setIPv4(locator_tcp_4, address)) + { + type = LOCATOR_KIND_TCPv4; + } + } + else if (response.second.size() > 0) + { + address = response.second.begin()->data(); + if (IPLocator::setIPv6(locator_tcp_6, address)) + { + type = LOCATOR_KIND_TCPv6; + } + } + } + + // On failure report error + if ( LOCATOR_PORT_INVALID == type ) + { + std::cout << "Invalid listening locator address specified:" << address << std::endl; + return 1; + } + + // Update TCP port + if (nullptr != pO_tcp_port) + { + std::stringstream is; + is << pO_tcp_port->arg; + uint16_t id; + + if (!(is >> id + && is.eof() + && IPLocator::setPhysicalPort(locator_tcp_4, id) + && IPLocator::setLogicalPort(locator_tcp_4, id) + && IPLocator::setPhysicalPort(locator_tcp_6, id) + && IPLocator::setLogicalPort(locator_tcp_6, id))) + { + std::cout << "Invalid listening locator port specified:" << id << std::endl; + return 1; + } + } + + // Add the locator + participantQos.wire_protocol().builtin.metatrafficUnicastLocatorList + .push_back( LOCATOR_KIND_TCPv4 == type ? locator_tcp_4 : locator_tcp_6 ); + + // Create user transport + if (type == LOCATOR_KIND_TCPv4) + { + auto tcp_descriptor = std::make_shared(); + tcp_descriptor->add_listener_port(static_cast(locator_tcp_4.port)); + participantQos.transport().user_transports.push_back(tcp_descriptor); + } + else + { + auto tcp_descriptor = std::make_shared(); + tcp_descriptor->add_listener_port(static_cast(locator_tcp_6.port)); + participantQos.transport().user_transports.push_back(tcp_descriptor); + } + + pO_tcp = pO_tcp->next(); + if (pO_tcp_port) + { + pO_tcp_port = pO_tcp_port->next(); + default_port = false; + } + else + { + if (!default_port) + { + std::cout << "Error: the number of specified TCP ports doesn't match the ip addresses" << + std::endl + << " provided. TCP transports cannot share their port number." << std::endl; + return 1; + } + // One default port has already been used + default_port = false; + } + } + } + } + fastrtps::rtps::GuidPrefix_t guid_prefix = participantQos.wire_protocol().prefix; // Create the server @@ -529,3 +694,33 @@ option::ArgStatus Arg::check_udp_port( return option::ARG_ILLEGAL; } + +option::ArgStatus Arg::check_tcp_port( + const option::Option& option, + bool msg) +{ + // The argument is required + if (nullptr != option.arg) + { + // It must be in an ephemeral port range + std::stringstream is; + is << option.arg; + int id; + + if (is >> id + && is.eof() + && id > 1024 + && id < 65536) + { + return option::ARG_OK; + } + } + + if (msg) + { + std::cout << "Option '" << option.name + << "' value should be an TCP port between 1025 and 65535." << std::endl; + } + + return option::ARG_ILLEGAL; +} diff --git a/tools/fds/server.h b/tools/fds/server.h index b536f3b307..6e47e50846 100644 --- a/tools/fds/server.h +++ b/tools/fds/server.h @@ -25,8 +25,10 @@ enum optionIndex UNKNOWN, HELP, SERVERID, - IPADDRESS, - PORT, + UDPADDRESS, + UDP_PORT, + TCPADDRESS, + TCP_PORT, BACKUP, XML_FILE }; @@ -44,6 +46,10 @@ struct Arg : public option::Arg static option::ArgStatus check_udp_port( const option::Option& option, bool msg); + + static option::ArgStatus check_tcp_port( + const option::Option& option, + bool msg); }; const option::Descriptor usage[] = { @@ -53,71 +59,88 @@ const option::Descriptor usage[] = { "\nUsage: " FAST_SERVER_BINARY " [optional parameters] \nGeneral options:" }, { HELP, 0, "h", "help", Arg::None, - " -h \t--help Produce help message.\n" }, + " -h \t--help Produce help message.\n" }, { SERVERID, 0, "i", "server-id", Arg::check_server_id, - " -i \t--server-id Unique server identifier. Specifies zero based server\n" - "\t position in ROS_DISCOVERY_SERVER environment variable.\n" }, + " -i \t--server-id Unique server identifier. Specifies zero based server\n" + "\t position in ROS_DISCOVERY_SERVER environment variable.\n" }, + + { UDPADDRESS, 0, "l", "udp-address", Arg::required, + " -l \t--udp-address IPv4/IPv6 address chosen to listen the clients. Defaults\n" + "\t to any (0.0.0.0/::0). Instead of an address, a name can\n" + "\t be specified.\n"}, + + { UDP_PORT, 0, "p", "udp-port", Arg::check_udp_port, + " -p \t--udp-port UDP port chosen to listen the clients. Defaults to 11811\n" }, - { IPADDRESS, 0, "l", "ip-address", Arg::required, - " -l \t--ip-address IPv4/IPv6 address chosen to listen the clients. Defaults\n" - "\t to any (0.0.0.0/::0). Instead of an address, a name can\n" - "\t be specified."}, + { TCPADDRESS, 0, "t", "tcp-address", Arg::required, + " -t \t--tcp-address IPv4/IPv6 address chosen to listen the clients using\n" + "\t TCP transport. Defaults to any (0.0.0.0/::0). Instead of an \n" + "\t address, a name can be specified.\n"}, - { PORT, 0, "p", "port", Arg::check_udp_port, - " -p \t--port UDP port chosen to listen the clients. Defaults to 11811\n" }, + { TCP_PORT, 0, "q", "tcp-port", Arg::check_tcp_port, + " -q \t--tcp-port TCP port chosen to listen the clients. Defaults to 42100\n" }, { BACKUP, 0, "b", "backup", Arg::None, - " -b \t--backup Creates a server with a backup file associated.\n" }, + " -b \t--backup Creates a server with a backup file associated.\n" }, { XML_FILE, 0, "x", "xml-file", Arg::required, - " -x \t--xml-file Gets config from XML file. If there is any argument in \n" - "\t common with the config of the XML, the XML argument will \n" - "\t be overriden. A XML file with several profiles will take\n" - "\t the profile with \"is_default_profile=\"true\"\" unless \n" - "\t another profile using uri with \"@\" character is defined.\n"}, + " -x \t--xml-file Gets config from XML file. If there is any argument in \n" + "\t common with the config of the XML, the XML argument will \n" + "\t be overriden. A XML file with several profiles will take\n" + "\t the profile with \"is_default_profile=\"true\"\" unless \n" + "\t another profile using uri with \"@\" character is defined.\n"}, { UNKNOWN, 0, "", "", Arg::None, "Examples:\n" - "\t1. Launch a default server with id 0 (first on ROS_DISCOVERY_SERVER)\n" - "\t listening on all available interfaces on UDP port 11811. Only one\n" - "\t server can use default values per machine.\n\n" - "\t$ " FAST_SERVER_BINARY " -i 0\n\n" - - "\t2. Launch a default server with id 1 (second on ROS_DISCOVERY_SERVER)\n" - "\t listening on localhost with UDP port 14520. Only localhost clients\n" - "\t can reach the server using as ROS_DISCOVERY_SERVER=;127.0.0.1:14520\n\n" - "\t$ " FAST_SERVER_BINARY " -i 1 -l 127.0.0.1 -p 14520\n\n" - - "\t3. Launch a default server with id 1 (second on ROS_DISCOVERY_SERVER)\n" - "\t listening on UDPv6 address with UDP port 14520.\n\n" - "\t$ " FAST_SERVER_BINARY " -i 1 -l 2a02:ec80:600:ed1a::3 -p 14520\n\n" - - "\t4. Launch a default server with id 2 (third on ROS_DISCOVERY_SERVER)\n" - "\t listening on Wi-Fi (192.163.6.34) and Ethernet (172.20.96.1) local\n" - "\t interfaces with UDP ports 8783 and 51083 respectively\n" - "\t (addresses and ports are made up for the example).\n\n" - "\t$ " FAST_SERVER_BINARY " -i 2 -l 192.163.6.34 -p 8783 -l 172.20.96.1 -p 51083\n\n" - - "\t5. Launch a default server with id 3 (fourth on ROS_DISCOVERY_SERVER)\n" - "\t listening on 172.31.44.1 with UDP port 12345 and provided with a\n" - "\t backup file. If the server crashes it will automatically restore its\n" - "\t previous state when reenacted.\n\n" - "\t$ " FAST_SERVER_BINARY " -i 3 -l 172.31.44.1 -p 12345 -b\n\n" - - "\t6. Launch a default server with id 0 (first on ROS_DISCOVERY_SERVER)\n" - "\t listening on localhost with UDP port 14520 Only localhost clients\n" - "\t can reach the server defining as ROS_DISCOVERY_SERVER=localhost:14520\n\n" - "\t$ " FAST_SERVER_BINARY " -i 0 -l localhost -p 14520\n\n" - - "\t7. Launch a server with id 0 (first on ROS_DISCOVERY_SERVER) reading\n" - "\t default configuration from XML file.\n\n" - "\t$ " FAST_SERVER_BINARY " -i 0 -x config.xml\n\n" - - "\t6 Launch a server with id 0 (first on ROS_DISCOVERY_SERVER) reading\n" - "\t specific profile_name configuration from XML file.\n\n" - "\t$ " FAST_SERVER_BINARY " -i 0 -x profile_name@config.xml"}, + "\t1. Launch a default server with id 0 (first on ROS_DISCOVERY_SERVER)\n" + "\t listening on all available interfaces on UDP port 11811. Only one\n" + "\t server can use default values per machine.\n\n" + "\t $ " FAST_SERVER_BINARY " -i 0\n\n" + + "\t2. Launch a default server with id 1 (second on ROS_DISCOVERY_SERVER)\n" + "\t listening on localhost with UDP port 14520. Only localhost clients\n" + "\t can reach the server using ROS_DISCOVERY_SERVER=;127.0.0.1:14520\n\n" + "\t $ " FAST_SERVER_BINARY " -i 1 -l 127.0.0.1 -p 14520\n\n" + + "\t3. Launch a default server with id 1 (second on ROS_DISCOVERY_SERVER)\n" + "\t listening on UDPv6 address with UDP port 14520.\n\n" + "\t $ " FAST_SERVER_BINARY " -i 1 -l 2a02:ec80:600:ed1a::3 -p 14520\n\n" + + "\t4. Launch a default server with id 2 (third on ROS_DISCOVERY_SERVER)\n" + "\t listening on Wi-Fi (192.163.6.34) and Ethernet (172.20.96.1) local\n" + "\t interfaces with UDP ports 8783 and 51083 respectively\n" + "\t (addresses and ports are made up for the example).\n\n" + "\t $ " FAST_SERVER_BINARY " -i 2 -l 192.163.6.34 -p 8783 -l 172.20.96.1 -p 51083\n\n" + + "\t5. Launch a default server with id 3 (fourth on ROS_DISCOVERY_SERVER)\n" + "\t listening on 172.31.44.1 with UDP port 12345 and provided with a\n" + "\t backup file. If the server crashes it will automatically restore its\n" + "\t previous state when reenacted.\n\n" + "\t $ " FAST_SERVER_BINARY " -i 3 -l 172.31.44.1 -p 12345 -b\n\n" + + "\t6. Launch a default server with id 0 (first on ROS_DISCOVERY_SERVER)\n" + "\t listening on localhost with UDP port 14520. Only localhost clients\n" + "\t can reach the server using ROS_DISCOVERY_SERVER=localhost:14520\n\n" + "\t $ " FAST_SERVER_BINARY " -i 0 -l localhost -p 14520\n\n" + + "\t7. Launch a server with id 0 (first on ROS_DISCOVERY_SERVER) reading\n" + "\t default configuration from XML file.\n\n" + "\t $ " FAST_SERVER_BINARY " -i 0 -x config.xml\n\n" + + "\t8. Launch a server with id 0 (first on ROS_DISCOVERY_SERVER) reading\n" + "\t specific profile_name configuration from XML file.\n\n" + "\t $ " FAST_SERVER_BINARY " -i 0 -x profile_name@config.xml\n\n" + + "\t9. Launch a server with id 0 (first on ROS_DISCOVERY_SERVER) listening\n" + "\t on localhost with default TCP port 42100.\n\n" + "\t $ " FAST_SERVER_BINARY " -i 0 -t 127.0.0.1\n\n" + + "\t10. Launch a server with id 0 (first on ROS_DISCOVERY_SERVER) listening\n" + "\t on localhost and Wi-Fi (192.163.6.34). Two TCP ports need to be\n" + "\t specified because TCP Transports cannot share ports.\n\n" + "\t $ " FAST_SERVER_BINARY " -i 0 -t 127.0.0.1 -q 42100 -t 192.163.6.34 -q 42101"}, { 0, 0, 0, 0, 0, 0 } };