summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Huston <shuston@riverace.com>2018-02-02 18:19:10 -0500
committerSteve Huston <shuston@riverace.com>2018-02-02 18:19:10 -0500
commit4018771ea5d21d85fd3dcb62a44202b90f6990ec (patch)
treee70fbb9fb1bd243e143dada344a09343e4c85c11
parentce6901f995267e3bc2cf5695c1bca42bd07b44b0 (diff)
downloadATCD-4018771ea5d21d85fd3dcb62a44202b90f6990ec.tar.gz
Add ipv6-only capability to ACE_SOCK_Acceptor
-rw-r--r--ACE/ace/SOCK_Acceptor.cpp51
-rw-r--r--ACE/ace/SOCK_Acceptor.h24
-rw-r--r--ACE/tests/SOCK_Acceptor_Test.cpp101
-rw-r--r--ACE/tests/tests.mpc7
4 files changed, 165 insertions, 18 deletions
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<sockaddr_in6 *> (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 <ACE_SOCK_Acceptor> class.
+ *
+ * @author Steve Huston <shuston@riverace.com>
+ */
+//=============================================================================
+
+
+#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 {