Skip to content

Commit

Permalink
Fix user of interface whitelist on linux [4084] (#346)
Browse files Browse the repository at this point in the history
* Refs #4073. Added regression tests.

* Refs #4073. Binding to multicast address on non-windows systems.

* Refs #4073. Adding to map.

* Refs #4073. Fixed socket close mechanism.

* Refs #4073. Fixed generation of topic name on blackbox tests.

* Refs #4073. Fix use of udpv4 in the generic interface.

* Disabling some unit tests on mac.
  • Loading branch information
richiware authored Dec 5, 2018
1 parent e9e22bb commit c9f0616
Show file tree
Hide file tree
Showing 8 changed files with 610 additions and 229 deletions.
2 changes: 2 additions & 0 deletions include/fastrtps/transport/UDPTransportInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ class UDPTransportInterface : public TransportInterface

bool OpenAndBindInputSockets(const Locator_t& locator, TransportReceiverInterface* receiver, bool is_multicast,
uint32_t maxMsgSize);
UDPChannelResource* CreateInputChannelResource(const std::string& sInterface, const Locator_t& locator,
bool is_multicast, uint32_t maxMsgSize, TransportReceiverInterface* receiver);
virtual eProsimaUDPSocket OpenAndBindInputSocket(const std::string& sIp, uint16_t port, bool is_multicast) = 0;
bool OpenAndBindOutputSockets(const Locator_t& locator);
eProsimaUDPSocket OpenAndBindUnicastOutputSocket(const asio::ip::udp::endpoint& endpoint, uint16_t& port);
Expand Down
69 changes: 47 additions & 22 deletions src/cpp/transport/UDPTransportInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,13 +210,8 @@ bool UDPTransportInterface::OpenAndBindInputSockets(const Locator_t& locator, Tr
std::vector<std::string> vInterfaces = GetBindingInterfacesList();
for (std::string sInterface : vInterfaces)
{
eProsimaUDPSocket unicastSocket = OpenAndBindInputSocket(sInterface, IPLocator::getPhysicalPort(locator), is_multicast);
UDPChannelResource* pChannelResource = new UDPChannelResource(unicastSocket, maxMsgSize);
pChannelResource->SetMessageReceiver(receiver);
pChannelResource->SetInterface(sInterface);
std::thread* newThread = new std::thread(&UDPTransportInterface::performListenOperation, this,
pChannelResource, locator);
pChannelResource->SetThread(newThread);
UDPChannelResource* pChannelResource;
pChannelResource = CreateInputChannelResource(sInterface, locator, is_multicast, maxMsgSize, receiver);
mInputSockets[IPLocator::getPhysicalPort(locator)].push_back(pChannelResource);
}
}
Expand All @@ -232,6 +227,19 @@ bool UDPTransportInterface::OpenAndBindInputSockets(const Locator_t& locator, Tr
return true;
}

UDPChannelResource* UDPTransportInterface::CreateInputChannelResource(const std::string& sInterface, const Locator_t& locator,
bool is_multicast, uint32_t maxMsgSize, TransportReceiverInterface* receiver)
{
eProsimaUDPSocket unicastSocket = OpenAndBindInputSocket(sInterface, IPLocator::getPhysicalPort(locator), is_multicast);
UDPChannelResource* pChannelResource = new UDPChannelResource(unicastSocket, maxMsgSize);
pChannelResource->SetMessageReceiver(receiver);
pChannelResource->SetInterface(sInterface);
std::thread* newThread = new std::thread(&UDPTransportInterface::performListenOperation, this,
pChannelResource, locator);
pChannelResource->SetThread(newThread);
return pChannelResource;
}

bool UDPTransportInterface::OpenAndBindOutputSockets(const Locator_t& locator)
{
(void)locator;
Expand Down Expand Up @@ -289,7 +297,7 @@ bool UDPTransportInterface::OpenAndBindOutputSockets(const Locator_t& locator)
{
eProsimaUDPSocket unicastSocket = OpenAndBindUnicastOutputSocket(GenerateEndpoint(infoIP.name, port), port);
SetSocketOutbountInterface(unicastSocket, infoIP.name);
if (firstInterface)
if (!firstInterface)
{
getSocketPtr(unicastSocket)->set_option(ip::multicast::enable_loopback(true));
firstInterface = true;
Expand Down Expand Up @@ -406,25 +414,42 @@ bool UDPTransportInterface::ReleaseInputChannel(const Locator_t& locator, UDPCha

try
{
Locator_t localLocator;
FillLocalIp(localLocator);

channel->Disable();

ip::udp::socket socket(mService);
socket.open(GenerateProtocol());
socket.bind(GenerateLocalEndpoint(localLocator, 0));

uint16_t port = IPLocator::getPhysicalPort(locator);

// We first send directly to localhost, in case all network interfaces are disabled
// (which would mean that multicast traffic may not be sent)
auto localEndpoint = GenerateLocalEndpoint(localLocator, port);
socket.send_to(asio::buffer("EPRORTPSCLOSE", 13), localEndpoint);
if(IsInterfaceWhiteListEmpty())
{
Locator_t localLocator;
FillLocalIp(localLocator);

ip::udp::socket socket(mService);
socket.open(GenerateProtocol());
socket.bind(GenerateLocalEndpoint(localLocator, 0));

// We first send directly to localhost, in case all network interfaces are disabled
// (which would mean that multicast traffic may not be sent)
auto localEndpoint = GenerateLocalEndpoint(localLocator, port);
socket.send_to(asio::buffer("EPRORTPSCLOSE", 13), localEndpoint);

// We then send to the address of the input locator
auto destinationEndpoint = GenerateLocalEndpoint(locator, port);
socket.send_to(asio::buffer("EPRORTPSCLOSE", 13), destinationEndpoint);
}
else
{
auto interface_address = channel->getSocket()->local_endpoint().address();
ip::udp::socket socket(mService);
socket.open(GenerateProtocol());
socket.bind(asio::ip::udp::endpoint(interface_address, 0));

auto localEndpoint = ip::udp::endpoint(interface_address, port);
socket.send_to(asio::buffer("EPRORTPSCLOSE", 13), localEndpoint);

// We then send to the address of the input locator
auto destinationEndpoint = GenerateLocalEndpoint(locator, port);
socket.send_to(asio::buffer("EPRORTPSCLOSE", 13), destinationEndpoint);
// We then send to the address of the input locator
auto destinationEndpoint = GenerateLocalEndpoint(locator, port);
socket.send_to(asio::buffer("EPRORTPSCLOSE", 13), destinationEndpoint);
}
}
catch (const std::exception& error)
{
Expand Down
96 changes: 71 additions & 25 deletions src/cpp/transport/UDPv4Transport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,42 +273,88 @@ bool UDPv4Transport::OpenInputChannel(const Locator_t& locator, TransportReceive

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

#ifndef _WIN32
if (!IsInterfaceWhiteListEmpty())
{
if (channelResource->GetInterface() == 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;
GetIP4sUniqueInterfaces(locNames, true);
for (const auto& infoIP : locNames)
if (channelResource->GetInterface() == locatorAddressStr)
{
auto ip = asio::ip::address_v4::from_string(infoIP.name);
try
{
channelResource->getSocket()->set_option(
ip::multicast::join_group(ip::address_v4::from_string(IPLocator::toIPv4string(locator)), ip));
}
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* pChannelResource;
pChannelResource = CreateInputChannelResource(locatorAddressStr, locator, true, maxMsgSize, receiver);
mInputSockets[IPLocator::getPhysicalPort(locator)].push_back(pChannelResource);

// Join group on all whitelisted interfaces
for (auto& ip : mInterfaceWhiteList)
{
(void)ex;
logWarning(RTPS_MSG_OUT, "Error joining multicast group on " << ip << ": " << ex.what());
pChannelResource->getSocket()->set_option(ip::multicast::join_group(locatorAddress, ip));
}
}
catch (asio::system_error const& e)
{
(void)e;
logWarning(RTPS_MSG_OUT, "UDPTransport Error binding " << locatorAddressStr << " at port: (" << IPLocator::getPhysicalPort(locator) << ")"
<< " with msg: " << e.what());
}
}
else
}
else
#endif
{
// The multicast group will be joined silently, because we do not
// want to return another resource.
auto& channelResources = mInputSockets.at(IPLocator::getPhysicalPort(locator));
for (UDPChannelResource* channelResource : channelResources)
{
auto ip = asio::ip::address_v4::from_string(channelResource->GetInterface());
try
if (channelResource->GetInterface() == s_IPv4AddressAny)
{
channelResource->getSocket()->set_option(
ip::multicast::join_group(ip::address_v4::from_string(IPLocator::toIPv4string(locator)), ip));
std::vector<IPFinder::info_IP> locNames;
GetIP4sUniqueInterfaces(locNames, true);
for (const auto& infoIP : locNames)
{
auto ip = asio::ip::address_v4::from_string(infoIP.name);
try
{
channelResource->getSocket()->set_option(ip::multicast::join_group(locatorAddress, ip));
}
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_v4::from_string(channelResource->GetInterface());
try
{
channelResource->getSocket()->set_option(ip::multicast::join_group(locatorAddress, ip));
}
catch (std::system_error& ex)
{
(void)ex;
logWarning(RTPS_MSG_OUT, "Error joining multicast group on " << ip << ": " << ex.what());
}
}
}
}
Expand Down
Loading

0 comments on commit c9f0616

Please sign in to comment.