LCOV - code coverage report
Current view: top level - home/h/core/forks/m4-libzmq/src - tcp_address.cpp (source / functions) Hit Total Coverage
Test: zeromq-4.2.0 Code Coverage Lines: 139 226 61.5 %
Date: 2016-05-09 Functions: 15 20 75.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :     Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
       3             : 
       4             :     This file is part of libzmq, the ZeroMQ core engine in C++.
       5             : 
       6             :     libzmq is free software; you can redistribute it and/or modify it under
       7             :     the terms of the GNU Lesser General Public License (LGPL) as published
       8             :     by the Free Software Foundation; either version 3 of the License, or
       9             :     (at your option) any later version.
      10             : 
      11             :     As a special exception, the Contributors give you permission to link
      12             :     this library with independent modules to produce an executable,
      13             :     regardless of the license terms of these independent modules, and to
      14             :     copy and distribute the resulting executable under terms of your choice,
      15             :     provided that you also meet, for each linked independent module, the
      16             :     terms and conditions of the license of that module. An independent
      17             :     module is a module which is not derived from or based on this library.
      18             :     If you modify this library, you must extend this exception to your
      19             :     version of the library.
      20             : 
      21             :     libzmq is distributed in the hope that it will be useful, but WITHOUT
      22             :     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      23             :     FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
      24             :     License for more details.
      25             : 
      26             :     You should have received a copy of the GNU Lesser General Public License
      27             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      28             : */
      29             : 
      30             : #include "precompiled.hpp"
      31             : #include <string>
      32             : #include <sstream>
      33             : 
      34             : #include "macros.hpp"
      35             : #include "tcp_address.hpp"
      36             : #include "stdint.hpp"
      37             : #include "err.hpp"
      38             : #include "ip.hpp"
      39             : 
      40             : #ifndef ZMQ_HAVE_WINDOWS
      41             : #include <sys/types.h>
      42             : #include <arpa/inet.h>
      43             : #include <netinet/tcp.h>
      44             : #include <net/if.h>
      45             : #include <netdb.h>
      46             : #include <ctype.h>
      47             : #include <unistd.h>
      48             : #include <stdlib.h>
      49             : #endif
      50             : 
      51             : #ifdef ZMQ_HAVE_SOLARIS
      52             : #include <sys/sockio.h>
      53             : 
      54             : //  On Solaris platform, network interface name can be queried by ioctl.
      55             : int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv6_, bool is_src_)
      56             : {
      57             :     //  TODO: Unused parameter, IPv6 support not implemented for Solaris.
      58             :     LIBZMQ_UNUSED (ipv6_);
      59             : 
      60             :     //  Create a socket.
      61             :     const int fd = open_socket (AF_INET, SOCK_DGRAM, 0);
      62             :     errno_assert (fd != -1);
      63             : 
      64             :     //  Retrieve number of interfaces.
      65             :     lifnum ifn;
      66             :     ifn.lifn_family = AF_INET;
      67             :     ifn.lifn_flags = 0;
      68             :     int rc = ioctl (fd, SIOCGLIFNUM, (char*) &ifn);
      69             :     errno_assert (rc != -1);
      70             : 
      71             :     //  Allocate memory to get interface names.
      72             :     const size_t ifr_size = sizeof (struct lifreq) * ifn.lifn_count;
      73             :     char *ifr = (char*) malloc (ifr_size);
      74             :     alloc_assert (ifr);
      75             : 
      76             :     //  Retrieve interface names.
      77             :     lifconf ifc;
      78             :     ifc.lifc_family = AF_INET;
      79             :     ifc.lifc_flags = 0;
      80             :     ifc.lifc_len = ifr_size;
      81             :     ifc.lifc_buf = ifr;
      82             :     rc = ioctl (fd, SIOCGLIFCONF, (char*) &ifc);
      83             :     errno_assert (rc != -1);
      84             : 
      85             :     //  Find the interface with the specified name and AF_INET family.
      86             :     bool found = false;
      87             :     lifreq *ifrp = ifc.lifc_req;
      88             :     for (int n = 0; n < (int) (ifc.lifc_len / sizeof (lifreq));
      89             :           n ++, ifrp ++) {
      90             :         if (!strcmp (nic_, ifrp->lifr_name)) {
      91             :             rc = ioctl (fd, SIOCGLIFADDR, (char*) ifrp);
      92             :             errno_assert (rc != -1);
      93             :             if (ifrp->lifr_addr.ss_family == AF_INET) {
      94             :                 if (is_src_)
      95             :                     source_address.ipv4 = *(sockaddr_in*) &ifrp->lifr_addr;
      96             :                 else
      97             :                     address.ipv4 = *(sockaddr_in*) &ifrp->lifr_addr;
      98             :                 found = true;
      99             :                 break;
     100             :             }
     101             :         }
     102             :     }
     103             : 
     104             :     //  Clean-up.
     105             :     free (ifr);
     106             :     close (fd);
     107             : 
     108             :     if (!found) {
     109             :         errno = ENODEV;
     110             :         return -1;
     111             :     }
     112             :     return 0;
     113             : }
     114             : 
     115             : #elif defined ZMQ_HAVE_AIX || defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_ANDROID
     116             : #include <sys/ioctl.h>
     117             : 
     118             : int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv6_, bool is_src_)
     119             : {
     120             : #if defined ZMQ_HAVE_AIX || defined ZMQ_HAVE_HPUX
     121             :     // IPv6 support not implemented for AIX or HP/UX.
     122             :     if (ipv6_)
     123             :     {
     124             :         errno = ENODEV;
     125             :         return -1;
     126             :     }
     127             : #endif
     128             : 
     129             :     //  Create a socket.
     130             :     const int sd = open_socket (ipv6_ ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
     131             :     errno_assert (sd != -1);
     132             : 
     133             :     struct ifreq ifr;
     134             : 
     135             :     //  Copy interface name for ioctl get.
     136             :     strncpy (ifr.ifr_name, nic_, sizeof (ifr.ifr_name) );
     137             : 
     138             :     //  Fetch interface address.
     139             :     const int rc = ioctl (sd, SIOCGIFADDR, (caddr_t) &ifr, sizeof (ifr) );
     140             : 
     141             :     //  Clean up.
     142             :     close (sd);
     143             : 
     144             :     if (rc == -1) {
     145             :         errno = ENODEV;
     146             :         return -1;
     147             :     }
     148             : 
     149             :     const int family = ifr.ifr_addr.sa_family;
     150             :     if ((family == AF_INET || (ipv6_ && family == AF_INET6))
     151             :         && !strcmp (nic_, ifr.ifr_name))
     152             :     {
     153             :         if (is_src_)
     154             :             memcpy (&source_address, &ifr.ifr_addr,
     155             :                     (family == AF_INET) ? sizeof (struct sockaddr_in)
     156             :                                         : sizeof (struct sockaddr_in6));
     157             :         else
     158             :             memcpy (&address, &ifr.ifr_addr,
     159             :                     (family == AF_INET) ? sizeof (struct sockaddr_in)
     160             :                                         : sizeof (struct sockaddr_in6));
     161             :     }
     162             :     else
     163             :     {
     164             :         errno = ENODEV;
     165             :         return -1;
     166             :     }
     167             : 
     168             :     return 0;
     169             : }
     170             : 
     171             : #elif ((defined ZMQ_HAVE_LINUX || defined ZMQ_HAVE_FREEBSD ||\
     172             :     defined ZMQ_HAVE_OSX || defined ZMQ_HAVE_OPENBSD ||\
     173             :     defined ZMQ_HAVE_QNXNTO || defined ZMQ_HAVE_NETBSD ||\
     174             :     defined ZMQ_HAVE_DRAGONFLY || defined ZMQ_HAVE_GNU)\
     175             :     && defined ZMQ_HAVE_IFADDRS)
     176             : 
     177             : #include <ifaddrs.h>
     178             : 
     179             : //  On these platforms, network interface name can be queried
     180             : //  using getifaddrs function.
     181         285 : int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv6_, bool is_src_)
     182             : {
     183             :     //  Get the addresses.
     184         285 :     ifaddrs *ifa = NULL;
     185         285 :     const int rc = getifaddrs (&ifa);
     186         285 :     errno_assert (rc == 0);
     187         285 :     zmq_assert (ifa != NULL);
     188             : 
     189             :     //  Find the corresponding network interface.
     190         285 :     bool found = false;
     191        2265 :     for (ifaddrs *ifp = ifa; ifp != NULL; ifp = ifp->ifa_next) {
     192        1983 :         if (ifp->ifa_addr == NULL)
     193             :             continue;
     194             : 
     195        1983 :         const int family = ifp->ifa_addr->sa_family;
     196        1983 :         if ((family == AF_INET || (ipv6_ && family == AF_INET6))
     197         603 :         && !strcmp (nic_, ifp->ifa_name)) {
     198           3 :             if (is_src_)
     199             :                 memcpy (&source_address, ifp->ifa_addr,
     200             :                         (family == AF_INET) ? sizeof (struct sockaddr_in)
     201           3 :                                             : sizeof (struct sockaddr_in6));
     202             :             else
     203             :                 memcpy (&address, ifp->ifa_addr,
     204             :                         (family == AF_INET) ? sizeof (struct sockaddr_in)
     205           0 :                                             : sizeof (struct sockaddr_in6));
     206             :             found = true;
     207             :             break;
     208             :         }
     209             :     }
     210             : 
     211             :     //  Clean-up;
     212         285 :     freeifaddrs (ifa);
     213             : 
     214         285 :     if (!found) {
     215         282 :         errno = ENODEV;
     216         282 :         return -1;
     217             :     }
     218             :     return 0;
     219             : }
     220             : 
     221             : #else
     222             : 
     223             : //  On other platforms we assume there are no sane interface names.
     224             : //  This is true especially of Windows.
     225             : int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv6_, bool is_src_)
     226             : {
     227             :     LIBZMQ_UNUSED (nic_);
     228             :     LIBZMQ_UNUSED (ipv6_);
     229             : 
     230             :     errno = ENODEV;
     231             :     return -1;
     232             : }
     233             : 
     234             : #endif
     235             : 
     236         291 : int zmq::tcp_address_t::resolve_interface (const char *interface_, bool ipv6_, bool is_src_)
     237             : {
     238             :     //  Initialize temporary output pointers with storage address.
     239             :     sockaddr_storage ss;
     240         291 :     sockaddr *out_addr = (sockaddr*) &ss;
     241             :     size_t out_addrlen;
     242             : 
     243             :     //  Initialise IP-format family/port and populate temporary output pointers
     244             :     //  with the address.
     245         291 :     if (ipv6_) {
     246             :         sockaddr_in6 ip6_addr;
     247             :         memset (&ip6_addr, 0, sizeof (ip6_addr) );
     248          15 :         ip6_addr.sin6_family = AF_INET6;
     249             :         memcpy (&ip6_addr.sin6_addr, &in6addr_any, sizeof (in6addr_any) );
     250          15 :         out_addrlen = sizeof (ip6_addr);
     251             :         memcpy (out_addr, &ip6_addr, out_addrlen);
     252             :     }
     253             :     else {
     254             :         sockaddr_in ip4_addr;
     255             :         memset (&ip4_addr, 0, sizeof (ip4_addr) );
     256         276 :         ip4_addr.sin_family = AF_INET;
     257             :         ip4_addr.sin_addr.s_addr = htonl (INADDR_ANY);
     258         276 :         out_addrlen = sizeof (ip4_addr);
     259             :         memcpy (out_addr, &ip4_addr, out_addrlen);
     260             :     }
     261             :     //  "*" resolves to INADDR_ANY or in6addr_any.
     262         291 :     if (strcmp (interface_, "*") == 0) {
     263           6 :         zmq_assert (out_addrlen <= sizeof (address) );
     264           6 :         if (is_src_)
     265           0 :             memcpy (&source_address, out_addr, out_addrlen);
     266             :         else
     267           6 :             memcpy (&address, out_addr, out_addrlen);
     268             :         return 0;
     269             :     }
     270             : 
     271             :     //  Try to resolve the string as a NIC name.
     272         285 :     int rc = resolve_nic_name (interface_, ipv6_, is_src_);
     273         285 :     if (rc == 0 || errno != ENODEV)
     274             :         return rc;
     275             : 
     276             :     //  There's no such interface name. Assume literal address.
     277             : #if defined ZMQ_HAVE_OPENVMS && defined __ia64
     278             :     __addrinfo64 *res = NULL;
     279             :     __addrinfo64 req;
     280             : #else
     281         282 :     addrinfo *res = NULL;
     282             :     addrinfo req;
     283             : #endif
     284             :     memset (&req, 0, sizeof (req) );
     285             : 
     286             :     //  Choose IPv4 or IPv6 protocol family. Note that IPv6 allows for
     287             :     //  IPv4-in-IPv6 addresses.
     288         282 :     req.ai_family = ipv6_? AF_INET6: AF_INET;
     289             : 
     290             :     //  Arbitrary, not used in the output, but avoids duplicate results.
     291         282 :     req.ai_socktype = SOCK_STREAM;
     292             : 
     293             :     //  Restrict hostname/service to literals to avoid any DNS lookups or
     294             :     //  service-name irregularity due to indeterminate socktype.
     295         282 :     req.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
     296             : 
     297             : #if defined AI_V4MAPPED && !defined ZMQ_HAVE_FREEBSD && !defined ZMQ_HAVE_DRAGONFLY
     298             :     //  In this API we only require IPv4-mapped addresses when
     299             :     //  no native IPv6 interfaces are available (~AI_ALL).
     300             :     //  This saves an additional DNS roundtrip for IPv4 addresses.
     301             :     //  Note: While the AI_V4MAPPED flag is defined on FreeBSD system,
     302             :     //  it is not supported here. See libzmq issue #331.
     303         282 :     if (req.ai_family == AF_INET6)
     304          12 :         req.ai_flags |= AI_V4MAPPED;
     305             : #endif
     306             : 
     307             :     //  Resolve the literal address. Some of the error info is lost in case
     308             :     //  of error, however, there's no way to report EAI errors via errno.
     309         282 :     rc = getaddrinfo (interface_, NULL, &req, &res);
     310         282 :     if (rc) {
     311           3 :         errno = ENODEV;
     312           3 :         return -1;
     313             :     }
     314             : 
     315             :     //  Use the first result.
     316         279 :     zmq_assert (res != NULL);
     317         279 :     zmq_assert ((size_t) res->ai_addrlen <= sizeof (address) );
     318         279 :     if (is_src_)
     319           3 :         memcpy (&source_address, res->ai_addr, res->ai_addrlen);
     320             :     else
     321         276 :         memcpy (&address, res->ai_addr, res->ai_addrlen);
     322             : 
     323             :     //  Cleanup getaddrinfo after copying the possibly referenced result.
     324         279 :     freeaddrinfo (res);
     325             : 
     326         279 :     return 0;
     327             : }
     328             : 
     329        3797 : int zmq::tcp_address_t::resolve_hostname (const char *hostname_, bool ipv6_, bool is_src_)
     330             : {
     331             :     //  Set up the query.
     332             : #if defined ZMQ_HAVE_OPENVMS && defined __ia64 && __INITIAL_POINTER_SIZE == 64
     333             :     __addrinfo64 req;
     334             : #else
     335             :     addrinfo req;
     336             : #endif
     337             :     memset (&req, 0, sizeof (req) );
     338             : 
     339             :     //  Choose IPv4 or IPv6 protocol family. Note that IPv6 allows for
     340             :     //  IPv4-in-IPv6 addresses.
     341        3797 :     req.ai_family = ipv6_? AF_INET6: AF_INET;
     342             : 
     343             :     //  Need to choose one to avoid duplicate results from getaddrinfo() - this
     344             :     //  doesn't really matter, since it's not included in the addr-output.
     345        3797 :     req.ai_socktype = SOCK_STREAM;
     346             : 
     347             : #if defined AI_V4MAPPED && !defined ZMQ_HAVE_FREEBSD && !defined ZMQ_HAVE_DRAGONFLY
     348             :     //  In this API we only require IPv4-mapped addresses when
     349             :     //  no native IPv6 interfaces are available.
     350             :     //  This saves an additional DNS roundtrip for IPv4 addresses.
     351             :     //  Note: While the AI_V4MAPPED flag is defined on FreeBSD system,
     352             :     //  it is not supported here. See libzmq issue #331.
     353        3797 :     if (req.ai_family == AF_INET6)
     354          18 :         req.ai_flags |= AI_V4MAPPED;
     355             : #endif
     356             : 
     357             :     //  Resolve host name. Some of the error info is lost in case of error,
     358             :     //  however, there's no way to report EAI errors via errno.
     359             : #if defined ZMQ_HAVE_OPENVMS && defined __ia64 && __INITIAL_POINTER_SIZE == 64
     360             :     __addrinfo64 *res;
     361             : #else
     362             :     addrinfo *res;
     363             : #endif
     364        3797 :     const int rc = getaddrinfo (hostname_, NULL, &req, &res);
     365        3797 :     if (rc) {
     366           3 :         switch (rc) {
     367             :         case EAI_MEMORY:
     368           0 :             errno = ENOMEM;
     369           0 :             break;
     370             :         default:
     371           3 :             errno = EINVAL;
     372           3 :             break;
     373             :         }
     374             :         return -1;
     375             :     }
     376             : 
     377             :     //  Copy first result to output addr with hostname and service.
     378        3794 :     zmq_assert ((size_t) res->ai_addrlen <= sizeof (address) );
     379        3794 :     if (is_src_)
     380           0 :         memcpy (&source_address, res->ai_addr, res->ai_addrlen);
     381             :     else
     382        3794 :         memcpy (&address, res->ai_addr, res->ai_addrlen);
     383             : 
     384        3794 :     freeaddrinfo (res);
     385             : 
     386        3794 :     return 0;
     387             : }
     388             : 
     389        4080 : zmq::tcp_address_t::tcp_address_t () :
     390        4080 :     _has_src_addr (false)
     391             : {
     392        4080 :     memset (&address, 0, sizeof (address) );
     393        4080 :     memset (&source_address, 0, sizeof (source_address) );
     394        4080 : }
     395             : 
     396         279 : zmq::tcp_address_t::tcp_address_t (const sockaddr *sa, socklen_t sa_len) :
     397         279 :     _has_src_addr (false)
     398             : {
     399         279 :     zmq_assert (sa && sa_len > 0);
     400             : 
     401         279 :     memset (&address, 0, sizeof (address) );
     402         279 :     memset (&source_address, 0, sizeof (source_address) );
     403         279 :     if (sa->sa_family == AF_INET && sa_len >= (socklen_t) sizeof (address.ipv4) )
     404         264 :         memcpy (&address.ipv4, sa, sizeof (address.ipv4) );
     405             :     else
     406          15 :     if (sa->sa_family == AF_INET6 && sa_len >= (socklen_t) sizeof (address.ipv6) )
     407          15 :         memcpy (&address.ipv6, sa, sizeof (address.ipv6) );
     408         279 : }
     409             : 
     410        4358 : zmq::tcp_address_t::~tcp_address_t ()
     411             : {
     412        4358 : }
     413             : 
     414        4092 : int zmq::tcp_address_t::resolve (const char *name_, bool local_, bool ipv6_, bool is_src_)
     415             : {
     416        4092 :     if (!is_src_) {
     417             :         // Test the ';' to know if we have a source address in name_
     418        4083 :         const char *src_delimiter = strrchr (name_, ';');
     419        4083 :         if (src_delimiter) {
     420           9 :             std::string src_name (name_, src_delimiter - name_);
     421          18 :             const int rc = resolve (src_name.c_str (), local_, ipv6_, true);
     422           9 :             if (rc != 0)
     423           3 :                 return -1;
     424           6 :             name_ = src_delimiter + 1;
     425           6 :             _has_src_addr = true;
     426             :         }
     427             :     }
     428             : 
     429             :     //  Find the ':' at end that separates address from the port number.
     430        4089 :     const char *delimiter = strrchr (name_, ':');
     431        4089 :     if (!delimiter) {
     432           0 :         errno = EINVAL;
     433           0 :         return -1;
     434             :     }
     435             : 
     436             :     //  Separate the address/port.
     437        4089 :     std::string addr_str (name_, delimiter - name_);
     438        4089 :     std::string port_str (delimiter + 1);
     439             : 
     440             :     //  Remove square brackets around the address, if any, as used in IPv6
     441        8193 :     if (addr_str.size () >= 2 && addr_str [0] == '[' &&
     442          42 :           addr_str [addr_str.size () - 1] == ']')
     443          42 :         addr_str = addr_str.substr (1, addr_str.size () - 2);
     444             : 
     445             :     // Test the '%' to know if we have an interface name / zone_id in the address
     446             :     // Reference: https://tools.ietf.org/html/rfc4007
     447        4089 :     std::size_t pos = addr_str.rfind("%");
     448        4089 :     uint32_t zone_id = 0;
     449        4089 :     if (pos != std::string::npos) {
     450           0 :         std::string if_str = addr_str.substr(pos + 1);
     451           0 :         addr_str = addr_str.substr(0, pos);
     452           0 :         if (isalpha (if_str.at (0)))
     453             : #if !defined ZMQ_HAVE_WINDOWS_TARGET_XP
     454           0 :             zone_id = if_nametoindex(if_str.c_str());
     455             : #else
     456             :             // The function 'if_nametoindex' is not supported on Windows XP.
     457             :             // If we are targeting XP using a vxxx_xp toolset then fail.
     458             :             // This is brutal as this code could be run on later windows clients
     459             :             // meaning the IPv6 zone_id cannot have an interface name.
     460             :             // This could be fixed with a runtime check.
     461             :             zone_id = 0;
     462             : #endif
     463             :         else
     464           0 :             zone_id = (uint32_t) atoi (if_str.c_str ());
     465           0 :         if (zone_id == 0) {
     466           0 :             errno = EINVAL;
     467           0 :             return -1;
     468             :         }
     469             : 
     470             :     }
     471             : 
     472             :     //  Allow 0 specifically, to detect invalid port error in atoi if not
     473             :     uint16_t port;
     474        8156 :     if (port_str == "*" || port_str == "0")
     475             :         //  Resolve wildcard to 0 to allow autoselection of port
     476             :         port = 0;
     477             :     else {
     478             :         //  Parse the port number (0 is not a valid port).
     479        8129 :         port = (uint16_t) atoi (port_str.c_str ());
     480        4064 :         if (port == 0) {
     481           0 :             errno = EINVAL;
     482           0 :             return -1;
     483             :         }
     484             :     }
     485             : 
     486             :     //  Resolve the IP address.
     487             :     int rc;
     488        4088 :     if (local_ || is_src_)
     489         582 :         rc = resolve_interface (addr_str.c_str (), ipv6_, is_src_);
     490             :     else
     491        7594 :         rc = resolve_hostname (addr_str.c_str (), ipv6_, is_src_);
     492        4089 :     if (rc != 0)
     493             :         return -1;
     494             : 
     495             :     //  Set the port into the address structure.
     496        4083 :     if (is_src_) {
     497           6 :         if (source_address.generic.sa_family == AF_INET6) {
     498           0 :             source_address.ipv6.sin6_port = htons (port);
     499           0 :             source_address.ipv6.sin6_scope_id = zone_id;
     500             :         }
     501             :         else
     502           6 :             source_address.ipv4.sin_port = htons (port);
     503             :     }
     504             :     else {
     505        4077 :         if (address.generic.sa_family == AF_INET6) {
     506          33 :             address.ipv6.sin6_port = htons (port);
     507          33 :             address.ipv6.sin6_scope_id = zone_id;
     508             :         }
     509             :         else
     510        4044 :             address.ipv4.sin_port = htons (port);
     511             :     }
     512             : 
     513             :     return 0;
     514             : }
     515             : 
     516         766 : int zmq::tcp_address_t::to_string (std::string &addr_)
     517             : {
     518         766 :     if (address.generic.sa_family != AF_INET
     519         766 :     &&  address.generic.sa_family != AF_INET6) {
     520             :         addr_.clear ();
     521           0 :         return -1;
     522             :     }
     523             : 
     524             :     //  Not using service resolving because of
     525             :     //  https://github.com/zeromq/libzmq/commit/1824574f9b5a8ce786853320e3ea09fe1f822bc4
     526             :     char hbuf [NI_MAXHOST];
     527         766 :     int rc = getnameinfo (addr (), addrlen (), hbuf, sizeof (hbuf), NULL, 0, NI_NUMERICHOST);
     528         766 :     if (rc != 0) {
     529             :         addr_.clear ();
     530           0 :         return rc;
     531             :     }
     532             : 
     533         766 :     if (address.generic.sa_family == AF_INET6) {
     534          33 :         std::stringstream s;
     535          33 :         s << "tcp://[" << hbuf << "]:" << ntohs (address.ipv6.sin6_port);
     536          33 :         addr_ = s.str ();
     537             :     }
     538             :     else {
     539         733 :         std::stringstream s;
     540         733 :         s << "tcp://" << hbuf << ":" << ntohs (address.ipv4.sin_port);
     541         733 :         addr_ = s.str ();
     542             :     }
     543             :     return 0;
     544             : }
     545             : 
     546        4056 : const sockaddr *zmq::tcp_address_t::addr () const
     547             : {
     548        4056 :     return &address.generic;
     549             : }
     550             : 
     551        4056 : socklen_t zmq::tcp_address_t::addrlen () const
     552             : {
     553        4822 :     if (address.generic.sa_family == AF_INET6)
     554             :         return (socklen_t) sizeof (address.ipv6);
     555             :     else
     556        4026 :         return (socklen_t) sizeof (address.ipv4);
     557             : }
     558             : 
     559           6 : const sockaddr *zmq::tcp_address_t::src_addr () const
     560             : {
     561           6 :     return &source_address.generic;
     562             : }
     563             : 
     564           6 : socklen_t zmq::tcp_address_t::src_addrlen () const
     565             : {
     566           6 :     if (address.generic.sa_family == AF_INET6)
     567             :         return (socklen_t) sizeof (source_address.ipv6);
     568             :     else
     569           6 :         return (socklen_t) sizeof (source_address.ipv4);
     570             : }
     571             : 
     572        3789 : bool zmq::tcp_address_t::has_src_addr () const
     573             : {
     574        3789 :     return _has_src_addr;
     575             : }
     576             : 
     577             : #if defined ZMQ_HAVE_WINDOWS
     578             : unsigned short zmq::tcp_address_t::family () const
     579             : #else
     580        8118 : sa_family_t zmq::tcp_address_t::family () const
     581             : #endif
     582             : {
     583        8118 :     return address.generic.sa_family;
     584             : }
     585             : 
     586           0 : zmq::tcp_address_mask_t::tcp_address_mask_t () :
     587             :     tcp_address_t (),
     588           0 :     address_mask (-1)
     589             : {
     590           0 : }
     591             : 
     592           0 : int zmq::tcp_address_mask_t::mask () const
     593             : {
     594           0 :     return address_mask;
     595             : }
     596             : 
     597           0 : int zmq::tcp_address_mask_t::resolve (const char *name_, bool ipv6_)
     598             : {
     599             :     // Find '/' at the end that separates address from the cidr mask number.
     600             :     // Allow empty mask clause and treat it like '/32' for ipv4 or '/128' for ipv6.
     601             :     std::string addr_str, mask_str;
     602           0 :     const char *delimiter = strrchr (name_, '/');
     603           0 :     if (delimiter != NULL) {
     604           0 :         addr_str.assign (name_, delimiter - name_);
     605           0 :         mask_str.assign (delimiter + 1);
     606           0 :         if (mask_str.empty ()) {
     607           0 :             errno = EINVAL;
     608           0 :             return -1;
     609             :         }
     610             :     }
     611             :     else
     612           0 :         addr_str.assign (name_);
     613             : 
     614             :     // Parse address part using standard routines.
     615             :     const int rc =
     616           0 :         tcp_address_t::resolve_hostname (addr_str.c_str (), ipv6_);
     617           0 :     if (rc != 0)
     618             :         return rc;
     619             : 
     620             :     // Parse the cidr mask number.
     621           0 :     if (mask_str.empty ()) {
     622           0 :         if (address.generic.sa_family == AF_INET6)
     623           0 :             address_mask = 128;
     624             :         else
     625           0 :             address_mask = 32;
     626             :     }
     627             :     else
     628           0 :     if (mask_str == "0")
     629           0 :         address_mask = 0;
     630             :     else {
     631           0 :         const int mask = atoi (mask_str.c_str ());
     632           0 :         if (
     633           0 :             (mask < 1) ||
     634           0 :             (address.generic.sa_family == AF_INET6 && mask > 128) ||
     635           0 :             (address.generic.sa_family != AF_INET6 && mask > 32)
     636             :         ) {
     637           0 :             errno = EINVAL;
     638           0 :             return -1;
     639             :         }
     640           0 :         address_mask = mask;
     641             :     }
     642             : 
     643             :     return 0;
     644             : }
     645             : 
     646           0 : int zmq::tcp_address_mask_t::to_string (std::string &addr_)
     647             : {
     648           0 :     if (address.generic.sa_family != AF_INET
     649           0 :     &&  address.generic.sa_family != AF_INET6) {
     650             :         addr_.clear ();
     651           0 :         return -1;
     652             :     }
     653           0 :     if (address_mask == -1) {
     654             :         addr_.clear ();
     655           0 :         return -1;
     656             :     }
     657             : 
     658             :     char hbuf [NI_MAXHOST];
     659           0 :     int rc = getnameinfo (addr (), addrlen (), hbuf, sizeof (hbuf), NULL, 0, NI_NUMERICHOST);
     660           0 :     if (rc != 0) {
     661             :         addr_.clear ();
     662           0 :         return rc;
     663             :     }
     664             : 
     665           0 :     if (address.generic.sa_family == AF_INET6) {
     666           0 :         std::stringstream s;
     667           0 :         s << "[" << hbuf << "]/" << address_mask;
     668           0 :         addr_ = s.str ();
     669             :     }
     670             :     else {
     671           0 :         std::stringstream s;
     672           0 :         s << hbuf << "/" << address_mask;
     673           0 :         addr_ = s.str ();
     674             :     }
     675             :     return 0;
     676             : }
     677             : 
     678           0 : bool zmq::tcp_address_mask_t::match_address (const struct sockaddr *ss, const socklen_t ss_len) const
     679             : {
     680           0 :     zmq_assert (address_mask != -1
     681             :              && ss != NULL
     682             :              && ss_len >= (socklen_t) sizeof (struct sockaddr));
     683             : 
     684           0 :     if (ss->sa_family != address.generic.sa_family)
     685             :         return false;
     686             : 
     687           0 :     if (address_mask > 0) {
     688             :         int mask;
     689             :         const uint8_t *our_bytes, *their_bytes;
     690           0 :         if (ss->sa_family == AF_INET6) {
     691           0 :             zmq_assert (ss_len == sizeof (struct sockaddr_in6));
     692           0 :             their_bytes = (const uint8_t *) &(((const struct sockaddr_in6 *) ss)->sin6_addr);
     693           0 :             our_bytes = (const uint8_t *) &address.ipv6.sin6_addr;
     694           0 :             mask = sizeof (struct in6_addr) * 8;
     695             :         }
     696             :         else {
     697           0 :             zmq_assert (ss_len == sizeof (struct sockaddr_in));
     698           0 :             their_bytes = (const uint8_t *) &(((const struct sockaddr_in *) ss)->sin_addr);
     699           0 :             our_bytes = (const uint8_t *) &address.ipv4.sin_addr;
     700           0 :             mask = sizeof (struct in_addr) * 8;
     701             :         }
     702           0 :         if (address_mask < mask)
     703           0 :             mask = address_mask;
     704             : 
     705           0 :         const size_t full_bytes = mask / 8;
     706           0 :         if (memcmp (our_bytes, their_bytes, full_bytes))
     707             :             return false;
     708             : 
     709           0 :         const uint8_t last_byte_bits = 0xffU << (8 - mask % 8);
     710           0 :         if (last_byte_bits) {
     711           0 :             if ((their_bytes [full_bytes] & last_byte_bits) != (our_bytes [full_bytes] & last_byte_bits))
     712             :                 return false;
     713             :         }
     714             :     }
     715             : 
     716             :     return true;
     717             : }

Generated by: LCOV version 1.10