summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ip.cpp17
-rw-r--r--src/ip.hpp3
-rw-r--r--src/tcp_connecter.cpp21
-rw-r--r--src/tcp_listener.cpp19
4 files changed, 43 insertions, 17 deletions
diff --git a/src/ip.cpp b/src/ip.cpp
index f47e9bf..4bacff3 100644
--- a/src/ip.cpp
+++ b/src/ip.cpp
@@ -457,4 +457,21 @@ void zmq::unblock_socket (fd_t s_)
#endif
}
+void zmq::enable_ipv4_mapping (fd_t s_)
+{
+#ifdef IPV6_V6ONLY
+#ifdef ZMQ_HAVE_WINDOWS
+ DWORD flag = 0;
+#else
+ int flag = 0;
+#endif
+ int rc = setsockopt (s_, IPPROTO_IPV6, IPV6_V6ONLY, (const char*) &flag,
+ sizeof (flag));
+#ifdef ZMQ_HAVE_WINDOWS
+ wsa_assert (rc != SOCKET_ERROR);
+#else
+ errno_assert (rc == 0);
+#endif
+#endif
+}
diff --git a/src/ip.hpp b/src/ip.hpp
index 1066d4b..a8b6eb1 100644
--- a/src/ip.hpp
+++ b/src/ip.hpp
@@ -68,6 +68,9 @@ namespace zmq
// Sets the socket into non-blocking mode.
void unblock_socket (fd_t s_);
+ // Enable IPv4-mapping of addresses in case it is disabled by default.
+ void enable_ipv4_mapping (fd_t s_);
+
}
#endif
diff --git a/src/tcp_connecter.cpp b/src/tcp_connecter.cpp
index b3cd563..7531445 100644
--- a/src/tcp_connecter.cpp
+++ b/src/tcp_connecter.cpp
@@ -199,23 +199,10 @@ int zmq::tcp_connecter_t::open ()
return -1;
#endif
- // Enable IPv4-mapping of addresses in case it is disabled by default.
-#ifdef IPV6_V6ONLY
- if (addr.ss_family == AF_INET6) {
-#ifdef ZMQ_HAVE_WINDOWS
- DWORD flag = 0;
-#else
- int flag = 0;
-#endif
- int rc = setsockopt (s, IPPROTO_IPV6, IPV6_V6ONLY,
- (const char*) &flag, sizeof (flag));
-#ifdef ZMQ_HAVE_WINDOWS
- wsa_assert (rc != SOCKET_ERROR);
-#else
- errno_assert (rc == 0);
-#endif
- }
-#endif
+ // On some systems, IPv4 mapping in IPv6 sockets is disabled by default.
+ // Switch it on in such cases.
+ if (addr.ss_family == AF_INET6)
+ enable_ipv4_mapping (s);
// Set the socket to non-blocking mode so that we get async connect().
unblock_socket (s);
diff --git a/src/tcp_listener.cpp b/src/tcp_listener.cpp
index ef97862..406b4d0 100644
--- a/src/tcp_listener.cpp
+++ b/src/tcp_listener.cpp
@@ -131,6 +131,20 @@ int zmq::tcp_listener_t::set_address (const char *addr_)
// Create a listening socket.
s = ::socket (addr.ss_family, SOCK_STREAM, IPPROTO_TCP);
#ifdef ZMQ_HAVE_WINDOWS
+ if (s == INVALID_SOCKET)
+ wsa_error_to_errno ();
+#endif
+
+ // IPv6 address family not supported, try automatic downgrade to IPv4.
+ if (addr.ss_family == AF_INET6 && errno == EAFNOSUPPORT &&
+ !options.ipv4only) {
+ rc = resolve_ip_interface (&addr, &addr_len, addr_, true);
+ if (rc != 0)
+ return rc;
+ s = ::socket (addr.ss_family, SOCK_STREAM, IPPROTO_TCP);
+ }
+
+#ifdef ZMQ_HAVE_WINDOWS
if (s == INVALID_SOCKET) {
wsa_error_to_errno ();
return -1;
@@ -140,6 +154,11 @@ int zmq::tcp_listener_t::set_address (const char *addr_)
return -1;
#endif
+ // On some systems, IPv4 mapping in IPv6 sockets is disabled by default.
+ // Switch it on in such cases.
+ if (addr.ss_family == AF_INET6)
+ enable_ipv4_mapping (s);
+
// Allow reusing of the address.
int flag = 1;
#ifdef ZMQ_HAVE_WINDOWS