Skip to content

Commit

Permalink
UDPv6 refactor and tests (eProsima#1969)
Browse files Browse the repository at this point in the history
* Refs #11278: remove obsolete UDPv4 test

Signed-off-by: JLBuenoLopez-eProsima <[email protected]>

* Refs #11278: remove obsolete UDPv6 test. Uncomment and fix send tests

Signed-off-by: JLBuenoLopez-eProsima <[email protected]>

* Refs #11278: fix IPv6 whitelisting and default multicast address

Signed-off-by: JLBuenoLopez-eProsima <[email protected]>

* Refs #11278: fix blackbox tests to use IPv6

Signed-off-by: JLBuenoLopez-eProsima <[email protected]>

* Refs #11278: fix typo

Signed-off-by: JLBuenoLopez-eProsima <[email protected]>

* Refs #11278: refactor UDPv6 transport. Fix issue with IPv6 scoped address

Signed-off-by: JLBuenoLopez-eProsima <[email protected]>

* Refs #11278: add Whitelist IPv6 tests to Blackbox Network Configuration Tests

Signed-off-by: JLBuenoLopez-eProsima <[email protected]>

* Refs #11278: add whitelist test to UDPv6 unit tests

Signed-off-by: JLBuenoLopez-eProsima <[email protected]>

* Refs #11278: linters

Signed-off-by: JLBuenoLopez-eProsima <[email protected]>

* Refs #11617: fix blackbox infraestructure to use UDPv6

Signed-off-by: JLBuenoLopez-eProsima <[email protected]>

* Refs #11617: duplicate TransportUDP tests to run also UDPv6

Signed-off-by: JLBuenoLopez-eProsima <[email protected]>

* Refs #11617: duplicate NetworkConf tests to run also UDPv6

Signed-off-by: JLBuenoLopez-eProsima <[email protected]>

* Refs #11617: remove unnecessary (and false) comment

Signed-off-by: JLBuenoLopez-eProsima <[email protected]>

* Refs #11617: add tests to UDPv6 unit tests

Signed-off-by: JLBuenoLopez-eProsima <[email protected]>

* Refs #11617: linters

Signed-off-by: JLBuenoLopez-eProsima <[email protected]>

* Refs #11617: fix Windows warnings

Signed-off-by: JLBuenoLopez-eProsima <[email protected]>

* [11278] Fixing transport to fail gracefully if statistics submessage cannot be allocated

* [11278] Extending test to handle statistics transport peculiarities

* [11278] Making the transport tests DDS agnostics again. Now transports ignore any statistics management if the buffer is not properly formatted.

* [11278] Fixing UDPv6 tranport test locator settings.

* [11278] Master Rebase conflicts

Co-authored-by: Miguel Barro <[email protected]>
  • Loading branch information
JLBuenoLopez and Miguel Barro authored Jun 2, 2021
1 parent 56f9107 commit 65f2c66
Show file tree
Hide file tree
Showing 16 changed files with 1,233 additions and 398 deletions.
2 changes: 1 addition & 1 deletion src/cpp/rtps/transport/UDPv4Transport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ UDPv4Transport::UDPv4Transport(

if (interface_whitelist_.empty())
{
logError(TRANSPORT, "All whitelist interfaces where filtered out");
logError(TRANSPORT, "All whitelist interfaces were filtered out");
interface_whitelist_.emplace_back(ip::address_v4::from_string("192.0.2.0"));
}
}
Expand Down
213 changes: 135 additions & 78 deletions src/cpp/rtps/transport/UDPv6Transport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ static void get_ipv6s_unique_interfaces(
auto new_end = std::unique(locNames.begin(), locNames.end(),
[](const IPFinder::info_IP& a, const IPFinder::info_IP& b) -> bool
{
return a.dev == b.dev;
return a.type != IPFinder::IP6_LOCAL && b.type != IPFinder::IP6_LOCAL && a.dev == b.dev;
});
locNames.erase(new_end, locNames.end());
}
Expand Down Expand Up @@ -102,9 +102,27 @@ UDPv6Transport::UDPv6Transport(
{
mSendBufferSize = descriptor.sendBufferSize;
mReceiveBufferSize = descriptor.receiveBufferSize;
for (const auto& interface : descriptor.interfaceWhiteList)

if (!descriptor.interfaceWhiteList.empty())
{
interface_whitelist_.emplace_back(ip::address_v6::from_string(interface));
std::vector<IPFinder::info_IP> local_interfaces;
get_ipv6s(local_interfaces, true);
for (IPFinder::info_IP& infoIP : local_interfaces)
{
for (auto& whitelist_interface : descriptor.interfaceWhiteList)
{
if (compare_ips(infoIP.name, whitelist_interface))
{
interface_whitelist_.emplace_back(ip::address_v6::from_string(infoIP.name));
}
}
}

if (interface_whitelist_.empty())
{
logError(TRANSPORT, "All whitelist interfaces were filtered out");
interface_whitelist_.emplace_back(ip::address_v6::from_string("2001:db8::"));
}
}
}

Expand Down Expand Up @@ -150,51 +168,25 @@ bool UDPv6Transport::getDefaultMetatrafficUnicastLocators(
LocatorList& locators,
uint32_t metatraffic_unicast_port) const
{
if (interface_whitelist_.empty())
{
Locator locator;
locator.kind = LOCATOR_KIND_UDPv6;
locator.port = static_cast<uint16_t>(metatraffic_unicast_port);
locator.set_Invalid_Address();
locators.push_back(locator);
}
else
{
for (auto& it : interface_whitelist_)
{
Locator locator;
locator.kind = LOCATOR_KIND_UDPv6;
locator.port = static_cast<uint16_t>(metatraffic_unicast_port);
IPLocator::setIPv6(locator, it.to_string());
locators.push_back(locator);
}
}
Locator locator;
locator.kind = LOCATOR_KIND_UDPv6;
locator.port = static_cast<uint16_t>(metatraffic_unicast_port);
locator.set_Invalid_Address();
locators.push_back(locator);

return true;
}

bool UDPv6Transport::getDefaultUnicastLocators(
LocatorList& locators,
uint32_t unicast_port) const
{
if (interface_whitelist_.empty())
{
Locator locator;
locator.kind = LOCATOR_KIND_UDPv6;
locator.set_Invalid_Address();
fillUnicastLocator(locator, unicast_port);
locators.push_back(locator);
}
else
{
for (auto& it : interface_whitelist_)
{
Locator locator;
locator.kind = LOCATOR_KIND_UDPv6;
IPLocator::setIPv6(locator, it.to_string());
fillUnicastLocator(locator, unicast_port);
locators.push_back(locator);
}
}
Locator locator;
locator.kind = LOCATOR_KIND_UDPv6;
locator.set_Invalid_Address();
fillUnicastLocator(locator, unicast_port);
locators.push_back(locator);

return true;
}

Expand Down Expand Up @@ -234,8 +226,8 @@ void UDPv6Transport::endpoint_to_locator(
void UDPv6Transport::fill_local_ip(
Locator& loc) const
{
IPLocator::setIPv6(loc, "::1");
loc.kind = LOCATOR_KIND_UDPv6;
IPLocator::setIPv6(loc, "::1");
}

const UDPTransportDescriptor* UDPv6Transport::configuration() const
Expand Down Expand Up @@ -342,47 +334,95 @@ bool UDPv6Transport::OpenInputChannel(

if (IPLocator::isMulticast(locator) && IsInputChannelOpen(locator))
{
// The multicast group will be joined silently, because we do not
// want to return another resource.
auto pChannelResources = mInputSockets.at(IPLocator::getPhysicalPort(locator));
for (auto& channelResource : pChannelResources)
std::string locatorAddressStr = IPLocator::toIPv6string(locator);
ip::address_v6 locatorAddress = ip::address_v6::from_string(locatorAddressStr);

#ifndef _WIN32
if (!is_interface_whitelist_empty())
{
if (channelResource->interface() == s_IPv4AddressAny)
//Either wildcard address or the multicast address needs to be bound on non-windows systems
bool found = false;

// First check if the multicast address is already bound
auto& channelResources = mInputSockets.at(IPLocator::getPhysicalPort(locator));
for (UDPChannelResource* channelResource : channelResources)
{
std::vector<IPFinder::info_IP> locNames;
get_ipv6s_unique_interfaces(locNames, true);
for (const auto& infoIP : locNames)
if (locatorAddressStr == channelResource->interface())
{
auto ip = asio::ip::address_v6::from_string(infoIP.name);
try
{
channelResource->socket()->set_option(ip::multicast::join_group(
ip::address_v6::from_string(IPLocator::toIPv6string(locator)), ip.scope_id()));
}
catch (std::system_error& ex)
found = true;
break;
}
}

// Create a new resource if no one is found
if (!found)
{
try
{
// Bind to multicast address
UDPChannelResource* p_channel_resource;
p_channel_resource = CreateInputChannelResource(locatorAddressStr, locator, true, maxMsgSize,
receiver);
mInputSockets[IPLocator::getPhysicalPort(locator)].push_back(p_channel_resource);

// Join group on all whitelisted interfaces
for (auto& ip : interface_whitelist_)
{
(void)ex;
logWarning(RTPS_MSG_OUT, "Error joining multicast group on " << ip << ": " << ex.what());
p_channel_resource->socket()->set_option(ip::multicast::join_group(locatorAddress,
ip.scope_id()));
}
}
catch (asio::system_error const& e)
{
logWarning(RTPS_MSG_OUT, "UDPTransport Error binding " << locatorAddressStr << " at port: (" <<
IPLocator::getPhysicalPort(locator) << ") with msg: " << e.what());
(void)e;
}
}
else
}
else
#endif // _WIN32
{
// The multicast group will be joined silently, because we do not
// want to return another resource.
auto pChannelResources = mInputSockets.at(IPLocator::getPhysicalPort(locator));
for (auto& channelResource : pChannelResources)
{
auto ip = asio::ip::address_v6::from_string(channelResource->interface());
try
if (channelResource->interface() == s_IPv6AddressAny)
{
channelResource->socket()->set_option(ip::multicast::join_group(
ip::address_v6::from_string(IPLocator::toIPv6string(locator)), ip.scope_id()));
std::vector<IPFinder::info_IP> locNames;
get_ipv6s_unique_interfaces(locNames, true);
for (const auto& infoIP : locNames)
{
auto ip = asio::ip::address_v6::from_string(infoIP.name);
try
{
channelResource->socket()->set_option(ip::multicast::join_group(locatorAddress,
ip.scope_id()));
}
catch (std::system_error& ex)
{
(void)ex;
logWarning(RTPS_MSG_OUT, "Error joining multicast group on " << ip << ": " << ex.what());
}
}
}
catch (std::system_error& ex)
else
{
(void)ex;
logWarning(RTPS_MSG_OUT, "Error joining multicast group on " << ip << ": " << ex.what());
auto ip = asio::ip::address_v6::from_string(channelResource->interface());
try
{
channelResource->socket()->set_option(ip::multicast::join_group(locatorAddress, ip.scope_id()));
}
catch (std::system_error& ex)
{
(void)ex;
logWarning(RTPS_MSG_OUT, "Error joining multicast group on " << ip << ": " << ex.what());
}
}
}
}
}

return success;
}

Expand All @@ -406,24 +446,26 @@ std::vector<std::string> UDPv6Transport::get_binding_interfaces_list()

bool UDPv6Transport::is_interface_allowed(
const std::string& interface) const
{
return is_interface_allowed(asio::ip::address_v6::from_string(interface));
}

bool UDPv6Transport::is_interface_allowed(
const ip::address_v6& ip) const
{
if (interface_whitelist_.empty())
{
return true;
}

if (ip == ip::address_v6::any())
if (asio::ip::address_v6::from_string(interface) == ip::address_v6::any())
{
return true;
}

return find(interface_whitelist_.begin(), interface_whitelist_.end(), ip) != interface_whitelist_.end();
for (auto& whitelist : interface_whitelist_)
{
if (compare_ips(whitelist.to_string(), interface))
{
return true;
}
}

return false;
}

bool UDPv6Transport::is_interface_whitelist_empty() const
Expand Down Expand Up @@ -455,8 +497,7 @@ LocatorList UDPv6Transport::NormalizeLocator(
get_ipv6s(locNames);
for (const auto& infoIP : locNames)
{
auto ip = asio::ip::address_v6::from_string(infoIP.name);
if (is_interface_allowed(ip))
if (is_interface_allowed(infoIP.name))
{
Locator newloc(locator);
IPLocator::setIPv6(newloc, infoIP.locator);
Expand Down Expand Up @@ -520,6 +561,22 @@ void UDPv6Transport::SetSocketOutboundInterface(
asio::ip::address_v6::from_string(sIp).scope_id()));
}

bool UDPv6Transport::compare_ips(
const std::string& ip1,
const std::string& ip2) const
{
// string::find returns string::npos if the character is not found
// If the second parameter is string::npos value, it indicates to take all characters until the end of the string
std::string substr1 = ip1.substr(0, ip1.find('%'));
std::string substr2 = ip2.substr(0, ip2.find('%'));

if (substr1.compare(substr2) == 0)
{
return true;
}
return false;
}

} // namespace rtps
} // namespace fastrtps
} // namespace eprosima
9 changes: 5 additions & 4 deletions src/cpp/rtps/transport/UDPv6Transport.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,6 @@ class UDPv6Transport : public UDPTransportInterface
virtual bool is_interface_allowed(
const std::string& interface) const override;

//! Checks if the given interface is allowed by the white list.
bool is_interface_allowed(
const asio::ip::address_v6& ip) const;

//! Checks if the interfaces white list is empty.
virtual bool is_interface_whitelist_empty() const override;
std::vector<asio::ip::address_v6> interface_whitelist_;
Expand All @@ -156,6 +152,11 @@ class UDPv6Transport : public UDPTransportInterface
virtual void SetSocketOutboundInterface(
eProsimaUDPSocket&,
const std::string&) override;

//! Checks if the IP address is the same without taking into account the scope of the IPv6 address
bool compare_ips(
const std::string& ip1,
const std::string& ip2) const;
};

} // namespace rtps
Expand Down
Loading

0 comments on commit 65f2c66

Please sign in to comment.