diff options
| -rw-r--r-- | src/ip.cpp | 64 | ||||
| -rw-r--r-- | src/ip.hpp | 4 | ||||
| -rw-r--r-- | src/tcp_connecter.cpp | 2 | ||||
| -rw-r--r-- | src/tcp_listener.cpp | 2 | ||||
| -rw-r--r-- | src/vtcp_connecter.cpp | 6 | 
5 files changed, 54 insertions, 24 deletions
@@ -213,7 +213,7 @@ static int resolve_nic_name (struct sockaddr* addr_, char const *interface_,  #endif  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.      const char *delimiter = strrchr (interface_, ':'); @@ -241,18 +241,27 @@ int zmq::resolve_ip_interface (sockaddr_storage* addr_, socklen_t *addr_len_,      sockaddr *out_addr = (sockaddr *) &ss;      socklen_t out_addrlen; -    //  Initialise IPv4-format family/port. -    sockaddr_in ip4_addr; -    memset (&ip4_addr, 0, sizeof (ip4_addr)); -    ip4_addr.sin_family = AF_INET; -    ip4_addr.sin_port = sin_port; -    ip4_addr.sin_addr.s_addr = htonl (INADDR_ANY); - -    //  Populate temporary output pointers with ip4_addr. -    out_addrlen = (socklen_t) sizeof (ip4_addr); -    memcpy (out_addr, &ip4_addr, out_addrlen); +    //  Initialise IP-format family/port and populate temporary output pointers +    //  with the address. +    if (ipv4only_) { +        sockaddr_in ip4_addr; +        memset (&ip4_addr, 0, sizeof (ip4_addr)); +        ip4_addr.sin_family = AF_INET; +        ip4_addr.sin_port = sin_port; +        ip4_addr.sin_addr.s_addr = htonl (INADDR_ANY); +        out_addrlen = (socklen_t) sizeof (ip4_addr); +        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) {          zmq_assert (out_addrlen <= (socklen_t) sizeof (*addr_));          memcpy (addr_, out_addr, out_addrlen); @@ -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. -    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)          return rc;      if (rc == 0) { @@ -281,8 +290,9 @@ int zmq::resolve_ip_interface (sockaddr_storage* addr_, socklen_t *addr_len_,  #endif      memset (&req, 0, sizeof (req)); -    //  We only support IPv4 addresses for now. -    req.ai_family = AF_INET; +    //  Choose IPv4 or IPv6 protocol family. Note that IPv6 allows for +    //  IPv4-in-IPv6 addresses. +    req.ai_family = ipv4only_ ? AF_INET : AF_INET6;      //  Arbitrary, not used in the output, but avoids duplicate results.      req.ai_socktype = SOCK_STREAM; @@ -291,6 +301,15 @@ int zmq::resolve_ip_interface (sockaddr_storage* addr_, socklen_t *addr_len_,      //  service-name irregularity due to indeterminate socktype.      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      //  of error, however, there's no way to report EAI errors via errno.      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_,  }  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.      const char *delimiter = strrchr (hostname_, ':'); @@ -329,8 +348,9 @@ int zmq::resolve_ip_hostname (sockaddr_storage *addr_, socklen_t *addr_len_,      addrinfo req;      memset (&req, 0, sizeof (req)); -    //  We only support IPv4 addresses for now. -    req.ai_family = AF_INET; +    //  Choose IPv4 or IPv6 protocol family. Note that IPv6 allows for +    //  IPv4-in-IPv6 addresses. +    req.ai_family = ipv4only_ ? AF_INET : AF_INET6;      //  Need to choose one to avoid duplicate results from getaddrinfo() - this      //  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_,      //  Avoid named services due to unclear socktype.      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,      //  however, there's no way to report EAI errors via errno.      addrinfo *res; @@ -51,12 +51,12 @@ namespace zmq      //  Resolves network interface name in <nic-name>:<port> format. Symbol "*"      //  (asterisk) resolves to INADDR_ANY (all network interfaces).      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.      //  Hostname can be either the name of the host or its IP address.      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.      int resolve_local_path (sockaddr_storage *addr_, socklen_t *addr_len_, diff --git a/src/tcp_connecter.cpp b/src/tcp_connecter.cpp index bca7085..6badaea 100644 --- a/src/tcp_connecter.cpp +++ b/src/tcp_connecter.cpp @@ -179,7 +179,7 @@ int zmq::tcp_connecter_t::get_new_reconnect_ivl ()  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 () diff --git a/src/tcp_listener.cpp b/src/tcp_listener.cpp index a5c6513..7dae4d1 100644 --- a/src/tcp_listener.cpp +++ b/src/tcp_listener.cpp @@ -123,7 +123,7 @@ void zmq::tcp_listener_t::close ()  int zmq::tcp_listener_t::set_address (const char *addr_)  {      //  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)          return -1; diff --git a/src/vtcp_connecter.cpp b/src/vtcp_connecter.cpp index 5c72044..f281b23 100644 --- a/src/vtcp_connecter.cpp +++ b/src/vtcp_connecter.cpp @@ -92,7 +92,8 @@ int zmq::vtcp_connecter_t::set_address (const char *addr_)          addr_str += ":9220";          std::string subport_str (delimiter + 1);          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)              return -1;      } @@ -100,7 +101,8 @@ int zmq::vtcp_connecter_t::set_address (const char *addr_)          std::string addr_str (addr_, delimiter - addr_);          std::string subport_str (delimiter + 1);          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)              return -1;      }  | 
