Fixed issue #499

This commit is contained in:
Pieter Hintjens 2013-01-31 20:47:45 +01:00
parent 963c6a8e2f
commit 309740e197
8 changed files with 98 additions and 83 deletions

View File

@ -324,12 +324,24 @@ Default value:: -1 (infinite)
Applicable socket types:: all Applicable socket types:: all
ZMQ_IPV6: Retrieve IPv6 socket status
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Retrieve the IPv6 option for the socket. A value of `1` means IPv6 is
enabled on the socket, while `0` means the socket will use only IPv4.
When IPv6 is enabled the socket will connect to, or accept connections
from, both IPv4 and IPv6 hosts.
[horizontal]
Option value type:: int
Option value unit:: boolean
Default value:: 0 (false)
Applicable socket types:: all, when using TCP transports.
ZMQ_IPV4ONLY: Retrieve IPv4-only socket override status ZMQ_IPV4ONLY: Retrieve IPv4-only socket override status
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Retrieve the underlying native socket type. A value of `1` will use IPv4 Retrieve the IPv4-only option for the socket. This option is deprecated.
sockets, while the value of `0` will use IPv6 sockets. An IPv6 socket Please use the ZMQ_IPV6 option.
lets applications connect to and accept connections from both IPv4 and IPv6
hosts.
[horizontal] [horizontal]
Option value type:: int Option value type:: int
@ -470,6 +482,7 @@ Option value unit:: -1,>0
Default value:: -1 (leave to OS default) Default value:: -1 (leave to OS default)
Applicable socket types:: all, when using TCP transports. Applicable socket types:: all, when using TCP transports.
RETURN VALUE RETURN VALUE
------------ ------------
The _zmq_getsockopt()_ function shall return zero if successful. Otherwise it The _zmq_getsockopt()_ function shall return zero if successful. Otherwise it

View File

@ -342,12 +342,26 @@ Default value:: -1 (infinite)
Applicable socket types:: all Applicable socket types:: all
ZMQ_IPV4ONLY: Use IPv4-only sockets ZMQ_IPV6: Enable IPv6 on socket
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the underlying native socket type. A value of `1` will use IPv4 sockets, Set the IPv6 option for the socket. A value of `1` means IPv6 is
while the value of `0` will use IPv6 sockets. An IPv6 socket lets enabled on the socket, while `0` means the socket will use only IPv4.
applications connect to and accept connections from both IPv4 and IPv6 hosts. When IPv6 is enabled the socket will connect to, or accept connections
from, both IPv4 and IPv6 hosts.
[horizontal]
Option value type:: int
Option value unit:: boolean
Default value:: 0 (false)
Applicable socket types:: all, when using TCP transports.
ZMQ_IPV4ONLY: Use IPv4-only on socket
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Set the IPv4-only ootion for the socket. This option is deprecated.
Please use the ZMQ_IPV6 option.
[horizontal] [horizontal]
Option value type:: int Option value type:: int

View File

