Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix user of interface whitelist on linux [4084] #346

Merged
merged 7 commits into from
Dec 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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