Commit c27b9ac7 authored by Steven McCoy's avatar Steven McCoy Committed by Martin Sustrik

Update resolve_ip_interface and resolve_ip_hostname with ipv4only parameter.

Signed-off-by: 's avatarSteven McCoy <steven.mccoy@miru.hk>
Signed-off-by: 's avatarMartin Sustrik <sustrik@250bpm.com>
parent 9184a54f
...@@ -213,7 +213,7 @@ static int resolve_nic_name (struct sockaddr* addr_, char const *interface_, ...@@ -213,7 +213,7 @@ static int resolve_nic_name (struct sockaddr* addr_, char const *interface_,
#endif #endif
int zmq::resolve_ip_interface (sockaddr_storage* addr_, socklen_t *addr_len_, int zmq::resolve_ip_interface (sockaddr_storage* addr_, socklen_t *addr_len_,
char const *interface_) char const *interface_, bool ipv4only_)
{ {
// Find the ':' at end that separates NIC name from service. // Find the ':' at end that separates NIC name from service.
const char *delimiter = strrchr (interface_, ':'); const char *delimiter = strrchr (interface_, ':');
...@@ -241,18 +241,27 @@ int zmq::resolve_ip_interface (sockaddr_storage* addr_, socklen_t *addr_len_, ...@@ -241,18 +241,27 @@ int zmq::resolve_ip_interface (sockaddr_storage* addr_, socklen_t *addr_len_,
sockaddr *out_addr = (sockaddr *) &ss; sockaddr *out_addr = (sockaddr *) &ss;
socklen_t out_addrlen; socklen_t out_addrlen;
// Initialise IPv4-format family/port. // Initialise IP-format family/port and populate temporary output pointers
// with the address.
if (ipv4only_) {
sockaddr_in ip4_addr; sockaddr_in ip4_addr;
memset (&ip4_addr, 0, sizeof (ip4_addr)); memset (&ip4_addr, 0, sizeof (ip4_addr));
ip4_addr.sin_family = AF_INET; ip4_addr.sin_family = AF_INET;
ip4_addr.sin_port = sin_port; ip4_addr.sin_port = sin_port;
ip4_addr.sin_addr.s_addr = htonl (INADDR_ANY); ip4_addr.sin_addr.s_addr = htonl (INADDR_ANY);
// Populate temporary output pointers with ip4_addr.
out_addrlen = (socklen_t) sizeof (ip4_addr); out_addrlen = (socklen_t) sizeof (ip4_addr);
memcpy (out_addr, &ip4_addr, out_addrlen); memcpy (out_addr, &ip4_addr, out_addrlen);
} else {
sockaddr_in6 ip6_addr;
memset (&ip6_addr, 0, sizeof (ip6_addr));
ip6_addr.sin6_family = AF_INET6;
ip6_addr.sin6_port = sin_port;
memcpy (&ip6_addr.sin6_addr, &in6addr_any, sizeof (in6addr_any));
out_addrlen = (socklen_t) sizeof (ip6_addr);
memcpy (out_addr, &ip6_addr, out_addrlen);
}
// * resolves to INADDR_ANY. // * resolves to INADDR_ANY or in6addr_any.
if (iface.compare("*") == 0) { if (iface.compare("*") == 0) {
zmq_assert (out_addrlen <= (socklen_t) sizeof (*addr_)); zmq_assert (out_addrlen <= (socklen_t) sizeof (*addr_));
memcpy (addr_, out_addr, out_addrlen); memcpy (addr_, out_addr, out_addrlen);
...@@ -261,7 +270,7 @@ int zmq::resolve_ip_interface (sockaddr_storage* addr_, socklen_t *addr_len_, ...@@ -261,7 +270,7 @@ int zmq::resolve_ip_interface (sockaddr_storage* addr_, socklen_t *addr_len_,
} }
// Try to resolve the string as a NIC name. // Try to resolve the string as a NIC name.
int rc = resolve_nic_name (out_addr, iface.c_str(), true); int rc = resolve_nic_name (out_addr, iface.c_str(), ipv4only_);
if (rc != 0 && errno != ENODEV) if (rc != 0 && errno != ENODEV)
return rc; return rc;
if (rc == 0) { if (rc == 0) {
...@@ -281,8 +290,9 @@ int zmq::resolve_ip_interface (sockaddr_storage* addr_, socklen_t *addr_len_, ...@@ -281,8 +290,9 @@ int zmq::resolve_ip_interface (sockaddr_storage* addr_, socklen_t *addr_len_,
#endif #endif
memset (&req, 0, sizeof (req)); memset (&req, 0, sizeof (req));
// We only support IPv4 addresses for now. // Choose IPv4 or IPv6 protocol family. Note that IPv6 allows for
req.ai_family = AF_INET; // IPv4-in-IPv6 addresses.
req.ai_family = ipv4only_ ? AF_INET : AF_INET6;
// 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;
...@@ -291,6 +301,15 @@ int zmq::resolve_ip_interface (sockaddr_storage* addr_, socklen_t *addr_len_, ...@@ -291,6 +301,15 @@ int zmq::resolve_ip_interface (sockaddr_storage* addr_, socklen_t *addr_len_,
// service-name irregularity due to indeterminate socktype. // service-name irregularity due to indeterminate socktype.
req.ai_flags = AI_PASSIVE | AI_NUMERICHOST | AI_NUMERICSERV; req.ai_flags = AI_PASSIVE | AI_NUMERICHOST | AI_NUMERICSERV;
#ifndef ZMQ_HAVE_WINDOWS
// Windows by default maps IPv4 addresses into IPv6. In this API we only
// require IPv4-mapped addresses when no native IPv6 interfaces are
// available (~AI_ALL). This saves an additional DNS roundtrip for IPv4
// addresses.
if (req.ai_family == AF_INET6)
req.ai_flags |= AI_V4MAPPED;
#endif
// Resolve the literal address. Some of the error info is lost in case // Resolve the literal address. Some of the error info is lost in case
// of error, however, there's no way to report EAI errors via errno. // of error, however, there's no way to report EAI errors via errno.
rc = getaddrinfo (iface.c_str(), service.c_str(), &req, &res); rc = getaddrinfo (iface.c_str(), service.c_str(), &req, &res);
...@@ -312,7 +331,7 @@ int zmq::resolve_ip_interface (sockaddr_storage* addr_, socklen_t *addr_len_, ...@@ -312,7 +331,7 @@ int zmq::resolve_ip_interface (sockaddr_storage* addr_, socklen_t *addr_len_,
} }
int zmq::resolve_ip_hostname (sockaddr_storage *addr_, socklen_t *addr_len_, int zmq::resolve_ip_hostname (sockaddr_storage *addr_, socklen_t *addr_len_,
const char *hostname_) const char *hostname_, bool ipv4only_)
{ {
// Find the ':' that separates hostname name from service. // Find the ':' that separates hostname name from service.
const char *delimiter = strrchr (hostname_, ':'); const char *delimiter = strrchr (hostname_, ':');
...@@ -329,8 +348,9 @@ int zmq::resolve_ip_hostname (sockaddr_storage *addr_, socklen_t *addr_len_, ...@@ -329,8 +348,9 @@ int zmq::resolve_ip_hostname (sockaddr_storage *addr_, socklen_t *addr_len_,
addrinfo req; addrinfo req;
memset (&req, 0, sizeof (req)); memset (&req, 0, sizeof (req));
// We only support IPv4 addresses for now. // Choose IPv4 or IPv6 protocol family. Note that IPv6 allows for
req.ai_family = AF_INET; // IPv4-in-IPv6 addresses.
req.ai_family = ipv4only_ ? AF_INET : AF_INET6;
// 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.
...@@ -339,6 +359,14 @@ int zmq::resolve_ip_hostname (sockaddr_storage *addr_, socklen_t *addr_len_, ...@@ -339,6 +359,14 @@ int zmq::resolve_ip_hostname (sockaddr_storage *addr_, socklen_t *addr_len_,
// Avoid named services due to unclear socktype. // Avoid named services due to unclear socktype.
req.ai_flags = AI_NUMERICSERV; req.ai_flags = AI_NUMERICSERV;
#ifndef ZMQ_HAVE_WINDOWS
// Windows by default maps IPv4 addresses into IPv6. In this API we only
// require IPv4-mapped addresses when no native IPv6 interfaces are
// available. This saves an additional DNS roundtrip for IPv4 addresses.
if (req.ai_family == AF_INET6)
req.ai_flags |= AI_V4MAPPED;
#endif
// Resolve host name. Some of the error info is lost in case of error, // Resolve host name. Some of the error info is lost in case of error,
// however, there's no way to report EAI errors via errno. // however, there's no way to report EAI errors via errno.
addrinfo *res; addrinfo *res;
......
...@@ -51,12 +51,12 @@ namespace zmq ...@@ -51,12 +51,12 @@ namespace zmq
// Resolves network interface name in <nic-name>:<port> format. Symbol "*" // Resolves network interface name in <nic-name>:<port> format. Symbol "*"
// (asterisk) resolves to INADDR_ANY (all network interfaces). // (asterisk) resolves to INADDR_ANY (all network interfaces).
int resolve_ip_interface (sockaddr_storage *addr_, socklen_t *addr_len_, int resolve_ip_interface (sockaddr_storage *addr_, socklen_t *addr_len_,
char const *interface_); char const *interface_, bool ipv4only_);
// This function resolves a string in <hostname>:<port-number> format. // This function resolves a string in <hostname>:<port-number> format.
// Hostname can be either the name of the host or its IP address. // Hostname can be either the name of the host or its IP address.
int resolve_ip_hostname (sockaddr_storage *addr_, socklen_t *addr_len_, int resolve_ip_hostname (sockaddr_storage *addr_, socklen_t *addr_len_,
const char *hostname_); const char *hostname_, bool ipv4only_);
// This function sets up address for UNIX domain transport. // This function sets up address for UNIX domain transport.
int resolve_local_path (sockaddr_storage *addr_, socklen_t *addr_len_, int resolve_local_path (sockaddr_storage *addr_, socklen_t *addr_len_,
......
...@@ -179,7 +179,7 @@ int zmq::tcp_connecter_t::get_new_reconnect_ivl () ...@@ -179,7 +179,7 @@ int zmq::tcp_connecter_t::get_new_reconnect_ivl ()
int zmq::tcp_connecter_t::set_address (const char *addr_) int zmq::tcp_connecter_t::set_address (const char *addr_)
{ {
return resolve_ip_hostname (&addr, &addr_len, addr_); return resolve_ip_hostname (&addr, &addr_len, addr_, options.ipv4only);
} }
int zmq::tcp_connecter_t::open () int zmq::tcp_connecter_t::open ()
......
...@@ -123,7 +123,7 @@ void zmq::tcp_listener_t::close () ...@@ -123,7 +123,7 @@ void zmq::tcp_listener_t::close ()
int zmq::tcp_listener_t::set_address (const char *addr_) int zmq::tcp_listener_t::set_address (const char *addr_)
{ {
// Convert the interface into sockaddr_in structure. // Convert the interface into sockaddr_in structure.
int rc = resolve_ip_interface (&addr, &addr_len, addr_); int rc = resolve_ip_interface (&addr, &addr_len, addr_, options.ipv4only);
if (rc != 0) if (rc != 0)
return -1; return -1;
......
...@@ -92,7 +92,8 @@ int zmq::vtcp_connecter_t::set_address (const char *addr_) ...@@ -92,7 +92,8 @@ int zmq::vtcp_connecter_t::set_address (const char *addr_)
addr_str += ":9220"; addr_str += ":9220";
std::string subport_str (delimiter + 1); std::string subport_str (delimiter + 1);
subport = (vtcp_subport_t) atoi (subport_str.c_str ()); subport = (vtcp_subport_t) atoi (subport_str.c_str ());
int rc = resolve_ip_hostname (&addr, &addr_len, addr_str.c_str ()); int rc = resolve_ip_hostname (&addr, &addr_len, addr_str.c_str (),
true);
if (rc != 0) if (rc != 0)
return -1; return -1;
} }
...@@ -100,7 +101,8 @@ int zmq::vtcp_connecter_t::set_address (const char *addr_) ...@@ -100,7 +101,8 @@ int zmq::vtcp_connecter_t::set_address (const char *addr_)
std::string addr_str (addr_, delimiter - addr_); std::string addr_str (addr_, delimiter - addr_);
std::string subport_str (delimiter + 1); std::string subport_str (delimiter + 1);
subport = (vtcp_subport_t) atoi (subport_str.c_str ()); subport = (vtcp_subport_t) atoi (subport_str.c_str ());
int rc = resolve_ip_hostname (&addr, &addr_len, addr_str.c_str ()); int rc = resolve_ip_hostname (&addr, &addr_len, addr_str.c_str (),
true);
if (rc != 0) if (rc != 0)
return -1; return -1;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment