From 4018771ea5d21d85fd3dcb62a44202b90f6990ec Mon Sep 17 00:00:00 2001 From: Steve Huston Date: Fri, 2 Feb 2018 18:19:10 -0500 Subject: Add ipv6-only capability to ACE_SOCK_Acceptor --- ACE/ace/SOCK_Acceptor.cpp | 51 +++++++++++++++----- ACE/ace/SOCK_Acceptor.h | 24 +++++++--- ACE/tests/SOCK_Acceptor_Test.cpp | 101 +++++++++++++++++++++++++++++++++++++++ ACE/tests/tests.mpc | 7 +++ 4 files changed, 165 insertions(+), 18 deletions(-) create mode 100644 ACE/tests/SOCK_Acceptor_Test.cpp diff --git a/ACE/ace/SOCK_Acceptor.cpp b/ACE/ace/SOCK_Acceptor.cpp index 9128232fed2..c329029e33a 100644 --- a/ACE/ace/SOCK_Acceptor.cpp +++ b/ACE/ace/SOCK_Acceptor.cpp @@ -220,12 +220,15 @@ ACE_SOCK_Acceptor::dump (void) const int ACE_SOCK_Acceptor::shared_open (const ACE_Addr &local_sap, int protocol_family, - int backlog) + int backlog, + int ipv6_only) { ACE_TRACE ("ACE_SOCK_Acceptor::shared_open"); int error = 0; -#if defined (ACE_HAS_IPV6) +#if !defined (ACE_HAS_IPV6) || (!defined (IPPROTO_IPV6) || !defined (IPV6_V6ONLY)) + ACE_UNUSED_ARG (ipv6_only); +#else /* !defined (ACE_HAS_IPV6) || (!defined (IPPROTO_IPV6) || !defined (IPV6_V6ONLY)) */ if (protocol_family == PF_INET6) { sockaddr_in6 local_inet6_addr; @@ -241,7 +244,23 @@ ACE_SOCK_Acceptor::shared_open (const ACE_Addr &local_sap, } else local_inet6_addr = *reinterpret_cast (local_sap.get_addr ()); - + /* + * Handle IPv6-only requests. On Windows, v6-only is the default + * unless it is turned off. On Linux, v4/v6 dual is the default + * unless v6-only is turned on. + * This must be done before attempting to bind the address. + * On Windows older than Vista this will fail. + */ +# if defined (IPPROTO_IPV6) && defined (IPV6_V6ONLY) + int setting = !!ipv6_only; + if (-1 == ACE_OS::setsockopt (this->get_handle (), + IPPROTO_IPV6, + IPV6_V6ONLY, + (char *)&setting, + sizeof (setting))) + error = 1; + else +# endif /* IPPROTO_V6 && IPV6_ONLY */ // We probably don't need a bind_port written here. // There are currently no supported OS's that define // ACE_LACKS_WILDCARD_BIND. @@ -251,7 +270,7 @@ ACE_SOCK_Acceptor::shared_open (const ACE_Addr &local_sap, error = 1; } else -#endif +#endif /* !defined (ACE_HAS_IPV6) || (!defined (IPPROTO_IPV6) || !defined (IPV6_V6ONLY)) */ if (protocol_family == PF_INET) { sockaddr_in local_inet_addr; @@ -301,7 +320,8 @@ ACE_SOCK_Acceptor::open (const ACE_Addr &local_sap, int reuse_addr, int protocol_family, int backlog, - int protocol) + int protocol, + int ipv6_only) { ACE_TRACE ("ACE_SOCK_Acceptor::open"); @@ -319,7 +339,8 @@ ACE_SOCK_Acceptor::open (const ACE_Addr &local_sap, else return this->shared_open (local_sap, protocol_family, - backlog); + backlog, + ipv6_only); } ACE_SOCK_Acceptor::ACE_SOCK_Acceptor (const ACE_Addr &local_sap, @@ -329,7 +350,8 @@ ACE_SOCK_Acceptor::ACE_SOCK_Acceptor (const ACE_Addr &local_sap, int reuse_addr, int protocol_family, int backlog, - int protocol) + int protocol, + int ipv6_only) { ACE_TRACE ("ACE_SOCK_Acceptor::ACE_SOCK_Acceptor"); if (this->open (local_sap, @@ -339,7 +361,8 @@ ACE_SOCK_Acceptor::ACE_SOCK_Acceptor (const ACE_Addr &local_sap, reuse_addr, protocol_family, backlog, - protocol) == -1) + protocol, + ipv6_only) == -1) ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE_SOCK_Acceptor"))); @@ -352,7 +375,8 @@ ACE_SOCK_Acceptor::open (const ACE_Addr &local_sap, int reuse_addr, int protocol_family, int backlog, - int protocol) + int protocol, + int ipv6_only) { ACE_TRACE ("ACE_SOCK_Acceptor::open"); @@ -375,7 +399,8 @@ ACE_SOCK_Acceptor::open (const ACE_Addr &local_sap, else return this->shared_open (local_sap, protocol_family, - backlog); + backlog, + ipv6_only); } // General purpose routine for performing server ACE_SOCK creation. @@ -384,14 +409,16 @@ ACE_SOCK_Acceptor::ACE_SOCK_Acceptor (const ACE_Addr &local_sap, int reuse_addr, int protocol_family, int backlog, - int protocol) + int protocol, + int ipv6_only) { ACE_TRACE ("ACE_SOCK_Acceptor::ACE_SOCK_Acceptor"); if (this->open (local_sap, reuse_addr, protocol_family, backlog, - protocol) == -1) + protocol, + ipv6_only) == -1) ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE_SOCK_Acceptor"))); diff --git a/ACE/ace/SOCK_Acceptor.h b/ACE/ace/SOCK_Acceptor.h index 87e202ba79c..8e9513ebccd 100644 --- a/ACE/ace/SOCK_Acceptor.h +++ b/ACE/ace/SOCK_Acceptor.h @@ -48,12 +48,16 @@ public: * @a local_sap is the address that we're going to listen for * connections on. If @a reuse_addr is 1 then we'll use the * @c SO_REUSEADDR to reuse this address. + * @a ipv6_only is used when opening a IPv6 acceptor. If non-zero, + * the socket will only accept connections from IPv6 peers. If zero + * the socket will accept both IPv4 and v6 if it is able to. */ ACE_SOCK_Acceptor (const ACE_Addr &local_sap, int reuse_addr = 0, int protocol_family = PF_UNSPEC, int backlog = ACE_DEFAULT_BACKLOG, - int protocol = 0); + int protocol = 0, + int ipv6_only = 0); /// Initialize a passive-mode QoS-enabled acceptor socket. Returns 0 /// on success and -1 on failure. @@ -64,20 +68,26 @@ public: int reuse_addr, int protocol_family = PF_UNSPEC, int backlog = ACE_DEFAULT_BACKLOG, - int protocol = 0); + int protocol = 0, + int ipv6_only = 0); /** * Initialize a passive-mode BSD-style acceptor socket (no QoS). * @a local_sap is the address that we're going to listen for * connections on. If @a reuse_addr is 1 then we'll use the - * @c SO_REUSEADDR to reuse this address. Returns 0 on success and + * @c SO_REUSEADDR to reuse this address. + * @a ipv6_only is used when opening a IPv6 acceptor. If non-zero, + * the socket will only accept connections from IPv6 peers. If zero + * the socket will accept both IPv4 and v6 if it is able to. + * @retval Returns 0 on success and * -1 on failure. */ int open (const ACE_Addr &local_sap, int reuse_addr = 0, int protocol_family = PF_UNSPEC, int backlog = ACE_DEFAULT_BACKLOG, - int protocol = 0); + int protocol = 0, + int ipv6_only = 0); /// Initialize a passive-mode QoS-enabled acceptor socket. Returns 0 /// on success and -1 on failure. @@ -88,7 +98,8 @@ public: int reuse_addr, int protocol_family = PF_UNSPEC, int backlog = ACE_DEFAULT_BACKLOG, - int protocol = 0); + int protocol = 0, + int ipv6_only = 0); /// Close the socket. Returns 0 on success and -1 on failure. int close (void); @@ -161,7 +172,8 @@ protected: */ int shared_open (const ACE_Addr &local_sap, int protocol_family, - int backlog); + int backlog, + int ipv6_only); private: /// Do not allow this function to percolate up to this interface... diff --git a/ACE/tests/SOCK_Acceptor_Test.cpp b/ACE/tests/SOCK_Acceptor_Test.cpp new file mode 100644 index 00000000000..84835a4eec5 --- /dev/null +++ b/ACE/tests/SOCK_Acceptor_Test.cpp @@ -0,0 +1,101 @@ + +//============================================================================= +/** + * @file SOCK_Acceptor_Test.cpp + * + * $Id$ + * + * This is a test of the class. + * + * @author Steve Huston + */ +//============================================================================= + + +#include "test_config.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_sys_wait.h" +#include "ace/Time_Value.h" +#include "ace/SOCK_Connector.h" +#include "ace/SOCK_Acceptor.h" + + +static int +test_accept (ACE_Addr listen_addr, int v6_only) +{ + int status = 0; + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) starting listen, ipv6-only %d\n"), + v6_only)); + // Bind listener to any port and then find out what the port was. + ACE_SOCK_Acceptor acceptor; + ACE_INET_Addr listening_at; + if (acceptor.open (listen_addr, + 0, + PF_UNSPEC, + ACE_DEFAULT_BACKLOG, + 0, + v6_only) == -1 + || acceptor.get_local_addr (listening_at) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("open")), + -1); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) listening at port %d\n"), + listening_at.get_port_number ())); + + // Try IPv4 and, if v6 is available, v6. If v6-capable and v6-only + // is selected, v4 should NOT work and v6 should. If not v6-capable + // just try v4 and it should work regardless of v6-only. + ACE_SOCK_Connector connector; + + ACE_INET_Addr v4_addr (listening_at.get_port_number(), + ACE_LOCALHOST, + PF_INET); + ACE_SOCK_Stream v4_stream; + bool v4_ok = (connector.connect (v4_stream, v4_addr) == 0); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("v4 connect %s\n"), + v4_ok ? ACE_TEXT ("OK") : ACE_TEXT ("FAIL"))); + v4_stream.close(); + +#if defined (ACE_HAS_IPV6) + ACE_INET_Addr v6_addr (listening_at.get_port_number(), + ACE_IPV6_LOCALHOST, + PF_INET6); + ACE_SOCK_Stream v6_stream; + bool v6_ok = (connector.connect (v6_stream, v6_addr) == 0); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("v6 connect %s\n"), + v6_ok ? ACE_TEXT ("OK") : ACE_TEXT ("FAIL"))); + v6_stream.close(); + + if (v6_only && v4_ok) + status = 1; + if (!v6_only && !v4_ok) + status = 1; + if (!v6_ok) + status = 1; +#else + status = v4_ok ? 0 : 1; +#endif /* ACE_HAS_IPV6 */ + acceptor.close (); + return status; +} + +int +run_main (int, ACE_TCHAR *[]) +{ + ACE_START_TEST (ACE_TEXT ("SOCK_Acceptor_Test")); + + int status = 0; + + if (test_accept (ACE_Addr::sap_any, 1) != 0) + status = 1; + if (test_accept (ACE_Addr::sap_any, 0) != 0) + status = 1; + + ACE_END_TEST; + return status; +} diff --git a/ACE/tests/tests.mpc b/ACE/tests/tests.mpc index 3ff247f79c0..c0c85aa221a 100644 --- a/ACE/tests/tests.mpc +++ b/ACE/tests/tests.mpc @@ -1437,6 +1437,13 @@ project(Singleton Test) : acetest { } } +project(SOCK Acceptor_Test) : acetest { + exename = SOCK_Acceptor_Test + Source_Files { + SOCK_Acceptor_Test.cpp + } +} + project(SOCK Test) : acetest { exename = SOCK_Test Source_Files { -- cgit v1.2.1