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 #2131 - Make -ORBListenerInterfaces work properly as documented and tested #2132

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*S_T.inl
*.bmak
*.recipe
.DS_Store

.depend.*
GNUmakefile*
Expand Down
23 changes: 23 additions & 0 deletions ACE/ace/INET_Addr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,10 @@ ACE_INET_Addr::ACE_INET_Addr (const ACE_INET_Addr &sa)
{
ACE_TRACE ("ACE_INET_Addr::ACE_INET_Addr");
this->set (sa);
if (sa.if_name_)
{
this->set_interface_name (sa.if_name_->c_str ());
}
}

// Initializes a ACE_INET_Addr from a PORT_NUMBER and a 32 bit Internet
Expand Down Expand Up @@ -1002,6 +1006,25 @@ ACE_INET_Addr::set_interface (const char *intf_name)
}
#endif /* ACE_LINUX && ACE_HAS_IPV6 */

std::shared_ptr<const std::string>
ACE_INET_Addr::get_interface_name () const
{
return this->if_name_;
}

void
ACE_INET_Addr::set_interface_name (const char * if_name)
{
if (if_name == nullptr)
{
this->if_name_.reset ();
}
else
{
this->if_name_ = std::make_shared<const std::string> (if_name);
}
}

const char *
ACE_INET_Addr::get_host_addr (char *dst, int size) const
{
Expand Down
22 changes: 22 additions & 0 deletions ACE/ace/INET_Addr.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
#endif /* ACE_LACKS_PRAGMA_ONCE */

#include "ace/Addr.h"

#include <memory>
#include <string>
#include <vector>

ACE_BEGIN_VERSIONED_NAMESPACE_DECL
Expand Down Expand Up @@ -283,6 +286,23 @@ class ACE_Export ACE_INET_Addr : public ACE_Addr
int set_interface (const char *intf_name);
#endif /* (ACE_LINUX || ACE_WIN32) && ACE_HAS_IPV6 */

/**
* For informational purposes only, get the name of the network interface to
* which this IP address is assigned (such as en0, eth2, utun4, etc.). This
* name is not used automatically by any parts of INET_Addr, nor is it stored
* in the internal IP address scope ID (see set_interface for that). It is
* applicable only in certain, limited scopes, notably calls to
* ACE::get_ip_interfaces().
*/
std::shared_ptr<const std::string> get_interface_name () const;

/**
* For informational purposes only, set the name of the network interface to
* which this IP address is assigned. See get_interface_name for more
* information.
*/
void set_interface_name (const char * if_name);

/// Return the port number, converting it into host byte-order.
u_short get_port_number () const;

Expand Down Expand Up @@ -417,6 +437,8 @@ class ACE_Export ACE_INET_Addr : public ACE_Addr
// holds all of them; one is always copied to inet_addr_.
std::vector<union ip46> inet_addrs_;
std::vector<union ip46>::iterator inet_addrs_iter_;

std::shared_ptr<const std::string> if_name_ = nullptr;
};

