diff --git a/src/cpp/rtps/builtin/discovery/participant/PDPClient.cpp b/src/cpp/rtps/builtin/discovery/participant/PDPClient.cpp index 4dd9b0bb510..962287b4b82 100644 --- a/src/cpp/rtps/builtin/discovery/participant/PDPClient.cpp +++ b/src/cpp/rtps/builtin/discovery/participant/PDPClient.cpp @@ -17,31 +17,25 @@ * */ +#include + +#include +#include #include +#include #include - +#include +#include #include #include -#include - -#include - #include - -#include -#include - +#include #include - +#include #include -#include -#include - -#include - -#include #include -#include +#include +#include using namespace eprosima::fastrtps; @@ -629,9 +623,8 @@ const std::string& ros_discovery_server_env() { static std::string servers; { -#pragma warning(suppress:4996) - const char* data = std::getenv(DEFAULT_ROS2_MASTER_URI); - if (nullptr != data) + const char* data; + if (eprosima::ReturnCode_t::RETCODE_OK == SystemInfo::instance().get_env(DEFAULT_ROS2_MASTER_URI, &data)) { servers = data; } @@ -654,8 +647,10 @@ bool load_environment_server_info( return false; } - // parsing ancillary regex - const std::regex ROS2_IPV4_PATTERN(R"(^((?:[0-9]{1,3}\.){3}[0-9]{1,3})?:?(?:(\d+))?$)"); + /* Parsing ancillary regex */ + // Address should be :. We do not need to verify that the first part + // is an IPv4 address, as it is done latter. + const std::regex ROS2_ADDRESS_PATTERN(R"(^([A-Za-z0-9-.]+)?:?(?:(\d+))?$)"); const std::regex ROS2_SERVER_LIST_PATTERN(R"(([^;]*);?)"); try @@ -681,16 +676,30 @@ bool load_environment_server_info( // now we must parse the inner expression std::smatch mr; std::string locator(sm); - if (std::regex_match(locator, mr, ROS2_IPV4_PATTERN, std::regex_constants::match_not_null)) + if (std::regex_match(locator, mr, ROS2_ADDRESS_PATTERN, std::regex_constants::match_not_null)) { std::smatch::iterator it = mr.cbegin(); while (++it != mr.cend()) { - if (!IPLocator::setIPv4(server_locator, it->str())) + std::string address = it->str(); + + // Check whether the address is IPv4 + if (!IPLocator::isIPv4(address)) + { + auto response = rtps::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(server_locator, address)) { std::stringstream ss; - ss << "Wrong ipv4 address passed into the server's list " << it->str(); + ss << "Wrong ipv4 address passed into the server's list " << address; throw std::invalid_argument(ss.str()); } @@ -705,17 +714,17 @@ bool load_environment_server_info( // reset the locator to default IPLocator::setPhysicalPort(server_locator, DEFAULT_ROS2_SERVER_PORT); - if ( it->matched) + if (it->matched) { // note stoi throws also an invalid_argument int port = stoi(it->str()); - if ( port > std::numeric_limits::max()) + if (port > std::numeric_limits::max()) { - throw std::out_of_range("Too larget udp port passed into the server's list"); + throw std::out_of_range("Too large udp port passed into the server's list"); } - if ( !IPLocator::setPhysicalPort(server_locator, static_cast(port))) + if (!IPLocator::setPhysicalPort(server_locator, static_cast(port))) { std::stringstream ss; ss << "Wrong udp port passed into the server's list " << it->str(); @@ -728,7 +737,7 @@ bool load_environment_server_info( // add the server to the list if (!get_server_client_default_guidPrefix(server_id, server_att.guidPrefix)) { - throw std::invalid_argument("The maximum number of default discovery servers have been reached"); + throw std::invalid_argument("The maximum number of default discovery servers has been reached"); } server_att.metatrafficUnicastLocatorList.clear(); @@ -757,7 +766,7 @@ bool load_environment_server_info( throw std::invalid_argument("No default server locators were provided."); } } - catch ( std::exception& e ) + catch (std::exception& e) { logError(SERVER_CLIENT_DISCOVERY, e.what()); attributes.clear(); diff --git a/src/cpp/rtps/xmlparser/XMLElementParser.cpp b/src/cpp/rtps/xmlparser/XMLElementParser.cpp index e7f377dbce8..b8f87cace54 100644 --- a/src/cpp/rtps/xmlparser/XMLElementParser.cpp +++ b/src/cpp/rtps/xmlparser/XMLElementParser.cpp @@ -2729,6 +2729,23 @@ XMLP_ret XMLParser::getXMLLocatorUDPv4( { return XMLP_ret::XML_ERROR; } + // Check whether the address is IPv4 + if (!IPLocator::isIPv4(s)) + { + auto response = rtps::IPLocator::resolveNameDNS(s); + + // Add the first valid IPv4 address that we can find + if (response.first.size() > 0) + { + s = response.first.begin()->data(); + } + else + { + logError(XMLPARSER, + "DNS server did not return any IPv4 address for: '" << s << "'. Name: " << name); + return XMLP_ret::XML_ERROR; + } + } IPLocator::setIPv4(locator, s); } else @@ -2776,6 +2793,23 @@ XMLP_ret XMLParser::getXMLLocatorUDPv6( { return XMLP_ret::XML_ERROR; } + // Check whether the address is IPv6 + if (!IPLocator::isIPv6(s)) + { + auto response = rtps::IPLocator::resolveNameDNS(s); + + // Add the first valid IPv6 address that we can find + if (response.second.size() > 0) + { + s = response.second.begin()->data(); + } + else + { + logError(XMLPARSER, + "DNS server did not return any IPv6 address for: '" << s << "'. Name: " << name); + return XMLP_ret::XML_ERROR; + } + } IPLocator::setIPv6(locator, s); } else diff --git a/test/blackbox/common/BlackboxTestsDiscovery.cpp b/test/blackbox/common/BlackboxTestsDiscovery.cpp index a8d60e6cb79..9353210ab6c 100644 --- a/test/blackbox/common/BlackboxTestsDiscovery.cpp +++ b/test/blackbox/common/BlackboxTestsDiscovery.cpp @@ -1266,7 +1266,7 @@ TEST(Discovery, ServerClientEnvironmentSetUp) ASSERT_TRUE(load_environment_server_info(text, output)); ASSERT_EQ(output, standard); - // 7. check ignore some servers scenario + // 8. Check that env var cannot specify more than 256 servers text = ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;" ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;" ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;192.168.36.34:14520"; @@ -1274,10 +1274,49 @@ TEST(Discovery, ServerClientEnvironmentSetUp) ASSERT_FALSE(load_environment_server_info(text, output)); - // 8. check non-consistent addresses scenario + // 9. Check addresses as dns name + text = "localhost:12345"; + + output.clear(); + standard.clear(); + + att.clear(); + IPLocator::setIPv4(loc, string("127.0.0.1")); + IPLocator::setPhysicalPort(loc, 12345); + att.metatrafficUnicastLocatorList.push_back(loc); + get_server_client_default_guidPrefix(0, att.guidPrefix); + standard.push_back(att); + + ASSERT_TRUE(load_environment_server_info(text, output)); + ASSERT_EQ(output, standard); + + // 10. Check mixed scenario with addresses and dns text = "192.168.36.34:14520;localhost:12345;172.30.80.1:31090;"; output.clear(); - ASSERT_FALSE(load_environment_server_info(text, output)); + standard.clear(); -} \ No newline at end of file + att.clear(); + IPLocator::setIPv4(loc, string("192.168.36.34")); + IPLocator::setPhysicalPort(loc, 14520); + att.metatrafficUnicastLocatorList.push_back(loc); + get_server_client_default_guidPrefix(0, att.guidPrefix); + standard.push_back(att); + + att.clear(); + IPLocator::setIPv4(loc, string("127.0.0.1")); + IPLocator::setPhysicalPort(loc, 12345); + att.metatrafficUnicastLocatorList.push_back(loc); + get_server_client_default_guidPrefix(1, att.guidPrefix); + standard.push_back(att); + + att.clear(); + IPLocator::setIPv4(loc, string("172.30.80.1")); + IPLocator::setPhysicalPort(loc, 31090); + att.metatrafficUnicastLocatorList.push_back(loc); + get_server_client_default_guidPrefix(2, att.guidPrefix); + standard.push_back(att); + + ASSERT_TRUE(load_environment_server_info(text, output)); + ASSERT_EQ(output, standard); +} diff --git a/tools/fds/README.txt b/tools/fds/README.txt index dbac9e07b89..c8cd94288ef 100644 --- a/tools/fds/README.txt +++ b/tools/fds/README.txt @@ -7,8 +7,9 @@ General options: -i --server-id Mandatory unique server identifier. Specifies zero based server position in ROS_DISCOVERY_SERVER environment variable. - -l --ip-address Server interface chosen to listen the clients. Defaults - to any (0.0.0.0) + -l --ip-address IPv4 address chosen to listen the clients. Defaults + to any (0.0.0.0). Instead of an address, a name can + be specified. -p --port UDP port chosen to listen the clients. Defaults to 11811 @@ -27,17 +28,22 @@ Examples: $ fast-discovery-server -i 1 -l 127.0.0.1 -p 14520 - 3. Launch a default server with id 3 (third on ROS_DISCOVERY_SERVER) + 3. Launch a default server with id 2 (third on ROS_DISCOVERY_SERVER) listening on Wi-Fi (192.168.36.34) and Ethernet (172.20.96.1) local interfaces with UDP ports 8783 and 51083 respectively (addresses and ports are made up for the example). - $ fast-discovery-server -i 1 -l 192.168.36.34 -p 14520 -l 172.20.96.1 -p 51083 + $ fast-discovery-server -i 2 -l 192.168.36.34 -p 8783 -l 172.20.96.1 -p 51083 - 4. Launch a default server with id 4 (fourth on ROS_DISCOVERY_SERVER) + 4. Launch a default server with id 3 (fourth on ROS_DISCOVERY_SERVER) listening on 172.30.144.1 with UDP port 12345 and provided with a backup file. If the server crashes it will automatically restore its previous state when reenacted. - $ fast-discovery-server -i 1 -l 172.30.144.1 -p 12345 -b + $ fast-discovery-server -i 3 -l 172.30.144.1 -p 12345 -b + 5. Launch a default server with id 0 (first on ROS_DISCOVERY_SERVER) + listening on localhost with UDP port 14520. Only localhost clients + can reach the server defining as `ROS_DISCOVERY_SERVER=localhost:14520`. + + $ fastdds discovery -i 0 -l localhost -p 14520 diff --git a/tools/fds/server.cpp b/tools/fds/server.cpp index 020f4eea7e8..15e765fb797 100644 --- a/tools/fds/server.cpp +++ b/tools/fds/server.cpp @@ -174,10 +174,25 @@ int main ( { while ( pOp ) { + // Get next address + std::string address = string(pOp->arg); + + // Check whether the address is IPv4 + if (!rtps::IPLocator::isIPv4(address)) + { + auto response = rtps::IPLocator::resolveNameDNS(address); + + // Add the first valid IPv4 address that we can find + if (response.first.size() > 0) + { + address = response.first.begin()->data(); + } + } + // Update locator address - if (!rtps::IPLocator::setIPv4(locator, string(pOp->arg))) + if (!rtps::IPLocator::setIPv4(locator, address)) { - cout << "Invalid listening locator address specified:" << pOp->arg << endl; + cout << "Invalid listening locator address specified:" << address << endl; return 1; } @@ -288,35 +303,26 @@ option::ArgStatus Arg::check_server_id( if (msg) { cout << "Option '" << option.name - << "' is mandatory. Should be a key indentifier between 0 and 255." << endl; + << "' is mandatory. Should be a key identifier between 0 and 255." << endl; } return option::ARG_ILLEGAL; } /*static*/ -option::ArgStatus Arg::check_server_ipv4( +option::ArgStatus Arg::required( const option::Option& option, bool msg) { - static const std::regex ipv4(R"(^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$)"); - - // the argument is required - if ( nullptr != option.arg ) + if (nullptr != option.arg) { - // we must check if its a proper ip address - if ( std::regex_match(option.arg, ipv4)) - { - return option::ARG_OK; - } + return option::ARG_OK; } if (msg) { - cout << "Option '" << option.name - << "' should be a proper IPv4 address." << endl; + cout << "Option '" << option << "' requires an argument" << endl; } - return option::ARG_ILLEGAL; } diff --git a/tools/fds/server.h b/tools/fds/server.h index ba9446b04fa..8d3c290b99a 100644 --- a/tools/fds/server.h +++ b/tools/fds/server.h @@ -34,7 +34,7 @@ struct Arg : public option::Arg const option::Option& option, bool msg); - static option::ArgStatus check_server_ipv4( + static option::ArgStatus required( const option::Option& option, bool msg); @@ -56,9 +56,10 @@ const option::Descriptor usage[] = { " -i \t--server-id Mandatory unique server identifier. Specifies zero based\n" "\t server position in ROS_DISCOVERY_SERVER environment variable.\n" }, - { IPADDRESS, 0, "l", "ip-address", Arg::check_server_ipv4, - " -l \t--ip-address Server interface chosen to listen the clients. Defaults\n" - "\t to any (0.0.0.0)\n" }, + { IPADDRESS, 0, "l", "ip-address", Arg::required, + " -l \t--ip-address IPv4 address chosen to listen the clients. Defaults\n" + "\t to any (0.0.0.0). Instead of an address, a name can\n" + "\t be specified."}, { PORT, 0, "p", "port", Arg::check_udp_port, " -p \t--port UDP port chosen to listen the clients. Defaults to 11811\n" }, @@ -79,17 +80,22 @@ const option::Descriptor usage[] = { "\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 3 (third on ROS_DISCOVERY_SERVER)\n" + "\t3. Launch a default server with id 2 (third on ROS_DISCOVERY_SERVER)\n" "\t listening on Wi-Fi (192.168.36.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 1 -l 192.168.36.34 -p 14520 -l 172.20.96.1 -p 51083\n\n" + "\t$ " FAST_SERVER_BINARY " -i 2 -l 192.168.36.34 -p 8783 -l 172.20.96.1 -p 51083\n\n" - "\t4. Launch a default server with id 4 (fourth on ROS_DISCOVERY_SERVER)\n" + "\t4. Launch a default server with id 3 (fourth on ROS_DISCOVERY_SERVER)\n" "\t listening on 172.30.144.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 1 -l 172.30.144.1 -p 12345 -b" }, + "\t$ " FAST_SERVER_BINARY " -i 3 -l 172.30.144.1 -p 12345 -b\n\n" + + "\t5. 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"}, { 0, 0, 0, 0, 0, 0 } };