@ -43,7 +43,7 @@ zmq::options_t::options_t () :
maxmsgsize (-1), maxmsgsize (-1),
rcvtimeo (-1), rcvtimeo (-1),
sndtimeo (-1), sndtimeo (-1),
ipv4only (1), ipv6 (0),
delay_attach_on_connect (0), delay_attach_on_connect (0),
delay_on_close (true), delay_on_close (true),
delay_on_disconnect (true), delay_on_disconnect (true),
@ -182,9 +182,10 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
valid = false; valid = false;
break; break;
/* Deprecated in favor of ZMQ_IPV6 */
case ZMQ_IPV4ONLY: case ZMQ_IPV4ONLY:
if (is_int && (value == 0 || value == 1)) if (is_int && (value == 0 || value == 1))
ipv4only = value; ipv6 = 1 - value;
else else
valid = false; valid = false;
break; break;
@ -192,7 +193,7 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
/* To replace the somewhat surprising IPV4ONLY */ /* To replace the somewhat surprising IPV4ONLY */
case ZMQ_IPV6: case ZMQ_IPV6:
if (is_int && (value == 0 || value == 1)) if (is_int && (value == 0 || value == 1))
ipv4only = 1 - value; ipv6 = value;
else else
valid = false; valid = false;
break; break;
@ -241,7 +242,7 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
else { else {
std::string filter_str ((const char *) optval_, optvallen_); std::string filter_str ((const char *) optval_, optvallen_);
tcp_address_mask_t mask; tcp_address_mask_t mask;
int rc = mask.resolve (filter_str.c_str (), ipv4only); int rc = mask.resolve (filter_str.c_str (), ipv6);
if (rc == 0) if (rc == 0)
tcp_accept_filters.push_back (mask); tcp_accept_filters.push_back (mask);
else else
@ -423,7 +424,7 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
*((int*) optval_) = ipv4only; *((int*) optval_) = 1 - ipv6;
*optvallen_ = sizeof (int); *optvallen_ = sizeof (int);
return 0; return 0;
@ -432,18 +433,18 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
*((int*) optval_) = 1 - ipv4only; *((int*) optval_) = ipv6;
*optvallen_ = sizeof (int); *optvallen_ = sizeof (int);
return 0; return 0;
case ZMQ_DELAY_ATTACH_ON_CONNECT: case ZMQ_DELAY_ATTACH_ON_CONNECT:
if (*optvallen_ < sizeof (int)) { if (*optvallen_ < sizeof (int)) {
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
*((int*) optval_) = delay_attach_on_connect; *((int*) optval_) = delay_attach_on_connect;
*optvallen_ = sizeof (int); *optvallen_ = sizeof (int);
return 0; return 0;
case ZMQ_TCP_KEEPALIVE: case ZMQ_TCP_KEEPALIVE:
if (*optvallen_ < sizeof (int)) { if (*optvallen_ < sizeof (int)) {
@ -482,7 +483,7 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
return 0; return 0;
case ZMQ_LAST_ENDPOINT: case ZMQ_LAST_ENDPOINT:
// don't allow string which cannot contain the entire message /* don't allow string which cannot contain the entire message */
if (*optvallen_ < last_endpoint.size() + 1) { if (*optvallen_ < last_endpoint.size() + 1) {
errno = EINVAL; errno = EINVAL;
return -1; return -1;

View File

@ -92,10 +92,8 @@ namespace zmq
int rcvtimeo; int rcvtimeo;
int sndtimeo; int sndtimeo;
// If 1, indicates the use of IPv4 sockets only, it will not be // If true, IPv6 is enabled (as well as IPv4)
// possible to communicate with IPv6-only hosts. If 0, the socket can bool ipv6;
// connect to and accept connections from both IPv4 and IPv6 hosts.
int ipv4only;
// If 1, connecting pipes are not attached immediately, meaning a send() // If 1, connecting pipes are not attached immediately, meaning a send()
// on a socket with only connecting pipes would block // on a socket with only connecting pipes would block

View File

@ -499,7 +499,7 @@ int zmq::socket_base_t::connect (const char *addr_)
paddr->resolved.tcp_addr = new (std::nothrow) tcp_address_t (); paddr->resolved.tcp_addr = new (std::nothrow) tcp_address_t ();
alloc_assert (paddr->resolved.tcp_addr); alloc_assert (paddr->resolved.tcp_addr);
int rc = paddr->resolved.tcp_addr->resolve ( int rc = paddr->resolved.tcp_addr->resolve (
address.c_str (), false, options.ipv4only ? true : false); address.c_str (), false, options.ipv6);
if (rc != 0) { if (rc != 0) {
delete paddr; delete paddr;
return -1; return -1;

View File

@ -52,10 +52,10 @@
#include <stdlib.h> #include <stdlib.h>
// On Solaris platform, network interface name can be queried by ioctl. // On Solaris platform, network interface name can be queried by ioctl.
int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv4only_) int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv6_)
{ {
// TODO: Unused parameter, IPv6 support not implemented for Solaris. // TODO: Unused parameter, IPv6 support not implemented for Solaris.
(void) ipv4only_; (void) ipv6_;
// Create a socket. // Create a socket.
int fd = open_socket (AF_INET, SOCK_DGRAM, 0); int fd = open_socket (AF_INET, SOCK_DGRAM, 0);
@ -106,7 +106,6 @@ int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv4only_)
errno = ENODEV; errno = ENODEV;
return -1; return -1;
} }
return 0; return 0;
} }
@ -117,10 +116,10 @@ int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv4only_)
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <net/if.h> #include <net/if.h>
int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv4only_) int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv6_)
{ {
// TODO: Unused parameter, IPv6 support not implemented for AIX or HP/UX. // TODO: Unused parameter, IPv6 support not implemented for AIX or HP/UX.
(void) ipv4only_; (void) ipv6_;
// Create a socket. // Create a socket.
int sd = open_socket (AF_INET, SOCK_DGRAM, 0); int sd = open_socket (AF_INET, SOCK_DGRAM, 0);
@ -141,7 +140,6 @@ int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv4only_)
errno = ENODEV; errno = ENODEV;
return -1; return -1;
} }
memcpy (&address.ipv4.sin_addr, &((sockaddr_in*) &ifr.ifr_addr)->sin_addr, memcpy (&address.ipv4.sin_addr, &((sockaddr_in*) &ifr.ifr_addr)->sin_addr,
sizeof (in_addr)); sizeof (in_addr));
@ -157,10 +155,10 @@ int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv4only_)
// On these platforms, network interface name can be queried // On these platforms, network interface name can be queried
// using getifaddrs function. // using getifaddrs function.
int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv4only_) int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv6_)
{ {
// Get the addresses. // Get the addresses.
ifaddrs* ifa = NULL; ifaddrs *ifa = NULL;
int rc = getifaddrs (&ifa); int rc = getifaddrs (&ifa);
errno_assert (rc == 0); errno_assert (rc == 0);
zmq_assert (ifa != NULL); zmq_assert (ifa != NULL);
@ -173,11 +171,8 @@ int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv4only_)
continue; continue;
int family = ifp->ifa_addr->sa_family; int family = ifp->ifa_addr->sa_family;
if ((family == AF_INET || (ipv6_ && family == AF_INET6))
if ((family == AF_INET && !strcmp (nic_, ifp->ifa_name)) {
|| (!ipv4only_ && family == AF_INET6))
&& !strcmp (nic_, ifp->ifa_name))
{
memcpy (&address, ifp->ifa_addr, memcpy (&address, ifp->ifa_addr,
(family == AF_INET) ? sizeof (struct sockaddr_in) (family == AF_INET) ? sizeof (struct sockaddr_in)
: sizeof (struct sockaddr_in6)); : sizeof (struct sockaddr_in6));
@ -193,7 +188,6 @@ int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv4only_)
errno = ENODEV; errno = ENODEV;
return -1; return -1;
} }
return 0; return 0;
} }
@ -201,11 +195,11 @@ int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv4only_)
// On other platforms we assume there are no sane interface names. // On other platforms we assume there are no sane interface names.
// This is true especially of Windows. // This is true especially of Windows.
int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv4only_) int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv6_)
{ {
// All unused parameters. // All unused parameters.
(void) nic_; (void) nic_;
(void) ipv4only_; (void) ipv6_;
errno = ENODEV; errno = ENODEV;
return -1; return -1;
@ -213,8 +207,7 @@ int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv4only_)
#endif #endif
int zmq::tcp_address_t::resolve_interface (const char *interface_, int zmq::tcp_address_t::resolve_interface (const char *interface_, bool ipv6_)
bool ipv4only_)
{ {
// Initialize temporary output pointers with storage address. // Initialize temporary output pointers with storage address.
sockaddr_storage ss; sockaddr_storage ss;
@ -223,15 +216,7 @@ int zmq::tcp_address_t::resolve_interface (const char *interface_,
// Initialise IP-format family/port and populate temporary output pointers // Initialise IP-format family/port and populate temporary output pointers
// with the address. // with the address.
if (ipv4only_) { if (ipv6_) {
sockaddr_in ip4_addr;
memset (&ip4_addr, 0, sizeof (ip4_addr));
ip4_addr.sin_family = AF_INET;
ip4_addr.sin_addr.s_addr = htonl (INADDR_ANY);
out_addrlen = sizeof ip4_addr;
memcpy (out_addr, &ip4_addr, out_addrlen);
}
else {
sockaddr_in6 ip6_addr; sockaddr_in6 ip6_addr;
memset (&ip6_addr, 0, sizeof (ip6_addr)); memset (&ip6_addr, 0, sizeof (ip6_addr));
ip6_addr.sin6_family = AF_INET6; ip6_addr.sin6_family = AF_INET6;
@ -239,8 +224,15 @@ int zmq::tcp_address_t::resolve_interface (const char *interface_,
out_addrlen = sizeof ip6_addr; out_addrlen = sizeof ip6_addr;
memcpy (out_addr, &ip6_addr, out_addrlen); memcpy (out_addr, &ip6_addr, out_addrlen);
} }
else {
// * resolves to INADDR_ANY or in6addr_any. sockaddr_in ip4_addr;
memset (&ip4_addr, 0, sizeof (ip4_addr));
ip4_addr.sin_family = AF_INET;
ip4_addr.sin_addr.s_addr = htonl (INADDR_ANY);
out_addrlen = sizeof ip4_addr;
memcpy (out_addr, &ip4_addr, out_addrlen);
}
// "*" resolves to INADDR_ANY or in6addr_any.
if (strcmp (interface_, "*") == 0) { if (strcmp (interface_, "*") == 0) {
zmq_assert (out_addrlen <= sizeof address); zmq_assert (out_addrlen <= sizeof address);
memcpy (&address, out_addr, out_addrlen); memcpy (&address, out_addr, out_addrlen);
@ -248,7 +240,7 @@ int zmq::tcp_address_t::resolve_interface (const char *interface_,
} }
// Try to resolve the string as a NIC name. // Try to resolve the string as a NIC name.
int rc = resolve_nic_name (interface_, ipv4only_); int rc = resolve_nic_name (interface_, ipv6_);
if (rc != 0 && errno != ENODEV) if (rc != 0 && errno != ENODEV)
return rc; return rc;
if (rc == 0) if (rc == 0)
@ -266,7 +258,7 @@ int zmq::tcp_address_t::resolve_interface (const char *interface_,
// Choose IPv4 or IPv6 protocol family. Note that IPv6 allows for // Choose IPv4 or IPv6 protocol family. Note that IPv6 allows for
// IPv4-in-IPv6 addresses. // IPv4-in-IPv6 addresses.
req.ai_family = ipv4only_ ? AF_INET : AF_INET6; req.ai_family = ipv6_? AF_INET6: AF_INET;
// Arbitrary, not used in the output, but avoids duplicate results. // Arbitrary, not used in the output, but avoids duplicate results.
req.ai_socktype = SOCK_STREAM; req.ai_socktype = SOCK_STREAM;
@ -304,7 +296,7 @@ int zmq::tcp_address_t::resolve_interface (const char *interface_,
return 0; return 0;
} }
int zmq::tcp_address_t::resolve_hostname (const char *hostname_, bool ipv4only_) int zmq::tcp_address_t::resolve_hostname (const char *hostname_, bool ipv6_)
{ {
// Set up the query. // Set up the query.
#if defined ZMQ_HAVE_OPENVMS && defined __ia64 && __INITIAL_POINTER_SIZE == 64 #if defined ZMQ_HAVE_OPENVMS && defined __ia64 && __INITIAL_POINTER_SIZE == 64
@ -316,7 +308,7 @@ int zmq::tcp_address_t::resolve_hostname (const char *hostname_, bool ipv4only_)
// Choose IPv4 or IPv6 protocol family. Note that IPv6 allows for // Choose IPv4 or IPv6 protocol family. Note that IPv6 allows for
// IPv4-in-IPv6 addresses. // IPv4-in-IPv6 addresses.
req.ai_family = ipv4only_ ? AF_INET : AF_INET6; req.ai_family = ipv6_? AF_INET6: AF_INET;
// Need to choose one to avoid duplicate results from getaddrinfo() - this // Need to choose one to avoid duplicate results from getaddrinfo() - this
// doesn't really matter, since it's not included in the addr-output. // doesn't really matter, since it's not included in the addr-output.
@ -382,7 +374,7 @@ zmq::tcp_address_t::~tcp_address_t ()
{ {
} }
int zmq::tcp_address_t::resolve (const char *name_, bool local_, bool ipv4only_) int zmq::tcp_address_t::resolve (const char *name_, bool local_, bool ipv6_)
{ {
// Find the ':' at end that separates address from the port number. // Find the ':' at end that separates address from the port number.
const char *delimiter = strrchr (name_, ':'); const char *delimiter = strrchr (name_, ':');
@ -390,7 +382,6 @@ int zmq::tcp_address_t::resolve (const char *name_, bool local_, bool ipv4only_)
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
// Separate the address/port. // Separate the address/port.
std::string addr_str (name_, delimiter - name_); std::string addr_str (name_, delimiter - name_);
std::string port_str (delimiter + 1); std::string port_str (delimiter + 1);
@ -400,8 +391,8 @@ int zmq::tcp_address_t::resolve (const char *name_, bool local_, bool ipv4only_)
addr_str [addr_str.size () - 1] == ']') addr_str [addr_str.size () - 1] == ']')
addr_str = addr_str.substr (1, addr_str.size () - 2); addr_str = addr_str.substr (1, addr_str.size () - 2);
uint16_t port;
// Allow 0 specifically, to detect invalid port error in atoi if not // Allow 0 specifically, to detect invalid port error in atoi if not
uint16_t port;
if (port_str == "*" || port_str == "0") if (port_str == "*" || port_str == "0")
// Resolve wildcard to 0 to allow autoselection of port // Resolve wildcard to 0 to allow autoselection of port
port = 0; port = 0;
@ -417,9 +408,9 @@ int zmq::tcp_address_t::resolve (const char *name_, bool local_, bool ipv4only_)
// Resolve the IP address. // Resolve the IP address.
int rc; int rc;
if (local_) if (local_)
rc = resolve_interface (addr_str.c_str (), ipv4only_); rc = resolve_interface (addr_str.c_str (), ipv6_);
else else
rc = resolve_hostname (addr_str.c_str (), ipv4only_); rc = resolve_hostname (addr_str.c_str (), ipv6_);
if (rc != 0) if (rc != 0)
return -1; return -1;
@ -434,7 +425,8 @@ int zmq::tcp_address_t::resolve (const char *name_, bool local_, bool ipv4only_)
int zmq::tcp_address_t::to_string (std::string &addr_) int zmq::tcp_address_t::to_string (std::string &addr_)
{ {
if (address.generic.sa_family != AF_INET && address.generic.sa_family != AF_INET6) { if (address.generic.sa_family != AF_INET
&& address.generic.sa_family != AF_INET6) {
addr_.clear (); addr_.clear ();
return -1; return -1;
} }
@ -493,7 +485,7 @@ int zmq::tcp_address_mask_t::mask () const
return address_mask; return address_mask;
} }
int zmq::tcp_address_mask_t::resolve (const char *name_, bool ipv4only_) int zmq::tcp_address_mask_t::resolve (const char *name_, bool ipv6_)
{ {
// Find '/' at the end that separates address from the cidr mask number. // Find '/' at the end that separates address from the cidr mask number.
// Allow empty mask clause and threat it like '/32' for ipv4 or '/128' for ipv6. // Allow empty mask clause and threat it like '/32' for ipv4 or '/128' for ipv6.
@ -507,12 +499,11 @@ int zmq::tcp_address_mask_t::resolve (const char *name_, bool ipv4only_)
return -1; return -1;
} }
} }
else { else
addr_str.assign (name_); addr_str.assign (name_);
}
// Parse address part using standard routines. // Parse address part using standard routines.
int rc = tcp_address_t::resolve_hostname (addr_str.c_str (), ipv4only_); int rc = tcp_address_t::resolve_hostname (addr_str.c_str (), ipv6_);
if (rc != 0) if (rc != 0)
return rc; return rc;

View File

@ -45,8 +45,8 @@ namespace zmq
// This function translates textual TCP address into an address // This function translates textual TCP address into an address
// strcuture. If 'local' is true, names are resolved as local interface // strcuture. If 'local' is true, names are resolved as local interface
// names. If it is false, names are resolved as remote hostnames. // names. If it is false, names are resolved as remote hostnames.
// If 'ipv4only' is true, the name will never resolve to IPv6 address. // If 'ipv6' is true, the name may resolve to IPv6 address.
int resolve (const char* name_, bool local_, bool ipv4only_); int resolve (const char *name_, bool local_, bool ipv6_);
// The opposite to resolve() // The opposite to resolve()
virtual int to_string (std::string &addr_); virtual int to_string (std::string &addr_);
@ -60,10 +60,9 @@ namespace zmq
socklen_t addrlen () const; socklen_t addrlen () const;
protected: protected:
int resolve_nic_name (const char *nic_, bool ipv6_);
int resolve_nic_name (const char *nic_, bool ipv4only_); int resolve_interface (const char *interface_, bool ipv6_);
int resolve_interface (const char *interface_, bool ipv4only_); int resolve_hostname (const char *hostname_, bool ipv6_);
int resolve_hostname (const char *hostname_, bool ipv4only_);
union { union {
sockaddr generic; sockaddr generic;
@ -75,13 +74,12 @@ namespace zmq
class tcp_address_mask_t : public tcp_address_t class tcp_address_mask_t : public tcp_address_t
{ {
public: public:
tcp_address_mask_t (); tcp_address_mask_t ();
// This function enhances tcp_address_t::resolve() with ability to parse // This function enhances tcp_address_t::resolve() with ability to parse
// additional cidr-like(/xx) mask value at the end of the name string. // additional cidr-like(/xx) mask value at the end of the name string.
// Works only with remote hostnames. // Works only with remote hostnames.
int resolve (const char* name_, bool ipv4only_); int resolve (const char *name_, bool ipv6_);
// The opposite to resolve() // The opposite to resolve()
int to_string (std::string &addr_); int to_string (std::string &addr_);
@ -91,7 +89,6 @@ namespace zmq
bool match_address (const struct sockaddr *ss, const socklen_t ss_len) const; bool match_address (const struct sockaddr *ss, const socklen_t ss_len) const;
private: private:
int address_mask; int address_mask;
}; };

View File

@ -148,7 +148,7 @@ int zmq::tcp_listener_t::get_address (std::string &addr_)
int zmq::tcp_listener_t::set_address (const char *addr_) int zmq::tcp_listener_t::set_address (const char *addr_)
{ {
// Convert the textual address into address structure. // Convert the textual address into address structure.
int rc = address.resolve (addr_, true, options.ipv4only ? true : false); int rc = address.resolve (addr_, true, options.ipv6);
if (rc != 0) if (rc != 0)
return -1; return -1;
@ -160,8 +160,9 @@ int zmq::tcp_listener_t::set_address (const char *addr_)
#endif #endif
// IPv6 address family not supported, try automatic downgrade to IPv4. // IPv6 address family not supported, try automatic downgrade to IPv4.
if (address.family () == AF_INET6 && errno == EAFNOSUPPORT && if (address.family () == AF_INET6
!options.ipv4only) { && errno == EAFNOSUPPORT
&& options.ipv6) {
rc = address.resolve (addr_, true, true); rc = address.resolve (addr_, true, true);
if (rc != 0) if (rc != 0)
return rc; return rc;