![]() |
libzmq master
The Intelligent Transport Layer
|
00001 /* 00002 Copyright (c) 2009-2011 250bpm s.r.o. 00003 Copyright (c) 2007-2009 iMatix Corporation 00004 Copyright (c) 2007-2011 Other contributors as noted in the AUTHORS file 00005 00006 This file is part of 0MQ. 00007 00008 0MQ is free software; you can redistribute it and/or modify it under 00009 the terms of the GNU Lesser General Public License as published by 00010 the Free Software Foundation; either version 3 of the License, or 00011 (at your option) any later version. 00012 00013 0MQ is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU Lesser General Public License for more details. 00017 00018 You should have received a copy of the GNU Lesser General Public License 00019 along with this program. If not, see <http://www.gnu.org/licenses/>. 00020 */ 00021 00022 #include <string.h> 00023 #include <string> 00024 00025 #include "tcp_address.hpp" 00026 #include "platform.hpp" 00027 #include "stdint.hpp" 00028 #include "err.hpp" 00029 #include "ip.hpp" 00030 00031 #ifdef ZMQ_HAVE_WINDOWS 00032 #include "windows.hpp" 00033 #else 00034 #include <sys/types.h> 00035 #include <arpa/inet.h> 00036 #include <netinet/tcp.h> 00037 #include <netdb.h> 00038 #endif 00039 00040 // Some platforms (notably Darwin/OSX and NetBSD) do not define all AI_ 00041 // flags for getaddrinfo(). This can be worked around safely by defining 00042 // these to 0. 00043 #ifndef AI_ADDRCONFIG 00044 #define AI_ADDRCONFIG 0 00045 #endif 00046 00047 #if defined ZMQ_HAVE_SOLARIS 00048 00049 #include <sys/sockio.h> 00050 #include <net/if.h> 00051 #include <unistd.h> 00052 #include <stdlib.h> 00053 00054 // On Solaris platform, network interface name can be queried by ioctl. 00055 int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv4only_) 00056 { 00057 // TODO: Unused parameter, IPv6 support not implemented for Solaris. 00058 (void) ipv4only_; 00059 00060 // Create a socket. 00061 int fd = open_socket (AF_INET, SOCK_DGRAM, 0); 00062 zmq_assert (fd != -1); 00063 00064 // Retrieve number of interfaces. 00065 lifnum ifn; 00066 ifn.lifn_family = AF_INET; 00067 ifn.lifn_flags = 0; 00068 int rc = ioctl (fd, SIOCGLIFNUM, (char*) &ifn); 00069 zmq_assert (rc != -1); 00070 00071 // Allocate memory to get interface names. 00072 size_t ifr_size = sizeof (struct lifreq) * ifn.lifn_count; 00073 char *ifr = (char*) malloc (ifr_size); 00074 alloc_assert (ifr); 00075 00076 // Retrieve interface names. 00077 lifconf ifc; 00078 ifc.lifc_family = AF_INET; 00079 ifc.lifc_flags = 0; 00080 ifc.lifc_len = ifr_size; 00081 ifc.lifc_buf = ifr; 00082 rc = ioctl (fd, SIOCGLIFCONF, (char*) &ifc); 00083 zmq_assert (rc != -1); 00084 00085 // Find the interface with the specified name and AF_INET family. 00086 bool found = false; 00087 lifreq *ifrp = ifc.lifc_req; 00088 for (int n = 0; n < (int) (ifc.lifc_len / sizeof (lifreq)); 00089 n ++, ifrp ++) { 00090 if (!strcmp (nic_, ifrp->lifr_name)) { 00091 rc = ioctl (fd, SIOCGLIFADDR, (char*) ifrp); 00092 zmq_assert (rc != -1); 00093 if (ifrp->lifr_addr.ss_family == AF_INET) { 00094 address.ipv4 = *(sockaddr_in*) &ifrp->lifr_addr; 00095 found = true; 00096 break; 00097 } 00098 } 00099 } 00100 00101 // Clean-up. 00102 free (ifr); 00103 close (fd); 00104 00105 if (!found) { 00106 errno = ENODEV; 00107 return -1; 00108 } 00109 00110 return 0; 00111 } 00112 00113 #elif defined ZMQ_HAVE_AIX || ZMQ_HAVE_HPUX || ZMQ_HAVE_ANDROID 00114 00115 #include <sys/types.h> 00116 #include <unistd.h> 00117 #include <sys/ioctl.h> 00118 #include <net/if.h> 00119 00120 int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv4only_) 00121 { 00122 // TODO: Unused parameter, IPv6 support not implemented for AIX or HP/UX. 00123 (void) ipv4only_; 00124 00125 // Create a socket. 00126 int sd = open_socket (AF_INET, SOCK_DGRAM, 0); 00127 zmq_assert (sd != -1); 00128 00129 struct ifreq ifr; 00130 00131 // Copy interface name for ioctl get. 00132 strncpy (ifr.ifr_name, nic_, sizeof (ifr.ifr_name)); 00133 00134 // Fetch interface address. 00135 int rc = ioctl (sd, SIOCGIFADDR, (caddr_t) &ifr, sizeof (struct ifreq)); 00136 00137 // Clean up. 00138 close (sd); 00139 00140 if (rc == -1) { 00141 errno = ENODEV; 00142 return -1; 00143 } 00144 00145 memcpy (&address.ipv4.sin_addr, &((sockaddr_in*) &ifr.ifr_addr)->sin_addr, 00146 sizeof (in_addr)); 00147 00148 return 0; 00149 } 00150 00151 #elif ((defined ZMQ_HAVE_LINUX || defined ZMQ_HAVE_FREEBSD ||\ 00152 defined ZMQ_HAVE_OSX || defined ZMQ_HAVE_OPENBSD ||\ 00153 defined ZMQ_HAVE_QNXNTO || defined ZMQ_HAVE_NETBSD)\ 00154 && defined ZMQ_HAVE_IFADDRS) 00155 00156 #include <ifaddrs.h> 00157 00158 // On these platforms, network interface name can be queried 00159 // using getifaddrs function. 00160 int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv4only_) 00161 { 00162 // Get the addresses. 00163 ifaddrs* ifa = NULL; 00164 int rc = getifaddrs (&ifa); 00165 zmq_assert (rc == 0); 00166 zmq_assert (ifa != NULL); 00167 00168 // Find the corresponding network interface. 00169 bool found = false; 00170 for (ifaddrs *ifp = ifa; ifp != NULL ;ifp = ifp->ifa_next) 00171 { 00172 if (ifp->ifa_addr == NULL) 00173 continue; 00174 00175 int family = ifp->ifa_addr->sa_family; 00176 00177 if ((family == AF_INET 00178 || (!ipv4only_ && family == AF_INET6)) 00179 && !strcmp (nic_, ifp->ifa_name)) 00180 { 00181 memcpy (&address, ifp->ifa_addr, 00182 (family == AF_INET) ? sizeof (struct sockaddr_in) 00183 : sizeof (struct sockaddr_in6)); 00184 found = true; 00185 break; 00186 } 00187 } 00188 00189 // Clean-up; 00190 freeifaddrs (ifa); 00191 00192 if (!found) { 00193 errno = ENODEV; 00194 return -1; 00195 } 00196 00197 return 0; 00198 } 00199 00200 #else 00201 00202 // On other platforms we assume there are no sane interface names. 00203 // This is true especially of Windows. 00204 int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv4only_) 00205 { 00206 // All unused parameters. 00207 (void) nic_; 00208 (void) ipv4only_; 00209 00210 errno = ENODEV; 00211 return -1; 00212 } 00213 00214 #endif 00215 00216 int zmq::tcp_address_t::resolve_interface (char const *interface_, 00217 bool ipv4only_) 00218 { 00219 // Initialize temporary output pointers with storage address. 00220 sockaddr_storage ss; 00221 sockaddr *out_addr = (sockaddr *) &ss; 00222 socklen_t out_addrlen; 00223 00224 // Initialise IP-format family/port and populate temporary output pointers 00225 // with the address. 00226 if (ipv4only_) { 00227 sockaddr_in ip4_addr; 00228 memset (&ip4_addr, 0, sizeof (ip4_addr)); 00229 ip4_addr.sin_family = AF_INET; 00230 ip4_addr.sin_addr.s_addr = htonl (INADDR_ANY); 00231 out_addrlen = (socklen_t) sizeof (ip4_addr); 00232 memcpy (out_addr, &ip4_addr, out_addrlen); 00233 } else { 00234 sockaddr_in6 ip6_addr; 00235 memset (&ip6_addr, 0, sizeof (ip6_addr)); 00236 ip6_addr.sin6_family = AF_INET6; 00237 memcpy (&ip6_addr.sin6_addr, &in6addr_any, sizeof (in6addr_any)); 00238 out_addrlen = (socklen_t) sizeof (ip6_addr); 00239 memcpy (out_addr, &ip6_addr, out_addrlen); 00240 } 00241 00242 // * resolves to INADDR_ANY or in6addr_any. 00243 if (strcmp (interface_, "*") == 0) { 00244 zmq_assert (out_addrlen <= (socklen_t) sizeof (address)); 00245 memcpy (&address, out_addr, out_addrlen); 00246 return 0; 00247 } 00248 00249 // Try to resolve the string as a NIC name. 00250 int rc = resolve_nic_name (interface_, ipv4only_); 00251 if (rc != 0 && errno != ENODEV) 00252 return rc; 00253 if (rc == 0) { 00254 zmq_assert (out_addrlen <= (socklen_t) sizeof (address)); 00255 memcpy (&address, out_addr, out_addrlen); 00256 return 0; 00257 } 00258 00259 // There's no such interface name. Assume literal address. 00260 #if defined ZMQ_HAVE_OPENVMS && defined __ia64 00261 __addrinfo64 *res = NULL; 00262 __addrinfo64 req; 00263 #else 00264 addrinfo *res = NULL; 00265 addrinfo req; 00266 #endif 00267 memset (&req, 0, sizeof (req)); 00268 00269 // Choose IPv4 or IPv6 protocol family. Note that IPv6 allows for 00270 // IPv4-in-IPv6 addresses. 00271 req.ai_family = ipv4only_ ? AF_INET : AF_INET6; 00272 00273 // Arbitrary, not used in the output, but avoids duplicate results. 00274 req.ai_socktype = SOCK_STREAM; 00275 00276 // Restrict hostname/service to literals to avoid any DNS lookups or 00277 // service-name irregularity due to indeterminate socktype. 00278 req.ai_flags = AI_PASSIVE | AI_NUMERICHOST; 00279 00280 #ifndef ZMQ_HAVE_WINDOWS 00281 // Windows by default maps IPv4 addresses into IPv6. In this API we only 00282 // require IPv4-mapped addresses when no native IPv6 interfaces are 00283 // available (~AI_ALL). This saves an additional DNS roundtrip for IPv4 00284 // addresses. 00285 if (req.ai_family == AF_INET6) 00286 req.ai_flags |= AI_V4MAPPED; 00287 #endif 00288 00289 // Resolve the literal address. Some of the error info is lost in case 00290 // of error, however, there's no way to report EAI errors via errno. 00291 rc = getaddrinfo (interface_, NULL, &req, &res); 00292 if (rc) { 00293 errno = ENODEV; 00294 return -1; 00295 } 00296 00297 // Use the first result. 00298 zmq_assert ((size_t) (res->ai_addrlen) <= sizeof (address)); 00299 memcpy (&address, res->ai_addr, res->ai_addrlen); 00300 00301 // Cleanup getaddrinfo after copying the possibly referenced result. 00302 if (res) 00303 freeaddrinfo (res); 00304 00305 return 0; 00306 } 00307 00308 int zmq::tcp_address_t::resolve_hostname (const char *hostname_, bool ipv4only_) 00309 { 00310 // Set up the query. 00311 #if defined ZMQ_HAVE_OPENVMS && defined __ia64 && __INITIAL_POINTER_SIZE == 64 00312 __addrinfo64 req; 00313 #else 00314 addrinfo req; 00315 #endif 00316 memset (&req, 0, sizeof (req)); 00317 00318 // Choose IPv4 or IPv6 protocol family. Note that IPv6 allows for 00319 // IPv4-in-IPv6 addresses. 00320 req.ai_family = ipv4only_ ? AF_INET : AF_INET6; 00321 00322 // Need to choose one to avoid duplicate results from getaddrinfo() - this 00323 // doesn't really matter, since it's not included in the addr-output. 00324 req.ai_socktype = SOCK_STREAM; 00325 00326 #ifndef ZMQ_HAVE_WINDOWS 00327 // Windows by default maps IPv4 addresses into IPv6. In this API we only 00328 // require IPv4-mapped addresses when no native IPv6 interfaces are 00329 // available. This saves an additional DNS roundtrip for IPv4 addresses. 00330 if (req.ai_family == AF_INET6) 00331 req.ai_flags |= AI_V4MAPPED; 00332 #endif 00333 00334 // Resolve host name. Some of the error info is lost in case of error, 00335 // however, there's no way to report EAI errors via errno. 00336 #if defined ZMQ_HAVE_OPENVMS && defined __ia64 && __INITIAL_POINTER_SIZE == 64 00337 __addrinfo64 *res; 00338 #else 00339 addrinfo *res; 00340 #endif 00341 int rc = getaddrinfo (hostname_, NULL, &req, &res); 00342 if (rc) { 00343 switch (rc) { 00344 case EAI_MEMORY: 00345 errno = ENOMEM; 00346 break; 00347 default: 00348 errno = EINVAL; 00349 break; 00350 } 00351 return -1; 00352 } 00353 00354 // Copy first result to output addr with hostname and service. 00355 zmq_assert ((size_t) (res->ai_addrlen) <= sizeof (address)); 00356 memcpy (&address, res->ai_addr, res->ai_addrlen); 00357 00358 freeaddrinfo (res); 00359 00360 return 0; 00361 } 00362 00363 zmq::tcp_address_t::tcp_address_t () 00364 { 00365 memset (&address, 0, sizeof (address)); 00366 } 00367 00368 zmq::tcp_address_t::~tcp_address_t () 00369 { 00370 } 00371 00372 int zmq::tcp_address_t::resolve (const char *name_, bool local_, bool ipv4only_) 00373 { 00374 // Find the ':' at end that separates address from the port number. 00375 const char *delimiter = strrchr (name_, ':'); 00376 if (!delimiter) { 00377 errno = EINVAL; 00378 return -1; 00379 } 00380 00381 // Separate the address/port. 00382 std::string addr_str (name_, delimiter - name_); 00383 std::string port_str (delimiter + 1); 00384 00385 // Remove square brackets around the address, if any. 00386 if (!addr_str.empty () && addr_str [0] == '[' && 00387 addr_str [addr_str.size () - 1] == ']') 00388 addr_str = addr_str.substr (1, addr_str.size () - 2); 00389 00390 // Parse the port number (0 is not a valid port). 00391 uint16_t port = (uint16_t) atoi (port_str.c_str()); 00392 if (port == 0) { 00393 errno = EINVAL; 00394 return -1; 00395 } 00396 00397 // Resolve the IP address. 00398 int rc; 00399 if (local_) 00400 rc = resolve_interface (addr_str.c_str (), ipv4only_); 00401 else 00402 rc = resolve_hostname (addr_str.c_str (), ipv4only_); 00403 if (rc != 0) 00404 return -1; 00405 00406 // Set the port into the address structure. 00407 if (address.generic.sa_family == AF_INET6) 00408 address.ipv6.sin6_port = htons (port); 00409 else 00410 address.ipv4.sin_port = htons (port); 00411 00412 return 0; 00413 } 00414 00415 sockaddr *zmq::tcp_address_t::addr () 00416 { 00417 return &address.generic; 00418 } 00419 00420 socklen_t zmq::tcp_address_t::addrlen () 00421 { 00422 if (address.generic.sa_family == AF_INET6) 00423 return (socklen_t) sizeof (address.ipv6); 00424 else 00425 return (socklen_t) sizeof (address.ipv4); 00426 } 00427 00428 #if defined ZMQ_HAVE_WINDOWS 00429 unsigned short zmq::tcp_address_t::family () 00430 #else 00431 sa_family_t zmq::tcp_address_t::family () 00432 #endif 00433 { 00434 return address.generic.sa_family; 00435 } 00436