ACE_END_VERSIONED_NAMESPACE_DECL
Expand Down
109 changes: 94 additions & 15 deletions ACE/ace/SOCK_Dgram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -649,10 +649,16 @@ ACE_SOCK_Dgram::make_multicast_ifaddr (ip_mreq *ret_mreq,
ip_mreq lmreq; // Scratch copy.
if (net_if != 0)
{
const char * net_if_char = ACE_TEXT_ALWAYS_CHAR (net_if);
if (ACE_OS::strstr (net_if_char, "if=") != 0)
{
net_if_char = net_if_char + 3;
}

#if defined (ACE_WIN32)
// This port number is not necessary, just convenient
ACE_INET_Addr interface_addr;
if (interface_addr.set (mcast_addr.get_port_number (), net_if) == -1)
if (interface_addr.set (mcast_addr.get_port_number (), net_if_char) == -1)
{
IP_ADAPTER_ADDRESSES tmp_addrs;
// Initial call to determine actual memory size needed
Expand All @@ -677,8 +683,8 @@ ACE_SOCK_Dgram::make_multicast_ifaddr (ip_mreq *ret_mreq,
int set_result = -1;
while (pAddrs && set_result == -1)
{
if (ACE_OS::strcmp (ACE_TEXT_ALWAYS_CHAR (net_if), pAddrs->AdapterName) == 0 ||
ACE_OS::strcmp (ACE_TEXT_ALWAYS_WCHAR (net_if), pAddrs->FriendlyName) == 0)
if (ACE_OS::strcmp (net_if_char, pAddrs->AdapterName) == 0 ||
ACE_OS::strcmp (ACE_Ascii_To_Wide (net_if_char).wchar_rep (), pAddrs->FriendlyName) == 0)
{
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = pAddrs->FirstUnicastAddress;
LPSOCKADDR sa = pUnicast->Address.lpSockaddr;
Expand All @@ -702,19 +708,19 @@ ACE_SOCK_Dgram::make_multicast_ifaddr (ip_mreq *ret_mreq,
ACE_HTONL (interface_addr.get_ip_address ());
#else
ifreq if_address;
ACE_OS::strsncpy (if_address.ifr_name, ACE_TEXT_ALWAYS_CHAR (net_if), (sizeof if_address.ifr_name));
ACE_OS::strsncpy (if_address.ifr_name, net_if_char, (sizeof if_address.ifr_name));
if (ACE_OS::ioctl (this->get_handle (),
SIOCGIFADDR,
&if_address) == -1)
{
// The net_if name failed to be found. It seems that older linux
// The net_if_char name failed to be found. It seems that older linux
// kernals only support the actual interface name (eg. "eth0"),
// not the IP address string of the interface (eg. "192.168.0.1"),
// which newer kernals seem to automatically translate.
// So assume that we have been given an IP Address and translate
// that instead, similar to the above for windows.
ACE_INET_Addr interface_addr;
if (interface_addr.set (mcast_addr.get_port_number (), net_if) == -1)
if (interface_addr.set (mcast_addr.get_port_number (), net_if_char) == -1)
return -1; // Still doesn't work, unknown device specified.
lmreq.imr_interface.s_addr =
ACE_HTONL (interface_addr.get_ip_address ());
Expand Down Expand Up @@ -755,11 +761,24 @@ ACE_SOCK_Dgram::make_multicast_ifaddr6 (ipv6_mreq *ret_mreq,
#if defined (ACE_WIN32) || !defined (ACE_LACKS_IF_NAMETOINDEX)
if (net_if != 0)
{
const char * net_if_char = ACE_TEXT_ALWAYS_CHAR (net_if);

struct in6_addr net_if_in6_addr;
bool net_if_is_ip_address ( false );
if (ACE_OS::strstr (net_if_char, "if=") != 0)
{
net_if_char = net_if_char + 3;
}
else
{
net_if_is_ip_address = inet_pton (AF_INET6, net_if_char, &net_if_in6_addr) == 1;
}

#if defined (ACE_WIN32)
int if_ix = 0;
bool const num_if =
ACE_OS::ace_isdigit (net_if[0]) &&
(if_ix = ACE_OS::atoi (net_if)) > 0;
ACE_OS::ace_isdigit (net_if_char[0]) &&
(if_ix = ACE_OS::atoi (net_if_char)) > 0;

ULONG bufLen = 15000; // Initial size as per Microsoft
char *buf = nullptr;
Expand Down Expand Up @@ -793,10 +812,30 @@ ACE_SOCK_Dgram::make_multicast_ifaddr6 (ipv6_mreq *ret_mreq,

while (pAddrs)
{
if ((num_if && pAddrs->Ipv6IfIndex == static_cast<unsigned int>(if_ix))
|| (!num_if &&
(ACE_OS::strcmp (ACE_TEXT_ALWAYS_CHAR (net_if), pAddrs->AdapterName) == 0
|| ACE_OS::strcmp (ACE_TEXT_ALWAYS_WCHAR (net_if), pAddrs->FriendlyName) == 0)))
if (net_if_is_ip_address)
{
IP_ADAPTER_UNICAST_ADDRESS *uni = 0;
for (uni = pAddrs->FirstUnicastAddress; uni != 0; uni = uni->Next)
{
struct sockaddr_in6 *sin = reinterpret_cast <sockaddr_in6 *> (uni->Address.lpSockaddr);
if (std::memcmp (
reinterpret_cast <void *> (&net_if_in6_addr),
reinterpret_cast <void *> (&sin->sin6_addr),
sizeof (in6_addr)) == 0)
{
lmreq.ipv6mr_interface = pAddrs->Ipv6IfIndex;
break;
}
}
if (lmreq.ipv6mr_interface != 0)
{
break;
}
}
else if ((num_if && pAddrs->Ipv6IfIndex == static_cast<unsigned int>(if_ix))
|| (!num_if &&
(ACE_OS::strcmp (net_if_char, pAddrs->AdapterName) == 0
|| ACE_OS::strcmp (ACE_Ascii_To_Wide (net_if_char).wchar_rep (), pAddrs->FriendlyName) == 0)))
{
lmreq.ipv6mr_interface = pAddrs->Ipv6IfIndex;
break;
Expand All @@ -809,13 +848,53 @@ ACE_SOCK_Dgram::make_multicast_ifaddr6 (ipv6_mreq *ret_mreq,

#else /* ACE_WIN32 */
#ifndef ACE_LACKS_IF_NAMETOINDEX
lmreq.ipv6mr_interface = ACE_OS::if_nametoindex (ACE_TEXT_ALWAYS_CHAR (net_if));
lmreq.ipv6mr_interface = ACE_OS::if_nametoindex (net_if_char);
#endif /* ACE_LACKS_IF_NAMETOINDEX */
#endif /* ACE_WIN32 */
if (lmreq.ipv6mr_interface == 0)
{
errno = EINVAL;
return -1;
#ifndef ACE_LACKS_IF_NAMETOINDEX
if (net_if_is_ip_address)
{
// net_if is an IP(v6) address, so find the interface name and *then* convert it to an interface index
ACE_INET_Addr *if_addrs = 0;
size_t if_cnt;
if (ACE::get_ip_interfaces (if_cnt, if_addrs) == 0)
{
struct sockaddr_in6 net_if_sockaddr_in6;
net_if_sockaddr_in6.sin6_family = AF_INET6;
net_if_sockaddr_in6.sin6_addr = net_if_in6_addr;
net_if_sockaddr_in6.sin6_port = 0;
net_if_sockaddr_in6.sin6_flowinfo = 0;
ACE_INET_Addr net_if_ace_inet_addr (
reinterpret_cast<struct sockaddr_in *> (&net_if_sockaddr_in6),
sizeof(sockaddr_in6));

while (if_cnt > 0)
{
// Convert to 0-based for indexing, next loop check
--if_cnt;

if (net_if_ace_inet_addr.is_ip_equal (if_addrs[if_cnt]))
{
auto if_name = if_addrs[if_cnt].get_interface_name ();
if (if_name)
{
lmreq.ipv6mr_interface = ACE_OS::if_nametoindex (if_name->c_str ());
}
break;
}
}
}
delete [] if_addrs;
}

if (lmreq.ipv6mr_interface == 0)
#endif /* ACE_LACKS_IF_NAMETOINDEX */
{
errno = EINVAL;
return -1;
}
}
}
#else /* ACE_WIN32 || !ACE_LACKS_IF_NAMETOINDEX */
Expand Down
6 changes: 4 additions & 2 deletions ACE/ace/Sock_Connect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,7 @@ get_ip_interfaces_getifaddrs (size_t &count,
addrs[count].set ((u_short) 0,
addr->sin_addr.s_addr,
0);
addrs[count].set_interface_name (p_if->ifa_name);
++count;
}
}
Expand All @@ -619,8 +620,9 @@ get_ip_interfaces_getifaddrs (size_t &count,
// Skip the ANY address
if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr))
{
addrs[count].set(reinterpret_cast<struct sockaddr_in *> (addr),
sizeof(sockaddr_in6));
addrs[count].set (reinterpret_cast<struct sockaddr_in *> (addr),
sizeof(sockaddr_in6));
addrs[count].set_interface_name (p_if->ifa_name);
++count;
}
}
Expand Down
1 change: 1 addition & 0 deletions TAO/bin/tao_other_tests.lst
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ TAO/orbsvcs/tests/Miop/McastPreferredInterfaces/run_test.pl: !MINIMUM !CORBA_E_C
TAO/orbsvcs/tests/Miop/McastPreferredInterfaces/run_test_ipv6.pl: !MINIMUM !CORBA_E_COMPACT !CORBA_E_MICRO !STATIC !NO_MCAST IPV6 !NO_LOOPBACK_MCAST
TAO/orbsvcs/tests/Miop/McastFragmentation/run_test.pl: !MINIMUM !CORBA_E_COMPACT !CORBA_E_MICRO !STATIC !NO_MCAST
TAO/orbsvcs/tests/Miop/McastFragmentation/run_test_ipv6.pl: IPV6 !MINIMUM !CORBA_E_COMPACT !CORBA_E_MICRO !STATIC !NO_MCAST
TAO/orbsvcs/tests/Miop/McastListenerInterfaces/run_test.pl: IPV6 !MINIMUM !CORBA_E_COMPACT !CORBA_E_MICRO !STATIC !NO_MCAST !NO_LOOPBACK_MCAST
# The following 2 tests use dynamic loading to change the default reactor on Windows !VxWorks !VxWorks_RTP !LabVIEW_RT
TAO/orbsvcs/tests/LoadBalancing/GenericFactory/Application_Controlled/run_test.pl: !MINIMUM !CORBA_E_COMPACT !CORBA_E_MICRO !DISABLE_INTERCEPTORS !STATIC !ACE_FOR_TAO !LynxOS !ST
TAO/orbsvcs/tests/LoadBalancing/GenericFactory/Infrastructure_Controlled/run_test.pl: !MINIMUM !CORBA_E_COMPACT !CORBA_E_MICRO !DISABLE_INTERCEPTORS !STATIC !ACE_FOR_TAO !LynxOS
Expand Down
8 changes: 8 additions & 0 deletions TAO/orbsvcs/tests/Miop/McastListenerInterfaces/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
TestC.cpp
TestC.h
TestC.inl
TestS.cpp
TestS.h
client
server
if_addrs_helper
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// -*- MPC -*-
project(*IDL): taoidldefaults {
IDL_Files {
Test.idl
}
custom_only = 1
}

project(*Server): orbsvcsexe, portablegroup {
exename = server
after += *IDL

Source_Files {
Test_impl.cpp
server.cpp
TestC.cpp
TestS.cpp
}
IDL_Files {
}
}

project(*Client): taoexe {
exename = client
after += *IDL

Source_Files {
client.cpp
TestC.cpp
}
IDL_Files {
}
}

project(*Helper) {
exename = if_addrs_helper

Header_Files {
}
Source_Files {
if_addrs_helper.cpp
}
}
15 changes: 15 additions & 0 deletions TAO/orbsvcs/tests/Miop/McastListenerInterfaces/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
This test verifies the proper behavior of the -ORBListenerInterfaces option on IPv4 and IPv6 with values *=ip_addr,
*=interface_name, and CopyPreferredInterfaces. The latter requires also using the -ORBPreferredInterface option.
It does so by doing the following:

1. Calling the local helper utility if_addrs_helper to determine the system name of the loopback interface and
ethernet-like interface(s) with routable IPv4 and IPv6 addresses, as well as the correct IP addresses for those
interfaces.

2. Creating a matrix of tests across these interfaces, IP addresses, and the *=ip_addr, *=interface_name, and
CopyPreferredInterfaces option values.

3. Executing the matrix of tests and asserting a specific failure (but no other failures) for loopback interfaces and
no failures for non-loopback interfaces. Specifically, for loopback interfaces, the server process should never
receive the instruction to shut down from the client, and so the test should time out waiting on the server process
and elect to kill it.
12 changes: 12 additions & 0 deletions TAO/orbsvcs/tests/Miop/McastListenerInterfaces/Test.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef _TEST_IDL_
#define _TEST_IDL_

module Test
{
interface Server
{
oneway void shutdown ();
};
};

#endif // _TEST_IDL_
12 changes: 12 additions & 0 deletions TAO/orbsvcs/tests/Miop/McastListenerInterfaces/Test_impl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include "Test_impl.h"


Server_impl::Server_impl (CORBA::ORB_ptr orb)
: orb_ (CORBA::ORB::_duplicate (orb))
{
}

void Server_impl::shutdown ()
{
this->orb_->shutdown (false);
}
17 changes: 17 additions & 0 deletions TAO/orbsvcs/tests/Miop/McastListenerInterfaces/Test_impl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef TEST_IMPL_HPP
#define TEST_IMPL_HPP

#include "TestS.h"

class Server_impl : public virtual POA_Test::Server
{
public:
Server_impl (CORBA::ORB_ptr orb);

virtual void shutdown ();

private:
CORBA::ORB_var orb_;
};

#endif /* TEST_IMPL_HPP */
Loading
Loading