libzmq  master
ZeroMQ C++ Core Engine (LIBZMQ)
tcp_address.cpp
Go to the documentation of this file.
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 int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv6_, bool is_src_)
182 {
183  // Get the addresses.
184  ifaddrs *ifa = NULL;
185  const int rc = getifaddrs (&ifa);
186  errno_assert (rc == 0);
187  zmq_assert (ifa != NULL);
188 
189  // Find the corresponding network interface.
190  bool found = false;
191  for (ifaddrs *ifp = ifa; ifp != NULL; ifp = ifp->ifa_next) {
192  if (ifp->ifa_addr == NULL)
193  continue;
194 
195  const int family = ifp->ifa_addr->sa_family;
196  if ((family == AF_INET || (ipv6_ && family == AF_INET6))
197  && !strcmp (nic_, ifp->ifa_name)) {
198  if (is_src_)
199  memcpy (&source_address, ifp->ifa_addr,
200  (family == AF_INET) ? sizeof (struct sockaddr_in)
201  : sizeof (struct sockaddr_in6));
202  else
203  memcpy (&address, ifp->ifa_addr,
204  (family == AF_INET) ? sizeof (struct sockaddr_in)
205  : sizeof (struct sockaddr_in6));
206  found = true;
207  break;
208  }
209  }
210 
211  // Clean-up;
212  freeifaddrs (ifa);
213 
214  if (!found) {
215  errno = ENODEV;
216  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 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  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  if (ipv6_) {
246  sockaddr_in6 ip6_addr;
247  memset (&ip6_addr, 0, sizeof (ip6_addr) );
248  ip6_addr.sin6_family = AF_INET6;
249  memcpy (&ip6_addr.sin6_addr, &in6addr_any, sizeof (in6addr_any) );
250  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  ip4_addr.sin_family = AF_INET;
257  ip4_addr.sin_addr.s_addr = htonl (INADDR_ANY);
258  out_addrlen = sizeof (ip4_addr);
259  memcpy (out_addr, &ip4_addr, out_addrlen);
260  }
261  // "*" resolves to INADDR_ANY or in6addr_any.
262  if (strcmp (interface_, "*") == 0) {
263  zmq_assert (out_addrlen <= sizeof (address) );
264  if (is_src_)
265  memcpy (&source_address, out_addr, out_addrlen);
266  else
267  memcpy (&address, out_addr, out_addrlen);
268  return 0;
269  }
270 
271  // Try to resolve the string as a NIC name.
272  int rc = resolve_nic_name (interface_, ipv6_, is_src_);
273  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  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  req.ai_family = ipv6_? AF_INET6: AF_INET;
289 
290  // Arbitrary, not used in the output, but avoids duplicate results.
291  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  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  if (req.ai_family == AF_INET6)
304  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  rc = getaddrinfo (interface_, NULL, &req, &res);
310  if (rc) {
311  errno = ENODEV;
312  return -1;
313  }
314 
315  // Use the first result.
316  zmq_assert (res != NULL);
317  zmq_assert ((size_t) res->ai_addrlen <= sizeof (address) );
318  if (is_src_)
319  memcpy (&source_address, res->ai_addr, res->ai_addrlen);
320  else
321  memcpy (&address, res->ai_addr, res->ai_addrlen);
322 
323  // Cleanup getaddrinfo after copying the possibly referenced result.
324  freeaddrinfo (res);
325 
326  return 0;
327 }
328 
329 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  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  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  if (req.ai_family == AF_INET6)
354  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  const int rc = getaddrinfo (hostname_, NULL, &req, &res);
365  if (rc) {
366  switch (rc) {
367  case EAI_MEMORY:
368  errno = ENOMEM;
369  break;
370  default:
371  errno = EINVAL;
372  break;
373  }
374  return -1;
375  }
376 
377  // Copy first result to output addr with hostname and service.
378  zmq_assert ((size_t) res->ai_addrlen <= sizeof (address) );
379  if (is_src_)
380  memcpy (&source_address, res->ai_addr, res->ai_addrlen);
381  else
382  memcpy (&address, res->ai_addr, res->ai_addrlen);
383 
384  freeaddrinfo (res);
385 
386  return 0;
387 }
388 
390  _has_src_addr (false)
391 {
392  memset (&address, 0, sizeof (address) );
393  memset (&source_address, 0, sizeof (source_address) );
394 }
395 
396 zmq::tcp_address_t::tcp_address_t (const sockaddr *sa, socklen_t sa_len) :
397  _has_src_addr (false)
398 {
399  zmq_assert (sa && sa_len > 0);
400 
401  memset (&address, 0, sizeof (address) );
402  memset (&source_address, 0, sizeof (source_address) );
403  if (sa->sa_family == AF_INET && sa_len >= (socklen_t) sizeof (address.ipv4) )
404  memcpy (&address.ipv4, sa, sizeof (address.ipv4) );
405  else
406  if (sa->sa_family == AF_INET6 && sa_len >= (socklen_t) sizeof (address.ipv6) )
407  memcpy (&address.ipv6, sa, sizeof (address.ipv6) );
408 }
409 
411 {
412 }
413 
414 int zmq::tcp_address_t::resolve (const char *name_, bool local_, bool ipv6_, bool is_src_)
415 {
416  if (!is_src_) {
417  // Test the ';' to know if we have a source address in name_
418  const char *src_delimiter = strrchr (name_, ';');
419  if (src_delimiter) {
420  std::string src_name (name_, src_delimiter - name_);
421  const int rc = resolve (src_name.c_str (), local_, ipv6_, true);
422  if (rc != 0)
423  return -1;
424  name_ = src_delimiter + 1;
425  _has_src_addr = true;
426  }
427  }
428 
429  // Find the ':' at end that separates address from the port number.
430  const char *delimiter = strrchr (name_, ':');
431  if (!delimiter) {
432  errno = EINVAL;
433  return -1;
434  }
435 
436  // Separate the address/port.
437  std::string addr_str (name_, delimiter - name_);
438  std::string port_str (delimiter + 1);
439 
440  // Remove square brackets around the address, if any, as used in IPv6
441  if (addr_str.size () >= 2 && addr_str [0] == '[' &&
442  addr_str [addr_str.size () - 1] == ']')
443  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  std::size_t pos = addr_str.rfind("%");
448  uint32_t zone_id = 0;
449  if (pos != std::string::npos) {
450  std::string if_str = addr_str.substr(pos + 1);
451  addr_str = addr_str.substr(0, pos);
452  if (isalpha (if_str.at (0)))
453 #if !defined ZMQ_HAVE_WINDOWS_TARGET_XP
454  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  zone_id = (uint32_t) atoi (if_str.c_str ());
465  if (zone_id == 0) {
466  errno = EINVAL;
467  return -1;
468  }
469 
470  }
471 
472  // Allow 0 specifically, to detect invalid port error in atoi if not
473  uint16_t port;
474  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  port = (uint16_t) atoi (port_str.c_str ());
480  if (port == 0) {
481  errno = EINVAL;
482  return -1;
483  }
484  }
485 
486  // Resolve the IP address.
487  int rc;
488  if (local_ || is_src_)
489  rc = resolve_interface (addr_str.c_str (), ipv6_, is_src_);
490  else
491  rc = resolve_hostname (addr_str.c_str (), ipv6_, is_src_);
492  if (rc != 0)
493  return -1;
494 
495  // Set the port into the address structure.
496  if (is_src_) {
497  if (source_address.generic.sa_family == AF_INET6) {
498  source_address.ipv6.sin6_port = htons (port);
499  source_address.ipv6.sin6_scope_id = zone_id;
500  }
501  else
502  source_address.ipv4.sin_port = htons (port);
503  }
504  else {
505  if (address.generic.sa_family == AF_INET6) {
506  address.ipv6.sin6_port = htons (port);
507  address.ipv6.sin6_scope_id = zone_id;
508  }
509  else
510  address.ipv4.sin_port = htons (port);
511  }
512 
513  return 0;
514 }
515 
516 int zmq::tcp_address_t::to_string (std::string &addr_)
517 {
518  if (address.generic.sa_family != AF_INET
519  && address.generic.sa_family != AF_INET6) {
520  addr_.clear ();
521  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  int rc = getnameinfo (addr (), addrlen (), hbuf, sizeof (hbuf), NULL, 0, NI_NUMERICHOST);
528  if (rc != 0) {
529  addr_.clear ();
530  return rc;
531  }
532 
533  if (address.generic.sa_family == AF_INET6) {
534  std::stringstream s;
535  s << "tcp://[" << hbuf << "]:" << ntohs (address.ipv6.sin6_port);
536  addr_ = s.str ();
537  }
538  else {
539  std::stringstream s;
540  s << "tcp://" << hbuf << ":" << ntohs (address.ipv4.sin_port);
541  addr_ = s.str ();
542  }
543  return 0;
544 }
545 
546 const sockaddr *zmq::tcp_address_t::addr () const
547 {
548  return &address.generic;
549 }
550 
551 socklen_t zmq::tcp_address_t::addrlen () const
552 {
553  if (address.generic.sa_family == AF_INET6)
554  return (socklen_t) sizeof (address.ipv6);
555  else
556  return (socklen_t) sizeof (address.ipv4);
557 }
558 
559 const sockaddr *zmq::tcp_address_t::src_addr () const
560 {
561  return &source_address.generic;
562 }
563 
565 {
566  if (address.generic.sa_family == AF_INET6)
567  return (socklen_t) sizeof (source_address.ipv6);
568  else
569  return (socklen_t) sizeof (source_address.ipv4);
570 }
571 
573 {
574  return _has_src_addr;
575 }
576 
577 #if defined ZMQ_HAVE_WINDOWS
578 unsigned short zmq::tcp_address_t::family () const
579 #else
580 sa_family_t zmq::tcp_address_t::family () const
581 #endif
582 {
583  return address.generic.sa_family;
584 }
585 
587  tcp_address_t (),
588  address_mask (-1)
589 {
590 }
591 
593 {
594  return address_mask;
595 }
596 
597 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  const char *delimiter = strrchr (name_, '/');
603  if (delimiter != NULL) {
604  addr_str.assign (name_, delimiter - name_);
605  mask_str.assign (delimiter + 1);
606  if (mask_str.empty ()) {
607  errno = EINVAL;
608  return -1;
609  }
610  }
611  else
612  addr_str.assign (name_);
613 
614  // Parse address part using standard routines.
615  const int rc =
616  tcp_address_t::resolve_hostname (addr_str.c_str (), ipv6_);
617  if (rc != 0)
618  return rc;
619 
620  // Parse the cidr mask number.
621  if (mask_str.empty ()) {
622  if (address.generic.sa_family == AF_INET6)
623  address_mask = 128;
624  else
625  address_mask = 32;
626  }
627  else
628  if (mask_str == "0")
629  address_mask = 0;
630  else {
631  const int mask = atoi (mask_str.c_str ());
632  if (
633  (mask < 1) ||
634  (address.generic.sa_family == AF_INET6 && mask > 128) ||
635  (address.generic.sa_family != AF_INET6 && mask > 32)
636  ) {
637  errno = EINVAL;
638  return -1;
639  }
640  address_mask = mask;
641  }
642 
643  return 0;
644 }
645 
646 int zmq::tcp_address_mask_t::to_string (std::string &addr_)
647 {
648  if (address.generic.sa_family != AF_INET
649  && address.generic.sa_family != AF_INET6) {
650  addr_.clear ();
651  return -1;
652  }
653  if (address_mask == -1) {
654  addr_.clear ();
655  return -1;
656  }
657 
658  char hbuf [NI_MAXHOST];
659  int rc = getnameinfo (addr (), addrlen (), hbuf, sizeof (hbuf), NULL, 0, NI_NUMERICHOST);
660  if (rc != 0) {
661  addr_.clear ();
662  return rc;
663  }
664 
665  if (address.generic.sa_family == AF_INET6) {
666  std::stringstream s;
667  s << "[" << hbuf << "]/" << address_mask;
668  addr_ = s.str ();
669  }
670  else {
671  std::stringstream s;
672  s << hbuf << "/" << address_mask;
673  addr_ = s.str ();
674  }
675  return 0;
676 }
677 
678 bool zmq::tcp_address_mask_t::match_address (const struct sockaddr *ss, const socklen_t ss_len) const
679 {
680  zmq_assert (address_mask != -1
681  && ss != NULL
682  && ss_len >= (socklen_t) sizeof (struct sockaddr));
683 
684  if (ss->sa_family != address.generic.sa_family)
685  return false;
686 
687  if (address_mask > 0) {
688  int mask;
689  const uint8_t *our_bytes, *their_bytes;
690  if (ss->sa_family == AF_INET6) {
691  zmq_assert (ss_len == sizeof (struct sockaddr_in6));
692  their_bytes = (const uint8_t *) &(((const struct sockaddr_in6 *) ss)->sin6_addr);
693  our_bytes = (const uint8_t *) &address.ipv6.sin6_addr;
694  mask = sizeof (struct in6_addr) * 8;
695  }
696  else {
697  zmq_assert (ss_len == sizeof (struct sockaddr_in));
698  their_bytes = (const uint8_t *) &(((const struct sockaddr_in *) ss)->sin_addr);
699  our_bytes = (const uint8_t *) &address.ipv4.sin_addr;
700  mask = sizeof (struct in_addr) * 8;
701  }
702  if (address_mask < mask)
703  mask = address_mask;
704 
705  const size_t full_bytes = mask / 8;
706  if (memcmp (our_bytes, their_bytes, full_bytes))
707  return false;
708 
709  const uint8_t last_byte_bits = 0xffU << (8 - mask % 8);
710  if (last_byte_bits) {
711  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 }
virtual int to_string(std::string &addr_)
int to_string(std::string &addr_)
fd_t open_socket(int domain_, int type_, int protocol_)
Definition: ip.cpp:50
#define zmq_assert(x)
Definition: err.hpp:119
int resolve_nic_name(const char *nic_, bool ipv6_, bool is_src_=false)
bool has_src_addr() const
socklen_t src_addrlen() const
int resolve(const char *name_, bool ipv6_)
int resolve_hostname(const char *hostname_, bool ipv6_, bool is_src_=false)
int resolve(const char *name_, bool local_, bool ipv6_, bool is_src_=false)
union zmq::tcp_address_t::@59 address
#define LIBZMQ_UNUSED(object)
Definition: macros.hpp:6
bool match_address(const struct sockaddr *ss, const socklen_t ss_len) const
virtual ~tcp_address_t()
const sockaddr * addr() const
socklen_t addrlen() const
sa_family_t family() const
#define alloc_assert(x)
Definition: err.hpp:159
#define errno_assert(x)
Definition: err.hpp:129
int resolve_interface(const char *interface_, bool ipv6_, bool is_src_=false)
union zmq::tcp_address_t::@60 source_address
const sockaddr * src_addr() const