1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/misc/prnetdb.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2343 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "primpl.h" 1.10 + 1.11 +#include <string.h> 1.12 + 1.13 +/* 1.14 + * On Unix, the error code for gethostbyname() and gethostbyaddr() 1.15 + * is returned in the global variable h_errno, instead of the usual 1.16 + * errno. 1.17 + */ 1.18 +#if defined(XP_UNIX) 1.19 +#if defined(_PR_NEED_H_ERRNO) 1.20 +extern int h_errno; 1.21 +#endif 1.22 +#define _MD_GETHOST_ERRNO() h_errno 1.23 +#else 1.24 +#define _MD_GETHOST_ERRNO() _MD_ERRNO() 1.25 +#endif 1.26 + 1.27 +/* 1.28 + * The meaning of the macros related to gethostbyname, gethostbyaddr, 1.29 + * and gethostbyname2 is defined below. 1.30 + * - _PR_HAVE_THREADSAFE_GETHOST: the gethostbyXXX functions return 1.31 + * the result in thread specific storage. For example, AIX, HP-UX, 1.32 + * and OSF1. 1.33 + * - _PR_HAVE_GETHOST_R: have the gethostbyXXX_r functions. See next 1.34 + * two macros. 1.35 + * - _PR_HAVE_GETHOST_R_INT: the gethostbyXXX_r functions return an 1.36 + * int. For example, Linux glibc. 1.37 + * - _PR_HAVE_GETHOST_R_POINTER: the gethostbyXXX_r functions return 1.38 + * a struct hostent* pointer. For example, Solaris and IRIX. 1.39 + */ 1.40 +#if defined(_PR_NO_PREEMPT) || defined(_PR_HAVE_GETHOST_R) \ 1.41 + || defined(_PR_HAVE_THREADSAFE_GETHOST) 1.42 +#define _PR_NO_DNS_LOCK 1.43 +#endif 1.44 + 1.45 +#if defined(_PR_NO_DNS_LOCK) 1.46 +#define LOCK_DNS() 1.47 +#define UNLOCK_DNS() 1.48 +#else 1.49 +PRLock *_pr_dnsLock = NULL; 1.50 +#define LOCK_DNS() PR_Lock(_pr_dnsLock) 1.51 +#define UNLOCK_DNS() PR_Unlock(_pr_dnsLock) 1.52 +#endif /* defined(_PR_NO_DNS_LOCK) */ 1.53 + 1.54 +/* 1.55 + * Some platforms have the reentrant getprotobyname_r() and 1.56 + * getprotobynumber_r(). However, they come in three flavors. 1.57 + * Some return a pointer to struct protoent, others return 1.58 + * an int, and glibc's flavor takes five arguments. 1.59 + */ 1.60 +#if defined(XP_BEOS) && defined(BONE_VERSION) 1.61 +#include <arpa/inet.h> /* pick up define for inet_addr */ 1.62 +#include <sys/socket.h> 1.63 +#define _PR_HAVE_GETPROTO_R 1.64 +#define _PR_HAVE_GETPROTO_R_POINTER 1.65 +#endif 1.66 + 1.67 +#if defined(SOLARIS) || (defined(BSDI) && defined(_REENTRANT)) \ 1.68 + || (defined(LINUX) && defined(_REENTRANT) \ 1.69 + && !(defined(__GLIBC__) && __GLIBC__ >= 2) \ 1.70 + && !defined(ANDROID)) 1.71 +#define _PR_HAVE_GETPROTO_R 1.72 +#define _PR_HAVE_GETPROTO_R_POINTER 1.73 +#endif 1.74 + 1.75 +#if defined(OSF1) \ 1.76 + || defined(AIX4_3_PLUS) || (defined(AIX) && defined(_THREAD_SAFE)) \ 1.77 + || (defined(HPUX10_10) && defined(_REENTRANT)) \ 1.78 + || (defined(HPUX10_20) && defined(_REENTRANT)) \ 1.79 + || defined(OPENBSD) 1.80 +#define _PR_HAVE_GETPROTO_R 1.81 +#define _PR_HAVE_GETPROTO_R_INT 1.82 +#endif 1.83 + 1.84 +#if __FreeBSD_version >= 602000 1.85 +#define _PR_HAVE_GETPROTO_R 1.86 +#define _PR_HAVE_5_ARG_GETPROTO_R 1.87 +#endif 1.88 + 1.89 +/* BeOS has glibc but not the glibc-style getprotobyxxx_r functions. */ 1.90 +#if (defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(XP_BEOS)) 1.91 +#define _PR_HAVE_GETPROTO_R 1.92 +#define _PR_HAVE_5_ARG_GETPROTO_R 1.93 +#endif 1.94 + 1.95 +#if !defined(_PR_HAVE_GETPROTO_R) 1.96 +PRLock* _getproto_lock = NULL; 1.97 +#endif 1.98 + 1.99 +#if defined(_PR_INET6_PROBE) 1.100 +extern PRBool _pr_ipv6_is_present(void); 1.101 +#endif 1.102 + 1.103 +#define _PR_IN6_IS_ADDR_UNSPECIFIED(a) \ 1.104 + (((a)->pr_s6_addr32[0] == 0) && \ 1.105 + ((a)->pr_s6_addr32[1] == 0) && \ 1.106 + ((a)->pr_s6_addr32[2] == 0) && \ 1.107 + ((a)->pr_s6_addr32[3] == 0)) 1.108 + 1.109 +#define _PR_IN6_IS_ADDR_LOOPBACK(a) \ 1.110 + (((a)->pr_s6_addr32[0] == 0) && \ 1.111 + ((a)->pr_s6_addr32[1] == 0) && \ 1.112 + ((a)->pr_s6_addr32[2] == 0) && \ 1.113 + ((a)->pr_s6_addr[12] == 0) && \ 1.114 + ((a)->pr_s6_addr[13] == 0) && \ 1.115 + ((a)->pr_s6_addr[14] == 0) && \ 1.116 + ((a)->pr_s6_addr[15] == 0x1U)) 1.117 + 1.118 +const PRIPv6Addr _pr_in6addr_any = {{{ 0, 0, 0, 0, 1.119 + 0, 0, 0, 0, 1.120 + 0, 0, 0, 0, 1.121 + 0, 0, 0, 0 }}}; 1.122 + 1.123 +const PRIPv6Addr _pr_in6addr_loopback = {{{ 0, 0, 0, 0, 1.124 + 0, 0, 0, 0, 1.125 + 0, 0, 0, 0, 1.126 + 0, 0, 0, 0x1U }}}; 1.127 +/* 1.128 + * The values at bytes 10 and 11 are compared using pointers to 1.129 + * 8-bit fields, and not 32-bit fields, to make the comparison work on 1.130 + * both big-endian and little-endian systems 1.131 + */ 1.132 + 1.133 +#define _PR_IN6_IS_ADDR_V4MAPPED(a) \ 1.134 + (((a)->pr_s6_addr32[0] == 0) && \ 1.135 + ((a)->pr_s6_addr32[1] == 0) && \ 1.136 + ((a)->pr_s6_addr[8] == 0) && \ 1.137 + ((a)->pr_s6_addr[9] == 0) && \ 1.138 + ((a)->pr_s6_addr[10] == 0xff) && \ 1.139 + ((a)->pr_s6_addr[11] == 0xff)) 1.140 + 1.141 +#define _PR_IN6_IS_ADDR_V4COMPAT(a) \ 1.142 + (((a)->pr_s6_addr32[0] == 0) && \ 1.143 + ((a)->pr_s6_addr32[1] == 0) && \ 1.144 + ((a)->pr_s6_addr32[2] == 0)) 1.145 + 1.146 +#define _PR_IN6_V4MAPPED_TO_IPADDR(a) ((a)->pr_s6_addr32[3]) 1.147 + 1.148 +#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) 1.149 + 1.150 +/* 1.151 + * The _pr_QueryNetIfs() function finds out if the system has 1.152 + * IPv4 or IPv6 source addresses configured and sets _pr_have_inet_if 1.153 + * and _pr_have_inet6_if accordingly. 1.154 + * 1.155 + * We have an implementation using SIOCGIFCONF ioctl and a 1.156 + * default implementation that simply sets _pr_have_inet_if 1.157 + * and _pr_have_inet6_if to true. A better implementation 1.158 + * would be to use the routing sockets (see Chapter 17 of 1.159 + * W. Richard Stevens' Unix Network Programming, Vol. 1, 2nd. Ed.) 1.160 + */ 1.161 + 1.162 +static PRLock *_pr_query_ifs_lock = NULL; 1.163 +static PRBool _pr_have_inet_if = PR_FALSE; 1.164 +static PRBool _pr_have_inet6_if = PR_FALSE; 1.165 + 1.166 +#undef DEBUG_QUERY_IFS 1.167 + 1.168 +#if defined(AIX) \ 1.169 + || (defined(DARWIN) && (!defined(HAVE_GETIFADDRS) \ 1.170 + || (defined(XP_MACOSX) && (!defined(MAC_OS_X_VERSION_10_2) || \ 1.171 + MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_2)))) 1.172 + 1.173 +/* 1.174 + * Use SIOCGIFCONF ioctl on platforms that don't have routing 1.175 + * sockets. Warning: whether SIOCGIFCONF ioctl returns AF_INET6 1.176 + * network interfaces is not portable. 1.177 + * 1.178 + * The _pr_QueryNetIfs() function is derived from the code in 1.179 + * src/lib/libc/net/getifaddrs.c in BSD Unix and the code in 1.180 + * Section 16.6 of W. Richard Stevens' Unix Network Programming, 1.181 + * Vol. 1, 2nd. Ed. 1.182 + */ 1.183 + 1.184 +#include <sys/ioctl.h> 1.185 +#include <sys/socket.h> 1.186 +#include <netinet/in.h> 1.187 +#include <net/if.h> 1.188 + 1.189 +#ifdef DEBUG_QUERY_IFS 1.190 +static void 1.191 +_pr_PrintIfreq(struct ifreq *ifr) 1.192 +{ 1.193 + PRNetAddr addr; 1.194 + struct sockaddr *sa; 1.195 + const char* family; 1.196 + char addrstr[64]; 1.197 + 1.198 + sa = &ifr->ifr_addr; 1.199 + if (sa->sa_family == AF_INET) { 1.200 + struct sockaddr_in *sin = (struct sockaddr_in *)sa; 1.201 + family = "inet"; 1.202 + memcpy(&addr.inet.ip, &sin->sin_addr, sizeof(sin->sin_addr)); 1.203 + } else if (sa->sa_family == AF_INET6) { 1.204 + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 1.205 + family = "inet6"; 1.206 + memcpy(&addr.ipv6.ip, &sin6->sin6_addr, sizeof(sin6->sin6_addr)); 1.207 + } else { 1.208 + return; /* skip if not AF_INET or AF_INET6 */ 1.209 + } 1.210 + addr.raw.family = sa->sa_family; 1.211 + PR_NetAddrToString(&addr, addrstr, sizeof(addrstr)); 1.212 + printf("%s: %s %s\n", ifr->ifr_name, family, addrstr); 1.213 +} 1.214 +#endif 1.215 + 1.216 +static void 1.217 +_pr_QueryNetIfs(void) 1.218 +{ 1.219 + int sock; 1.220 + int rv; 1.221 + struct ifconf ifc; 1.222 + struct ifreq *ifr; 1.223 + struct ifreq *lifr; 1.224 + PRUint32 len, lastlen; 1.225 + char *buf; 1.226 + 1.227 + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 1.228 + return; 1.229 + } 1.230 + 1.231 + /* Issue SIOCGIFCONF request in a loop. */ 1.232 + lastlen = 0; 1.233 + len = 100 * sizeof(struct ifreq); /* initial buffer size guess */ 1.234 + for (;;) { 1.235 + buf = (char *)PR_Malloc(len); 1.236 + if (NULL == buf) { 1.237 + close(sock); 1.238 + return; 1.239 + } 1.240 + ifc.ifc_buf = buf; 1.241 + ifc.ifc_len = len; 1.242 + rv = ioctl(sock, SIOCGIFCONF, &ifc); 1.243 + if (rv < 0) { 1.244 + if (errno != EINVAL || lastlen != 0) { 1.245 + close(sock); 1.246 + PR_Free(buf); 1.247 + return; 1.248 + } 1.249 + } else { 1.250 + if (ifc.ifc_len == lastlen) 1.251 + break; /* success, len has not changed */ 1.252 + lastlen = ifc.ifc_len; 1.253 + } 1.254 + len += 10 * sizeof(struct ifreq); /* increment */ 1.255 + PR_Free(buf); 1.256 + } 1.257 + close(sock); 1.258 + 1.259 + ifr = ifc.ifc_req; 1.260 + lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len]; 1.261 + 1.262 + while (ifr < lifr) { 1.263 + struct sockaddr *sa; 1.264 + int sa_len; 1.265 + 1.266 +#ifdef DEBUG_QUERY_IFS 1.267 + _pr_PrintIfreq(ifr); 1.268 +#endif 1.269 + sa = &ifr->ifr_addr; 1.270 + if (sa->sa_family == AF_INET) { 1.271 + struct sockaddr_in *sin = (struct sockaddr_in *) sa; 1.272 + if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) { 1.273 + _pr_have_inet_if = PR_TRUE; 1.274 + } 1.275 + } else if (sa->sa_family == AF_INET6) { 1.276 + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; 1.277 + if (!IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) 1.278 + && !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 1.279 + _pr_have_inet6_if = PR_TRUE; 1.280 + } 1.281 + } 1.282 + 1.283 +#ifdef _PR_HAVE_SOCKADDR_LEN 1.284 + sa_len = PR_MAX(sa->sa_len, sizeof(struct sockaddr)); 1.285 +#else 1.286 + switch (sa->sa_family) { 1.287 +#ifdef AF_LINK 1.288 + case AF_LINK: 1.289 + sa_len = sizeof(struct sockaddr_dl); 1.290 + break; 1.291 +#endif 1.292 + case AF_INET6: 1.293 + sa_len = sizeof(struct sockaddr_in6); 1.294 + break; 1.295 + default: 1.296 + sa_len = sizeof(struct sockaddr); 1.297 + break; 1.298 + } 1.299 +#endif 1.300 + ifr = (struct ifreq *)(((char *)sa) + sa_len); 1.301 + } 1.302 + PR_Free(buf); 1.303 +} 1.304 + 1.305 +#elif (defined(DARWIN) && defined(HAVE_GETIFADDRS)) || defined(FREEBSD) \ 1.306 + || defined(NETBSD) || defined(OPENBSD) 1.307 + 1.308 +/* 1.309 + * Use the BSD getifaddrs function. 1.310 + */ 1.311 + 1.312 +#include <sys/types.h> 1.313 +#include <sys/socket.h> 1.314 +#include <ifaddrs.h> 1.315 +#include <netinet/in.h> 1.316 + 1.317 +#ifdef DEBUG_QUERY_IFS 1.318 +static void 1.319 +_pr_PrintIfaddrs(struct ifaddrs *ifa) 1.320 +{ 1.321 + struct sockaddr *sa; 1.322 + const char* family; 1.323 + void *addrp; 1.324 + char addrstr[64]; 1.325 + 1.326 + sa = ifa->ifa_addr; 1.327 + if (sa->sa_family == AF_INET) { 1.328 + struct sockaddr_in *sin = (struct sockaddr_in *)sa; 1.329 + family = "inet"; 1.330 + addrp = &sin->sin_addr; 1.331 + } else if (sa->sa_family == AF_INET6) { 1.332 + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 1.333 + family = "inet6"; 1.334 + addrp = &sin6->sin6_addr; 1.335 + } else { 1.336 + return; /* skip if not AF_INET or AF_INET6 */ 1.337 + } 1.338 + inet_ntop(sa->sa_family, addrp, addrstr, sizeof(addrstr)); 1.339 + printf("%s: %s %s\n", ifa->ifa_name, family, addrstr); 1.340 +} 1.341 +#endif 1.342 + 1.343 +static void 1.344 +_pr_QueryNetIfs(void) 1.345 +{ 1.346 + struct ifaddrs *ifp; 1.347 + struct ifaddrs *ifa; 1.348 + 1.349 + if (getifaddrs(&ifp) == -1) { 1.350 + return; 1.351 + } 1.352 + for (ifa = ifp; ifa; ifa = ifa->ifa_next) { 1.353 + struct sockaddr *sa; 1.354 + 1.355 +#ifdef DEBUG_QUERY_IFS 1.356 + _pr_PrintIfaddrs(ifa); 1.357 +#endif 1.358 + sa = ifa->ifa_addr; 1.359 + if (sa->sa_family == AF_INET) { 1.360 + struct sockaddr_in *sin = (struct sockaddr_in *) sa; 1.361 + if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) { 1.362 + _pr_have_inet_if = 1; 1.363 + } 1.364 + } else if (sa->sa_family == AF_INET6) { 1.365 + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; 1.366 + if (!IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) 1.367 + && !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 1.368 + _pr_have_inet6_if = 1; 1.369 + } 1.370 + } 1.371 + } 1.372 + freeifaddrs(ifp); 1.373 +} 1.374 + 1.375 +#else /* default */ 1.376 + 1.377 +/* 1.378 + * Emulate the code in NSPR 4.2 or older. PR_GetIPNodeByName behaves 1.379 + * as if the system had both IPv4 and IPv6 source addresses configured. 1.380 + */ 1.381 +static void 1.382 +_pr_QueryNetIfs(void) 1.383 +{ 1.384 + _pr_have_inet_if = PR_TRUE; 1.385 + _pr_have_inet6_if = PR_TRUE; 1.386 +} 1.387 + 1.388 +#endif 1.389 + 1.390 +#endif /* _PR_INET6 && _PR_HAVE_GETHOSTBYNAME2 */ 1.391 + 1.392 +void _PR_InitNet(void) 1.393 +{ 1.394 +#if defined(XP_UNIX) 1.395 +#ifdef HAVE_NETCONFIG 1.396 + /* 1.397 + * This one-liner prevents the endless re-open's and re-read's of 1.398 + * /etc/netconfig on EACH and EVERY call to accept(), connect(), etc. 1.399 + */ 1.400 + (void)setnetconfig(); 1.401 +#endif 1.402 +#endif 1.403 +#if !defined(_PR_NO_DNS_LOCK) 1.404 + _pr_dnsLock = PR_NewLock(); 1.405 +#endif 1.406 +#if !defined(_PR_HAVE_GETPROTO_R) 1.407 + _getproto_lock = PR_NewLock(); 1.408 +#endif 1.409 +#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) 1.410 + _pr_query_ifs_lock = PR_NewLock(); 1.411 +#endif 1.412 +} 1.413 + 1.414 +void _PR_CleanupNet(void) 1.415 +{ 1.416 +#if !defined(_PR_NO_DNS_LOCK) 1.417 + if (_pr_dnsLock) { 1.418 + PR_DestroyLock(_pr_dnsLock); 1.419 + _pr_dnsLock = NULL; 1.420 + } 1.421 +#endif 1.422 +#if !defined(_PR_HAVE_GETPROTO_R) 1.423 + if (_getproto_lock) { 1.424 + PR_DestroyLock(_getproto_lock); 1.425 + _getproto_lock = NULL; 1.426 + } 1.427 +#endif 1.428 +#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) 1.429 + if (_pr_query_ifs_lock) { 1.430 + PR_DestroyLock(_pr_query_ifs_lock); 1.431 + _pr_query_ifs_lock = NULL; 1.432 + } 1.433 +#endif 1.434 +} 1.435 + 1.436 +/* 1.437 +** Allocate space from the buffer, aligning it to "align" before doing 1.438 +** the allocation. "align" must be a power of 2. 1.439 +*/ 1.440 +static char *Alloc(PRIntn amount, char **bufp, PRIntn *buflenp, PRIntn align) 1.441 +{ 1.442 + char *buf = *bufp; 1.443 + PRIntn buflen = *buflenp; 1.444 + 1.445 + if (align && ((long)buf & (align - 1))) { 1.446 + PRIntn skip = align - ((ptrdiff_t)buf & (align - 1)); 1.447 + if (buflen < skip) { 1.448 + return 0; 1.449 + } 1.450 + buf += skip; 1.451 + buflen -= skip; 1.452 + } 1.453 + if (buflen < amount) { 1.454 + return 0; 1.455 + } 1.456 + *bufp = buf + amount; 1.457 + *buflenp = buflen - amount; 1.458 + return buf; 1.459 +} 1.460 + 1.461 +typedef enum _PRIPAddrConversion { 1.462 + _PRIPAddrNoConversion, 1.463 + _PRIPAddrIPv4Mapped, 1.464 + _PRIPAddrIPv4Compat 1.465 +} _PRIPAddrConversion; 1.466 + 1.467 +/* 1.468 +** Convert an IPv4 address (v4) to an IPv4-mapped IPv6 address (v6). 1.469 +*/ 1.470 +static void MakeIPv4MappedAddr(const char *v4, char *v6) 1.471 +{ 1.472 + memset(v6, 0, 10); 1.473 + memset(v6 + 10, 0xff, 2); 1.474 + memcpy(v6 + 12, v4, 4); 1.475 +} 1.476 + 1.477 +/* 1.478 +** Convert an IPv4 address (v4) to an IPv4-compatible IPv6 address (v6). 1.479 +*/ 1.480 +static void MakeIPv4CompatAddr(const char *v4, char *v6) 1.481 +{ 1.482 + memset(v6, 0, 12); 1.483 + memcpy(v6 + 12, v4, 4); 1.484 +} 1.485 + 1.486 +/* 1.487 +** Copy a hostent, and all of the memory that it refers to into 1.488 +** (hopefully) stacked buffers. 1.489 +*/ 1.490 +static PRStatus CopyHostent( 1.491 + struct hostent *from, 1.492 + char **buf, 1.493 + PRIntn *bufsize, 1.494 + _PRIPAddrConversion conversion, 1.495 + PRHostEnt *to) 1.496 +{ 1.497 + PRIntn len, na; 1.498 + char **ap; 1.499 + 1.500 + if (conversion != _PRIPAddrNoConversion 1.501 + && from->h_addrtype == AF_INET) { 1.502 + PR_ASSERT(from->h_length == 4); 1.503 + to->h_addrtype = PR_AF_INET6; 1.504 + to->h_length = 16; 1.505 + } else { 1.506 +#if defined(_PR_INET6) || defined(_PR_INET6_PROBE) 1.507 + if (AF_INET6 == from->h_addrtype) 1.508 + to->h_addrtype = PR_AF_INET6; 1.509 + else 1.510 +#endif 1.511 + to->h_addrtype = from->h_addrtype; 1.512 + to->h_length = from->h_length; 1.513 + } 1.514 + 1.515 + /* Copy the official name */ 1.516 + if (!from->h_name) return PR_FAILURE; 1.517 + len = strlen(from->h_name) + 1; 1.518 + to->h_name = Alloc(len, buf, bufsize, 0); 1.519 + if (!to->h_name) return PR_FAILURE; 1.520 + memcpy(to->h_name, from->h_name, len); 1.521 + 1.522 + /* Count the aliases, then allocate storage for the pointers */ 1.523 + if (!from->h_aliases) { 1.524 + na = 1; 1.525 + } else { 1.526 + for (na = 1, ap = from->h_aliases; *ap != 0; na++, ap++){;} /* nothing to execute */ 1.527 + } 1.528 + to->h_aliases = (char**)Alloc( 1.529 + na * sizeof(char*), buf, bufsize, sizeof(char**)); 1.530 + if (!to->h_aliases) return PR_FAILURE; 1.531 + 1.532 + /* Copy the aliases, one at a time */ 1.533 + if (!from->h_aliases) { 1.534 + to->h_aliases[0] = 0; 1.535 + } else { 1.536 + for (na = 0, ap = from->h_aliases; *ap != 0; na++, ap++) { 1.537 + len = strlen(*ap) + 1; 1.538 + to->h_aliases[na] = Alloc(len, buf, bufsize, 0); 1.539 + if (!to->h_aliases[na]) return PR_FAILURE; 1.540 + memcpy(to->h_aliases[na], *ap, len); 1.541 + } 1.542 + to->h_aliases[na] = 0; 1.543 + } 1.544 + 1.545 + /* Count the addresses, then allocate storage for the pointers */ 1.546 + for (na = 1, ap = from->h_addr_list; *ap != 0; na++, ap++){;} /* nothing to execute */ 1.547 + to->h_addr_list = (char**)Alloc( 1.548 + na * sizeof(char*), buf, bufsize, sizeof(char**)); 1.549 + if (!to->h_addr_list) return PR_FAILURE; 1.550 + 1.551 + /* Copy the addresses, one at a time */ 1.552 + for (na = 0, ap = from->h_addr_list; *ap != 0; na++, ap++) { 1.553 + to->h_addr_list[na] = Alloc(to->h_length, buf, bufsize, 0); 1.554 + if (!to->h_addr_list[na]) return PR_FAILURE; 1.555 + if (conversion != _PRIPAddrNoConversion 1.556 + && from->h_addrtype == AF_INET) { 1.557 + if (conversion == _PRIPAddrIPv4Mapped) { 1.558 + MakeIPv4MappedAddr(*ap, to->h_addr_list[na]); 1.559 + } else { 1.560 + PR_ASSERT(conversion == _PRIPAddrIPv4Compat); 1.561 + MakeIPv4CompatAddr(*ap, to->h_addr_list[na]); 1.562 + } 1.563 + } else { 1.564 + memcpy(to->h_addr_list[na], *ap, to->h_length); 1.565 + } 1.566 + } 1.567 + to->h_addr_list[na] = 0; 1.568 + return PR_SUCCESS; 1.569 +} 1.570 + 1.571 +#ifdef SYMBIAN 1.572 +/* Set p_aliases by hand because Symbian's getprotobyname() returns NULL. */ 1.573 +static void AssignAliases(struct protoent *Protoent, char** aliases) 1.574 +{ 1.575 + if (NULL == Protoent->p_aliases) { 1.576 + if (0 == strcmp(Protoent->p_name, "ip")) 1.577 + aliases[0] = "IP"; 1.578 + else if (0 == strcmp(Protoent->p_name, "tcp")) 1.579 + aliases[0] = "TCP"; 1.580 + else if (0 == strcmp(Protoent->p_name, "udp")) 1.581 + aliases[0] = "UDP"; 1.582 + else 1.583 + aliases[0] = "UNKNOWN"; 1.584 + aliases[1] = NULL; 1.585 + Protoent->p_aliases = aliases; 1.586 + } 1.587 +} 1.588 +#endif 1.589 + 1.590 +#if !defined(_PR_HAVE_GETPROTO_R) 1.591 +/* 1.592 +** Copy a protoent, and all of the memory that it refers to into 1.593 +** (hopefully) stacked buffers. 1.594 +*/ 1.595 +static PRStatus CopyProtoent( 1.596 + struct protoent *from, char *buf, PRIntn bufsize, PRProtoEnt *to) 1.597 +{ 1.598 + PRIntn len, na; 1.599 + char **ap; 1.600 + 1.601 + /* Do the easy stuff */ 1.602 + to->p_num = from->p_proto; 1.603 + 1.604 + /* Copy the official name */ 1.605 + if (!from->p_name) return PR_FAILURE; 1.606 + len = strlen(from->p_name) + 1; 1.607 + to->p_name = Alloc(len, &buf, &bufsize, 0); 1.608 + if (!to->p_name) return PR_FAILURE; 1.609 + memcpy(to->p_name, from->p_name, len); 1.610 + 1.611 + /* Count the aliases, then allocate storage for the pointers */ 1.612 + for (na = 1, ap = from->p_aliases; *ap != 0; na++, ap++){;} /* nothing to execute */ 1.613 + to->p_aliases = (char**)Alloc( 1.614 + na * sizeof(char*), &buf, &bufsize, sizeof(char**)); 1.615 + if (!to->p_aliases) return PR_FAILURE; 1.616 + 1.617 + /* Copy the aliases, one at a time */ 1.618 + for (na = 0, ap = from->p_aliases; *ap != 0; na++, ap++) { 1.619 + len = strlen(*ap) + 1; 1.620 + to->p_aliases[na] = Alloc(len, &buf, &bufsize, 0); 1.621 + if (!to->p_aliases[na]) return PR_FAILURE; 1.622 + memcpy(to->p_aliases[na], *ap, len); 1.623 + } 1.624 + to->p_aliases[na] = 0; 1.625 + 1.626 + return PR_SUCCESS; 1.627 +} 1.628 +#endif /* !defined(_PR_HAVE_GETPROTO_R) */ 1.629 + 1.630 +/* 1.631 + * ################################################################# 1.632 + * NOTE: tmphe, tmpbuf, bufsize, h, and h_err are local variables 1.633 + * or arguments of PR_GetHostByName, PR_GetIPNodeByName, and 1.634 + * PR_GetHostByAddr. DO NOT CHANGE THE NAMES OF THESE LOCAL 1.635 + * VARIABLES OR ARGUMENTS. 1.636 + * ################################################################# 1.637 + */ 1.638 +#if defined(_PR_HAVE_GETHOST_R_INT) 1.639 + 1.640 +#define GETHOSTBYNAME(name) \ 1.641 + (gethostbyname_r(name, &tmphe, tmpbuf, bufsize, &h, &h_err), h) 1.642 +#define GETHOSTBYNAME2(name, af) \ 1.643 + (gethostbyname2_r(name, af, &tmphe, tmpbuf, bufsize, &h, &h_err), h) 1.644 +#define GETHOSTBYADDR(addr, addrlen, af) \ 1.645 + (gethostbyaddr_r(addr, addrlen, af, \ 1.646 + &tmphe, tmpbuf, bufsize, &h, &h_err), h) 1.647 + 1.648 +#elif defined(_PR_HAVE_GETHOST_R_POINTER) 1.649 + 1.650 +#define GETHOSTBYNAME(name) \ 1.651 + gethostbyname_r(name, &tmphe, tmpbuf, bufsize, &h_err) 1.652 +#define GETHOSTBYNAME2(name, af) \ 1.653 + gethostbyname2_r(name, af, &tmphe, tmpbuf, bufsize, &h_err) 1.654 +#define GETHOSTBYADDR(addr, addrlen, af) \ 1.655 + gethostbyaddr_r(addr, addrlen, af, &tmphe, tmpbuf, bufsize, &h_err) 1.656 + 1.657 +#else 1.658 + 1.659 +#define GETHOSTBYNAME(name) gethostbyname(name) 1.660 +#define GETHOSTBYNAME2(name, af) gethostbyname2(name, af) 1.661 +#define GETHOSTBYADDR(addr, addrlen, af) gethostbyaddr(addr, addrlen, af) 1.662 + 1.663 +#endif /* definition of GETHOSTBYXXX */ 1.664 + 1.665 +PR_IMPLEMENT(PRStatus) PR_GetHostByName( 1.666 + const char *name, char *buf, PRIntn bufsize, PRHostEnt *hp) 1.667 +{ 1.668 + struct hostent *h; 1.669 + PRStatus rv = PR_FAILURE; 1.670 +#if defined(_PR_HAVE_GETHOST_R) 1.671 + char localbuf[PR_NETDB_BUF_SIZE]; 1.672 + char *tmpbuf; 1.673 + struct hostent tmphe; 1.674 + int h_err; 1.675 +#endif 1.676 + 1.677 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.678 + 1.679 +#if defined(_PR_HAVE_GETHOST_R) 1.680 + tmpbuf = localbuf; 1.681 + if (bufsize > sizeof(localbuf)) 1.682 + { 1.683 + tmpbuf = (char *)PR_Malloc(bufsize); 1.684 + if (NULL == tmpbuf) 1.685 + { 1.686 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.687 + return rv; 1.688 + } 1.689 + } 1.690 +#endif 1.691 + 1.692 + LOCK_DNS(); 1.693 + 1.694 + h = GETHOSTBYNAME(name); 1.695 + 1.696 + if (NULL == h) 1.697 + { 1.698 + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO()); 1.699 + } 1.700 + else 1.701 + { 1.702 + _PRIPAddrConversion conversion = _PRIPAddrNoConversion; 1.703 + rv = CopyHostent(h, &buf, &bufsize, conversion, hp); 1.704 + if (PR_SUCCESS != rv) 1.705 + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); 1.706 + } 1.707 + UNLOCK_DNS(); 1.708 +#if defined(_PR_HAVE_GETHOST_R) 1.709 + if (tmpbuf != localbuf) 1.710 + PR_Free(tmpbuf); 1.711 +#endif 1.712 + return rv; 1.713 +} 1.714 + 1.715 +#if !defined(_PR_INET6) && \ 1.716 + defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME) 1.717 +typedef struct hostent * (*_pr_getipnodebyname_t)(const char *, int, 1.718 + int, int *); 1.719 +typedef struct hostent * (*_pr_getipnodebyaddr_t)(const void *, size_t, 1.720 + int, int *); 1.721 +typedef void (*_pr_freehostent_t)(struct hostent *); 1.722 +static void * _pr_getipnodebyname_fp; 1.723 +static void * _pr_getipnodebyaddr_fp; 1.724 +static void * _pr_freehostent_fp; 1.725 + 1.726 +/* 1.727 + * Look up the addresses of getipnodebyname, getipnodebyaddr, 1.728 + * and freehostent. 1.729 + */ 1.730 +PRStatus 1.731 +_pr_find_getipnodebyname(void) 1.732 +{ 1.733 + PRLibrary *lib; 1.734 + PRStatus rv; 1.735 +#define GETIPNODEBYNAME "getipnodebyname" 1.736 +#define GETIPNODEBYADDR "getipnodebyaddr" 1.737 +#define FREEHOSTENT "freehostent" 1.738 + 1.739 + _pr_getipnodebyname_fp = PR_FindSymbolAndLibrary(GETIPNODEBYNAME, &lib); 1.740 + if (NULL != _pr_getipnodebyname_fp) { 1.741 + _pr_freehostent_fp = PR_FindSymbol(lib, FREEHOSTENT); 1.742 + if (NULL != _pr_freehostent_fp) { 1.743 + _pr_getipnodebyaddr_fp = PR_FindSymbol(lib, GETIPNODEBYADDR); 1.744 + if (NULL != _pr_getipnodebyaddr_fp) 1.745 + rv = PR_SUCCESS; 1.746 + else 1.747 + rv = PR_FAILURE; 1.748 + } else 1.749 + rv = PR_FAILURE; 1.750 + (void)PR_UnloadLibrary(lib); 1.751 + } else 1.752 + rv = PR_FAILURE; 1.753 + return rv; 1.754 +} 1.755 +#endif 1.756 + 1.757 +#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) 1.758 +/* 1.759 +** Append the V4 addresses to the end of the list 1.760 +*/ 1.761 +static PRStatus AppendV4AddrsToHostent( 1.762 + struct hostent *from, 1.763 + char **buf, 1.764 + PRIntn *bufsize, 1.765 + PRHostEnt *to) 1.766 +{ 1.767 + PRIntn na, na_old; 1.768 + char **ap; 1.769 + char **new_addr_list; 1.770 + 1.771 + /* Count the addresses, then grow storage for the pointers */ 1.772 + for (na_old = 0, ap = to->h_addr_list; *ap != 0; na_old++, ap++) 1.773 + {;} /* nothing to execute */ 1.774 + for (na = na_old + 1, ap = from->h_addr_list; *ap != 0; na++, ap++) 1.775 + {;} /* nothing to execute */ 1.776 + new_addr_list = (char**)Alloc( 1.777 + na * sizeof(char*), buf, bufsize, sizeof(char**)); 1.778 + if (!new_addr_list) return PR_FAILURE; 1.779 + 1.780 + /* Copy the V6 addresses, one at a time */ 1.781 + for (na = 0, ap = to->h_addr_list; *ap != 0; na++, ap++) { 1.782 + new_addr_list[na] = to->h_addr_list[na]; 1.783 + } 1.784 + to->h_addr_list = new_addr_list; 1.785 + 1.786 + /* Copy the V4 addresses, one at a time */ 1.787 + for (ap = from->h_addr_list; *ap != 0; na++, ap++) { 1.788 + to->h_addr_list[na] = Alloc(to->h_length, buf, bufsize, 0); 1.789 + if (!to->h_addr_list[na]) return PR_FAILURE; 1.790 + MakeIPv4MappedAddr(*ap, to->h_addr_list[na]); 1.791 + } 1.792 + to->h_addr_list[na] = 0; 1.793 + return PR_SUCCESS; 1.794 +} 1.795 +#endif 1.796 + 1.797 +PR_IMPLEMENT(PRStatus) PR_GetIPNodeByName( 1.798 + const char *name, PRUint16 af, PRIntn flags, 1.799 + char *buf, PRIntn bufsize, PRHostEnt *hp) 1.800 +{ 1.801 + struct hostent *h = 0; 1.802 + PRStatus rv = PR_FAILURE; 1.803 +#if defined(_PR_HAVE_GETHOST_R) 1.804 + char localbuf[PR_NETDB_BUF_SIZE]; 1.805 + char *tmpbuf; 1.806 + struct hostent tmphe; 1.807 + int h_err; 1.808 +#endif 1.809 +#if defined(_PR_HAVE_GETIPNODEBYNAME) 1.810 + PRUint16 md_af = af; 1.811 + int error_num; 1.812 + int tmp_flags = 0; 1.813 +#endif 1.814 +#if defined(_PR_HAVE_GETHOSTBYNAME2) 1.815 + PRBool did_af_inet = PR_FALSE; 1.816 +#endif 1.817 + 1.818 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.819 + 1.820 + if (af != PR_AF_INET && af != PR_AF_INET6) { 1.821 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.822 + return PR_FAILURE; 1.823 + } 1.824 + 1.825 +#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) 1.826 + PR_Lock(_pr_query_ifs_lock); 1.827 + /* 1.828 + * Keep querying the presence of IPv4 and IPv6 interfaces until 1.829 + * at least one is up. This allows us to detect the local 1.830 + * machine going from offline to online. 1.831 + */ 1.832 + if (!_pr_have_inet_if && !_pr_have_inet6_if) { 1.833 + _pr_QueryNetIfs(); 1.834 +#ifdef DEBUG_QUERY_IFS 1.835 + if (_pr_have_inet_if) 1.836 + printf("Have IPv4 source address\n"); 1.837 + if (_pr_have_inet6_if) 1.838 + printf("Have IPv6 source address\n"); 1.839 +#endif 1.840 + } 1.841 + PR_Unlock(_pr_query_ifs_lock); 1.842 +#endif 1.843 + 1.844 +#if defined(_PR_HAVE_GETIPNODEBYNAME) 1.845 + if (flags & PR_AI_V4MAPPED) 1.846 + tmp_flags |= AI_V4MAPPED; 1.847 + if (flags & PR_AI_ADDRCONFIG) 1.848 + tmp_flags |= AI_ADDRCONFIG; 1.849 + if (flags & PR_AI_ALL) 1.850 + tmp_flags |= AI_ALL; 1.851 + if (af == PR_AF_INET6) 1.852 + md_af = AF_INET6; 1.853 + else 1.854 + md_af = af; 1.855 +#endif 1.856 + 1.857 +#if defined(_PR_HAVE_GETHOST_R) 1.858 + tmpbuf = localbuf; 1.859 + if (bufsize > sizeof(localbuf)) 1.860 + { 1.861 + tmpbuf = (char *)PR_Malloc(bufsize); 1.862 + if (NULL == tmpbuf) 1.863 + { 1.864 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.865 + return rv; 1.866 + } 1.867 + } 1.868 +#endif 1.869 + 1.870 + /* Do not need to lock the DNS lock if getipnodebyname() is called */ 1.871 +#ifdef _PR_INET6 1.872 +#ifdef _PR_HAVE_GETHOSTBYNAME2 1.873 + LOCK_DNS(); 1.874 + if (af == PR_AF_INET6) 1.875 + { 1.876 + if ((flags & PR_AI_ADDRCONFIG) == 0 || _pr_have_inet6_if) 1.877 + { 1.878 +#ifdef _PR_INET6_PROBE 1.879 + if (_pr_ipv6_is_present()) 1.880 +#endif 1.881 + h = GETHOSTBYNAME2(name, AF_INET6); 1.882 + } 1.883 + if ((NULL == h) && (flags & PR_AI_V4MAPPED) 1.884 + && ((flags & PR_AI_ADDRCONFIG) == 0 || _pr_have_inet_if)) 1.885 + { 1.886 + did_af_inet = PR_TRUE; 1.887 + h = GETHOSTBYNAME2(name, AF_INET); 1.888 + } 1.889 + } 1.890 + else 1.891 + { 1.892 + if ((flags & PR_AI_ADDRCONFIG) == 0 || _pr_have_inet_if) 1.893 + { 1.894 + did_af_inet = PR_TRUE; 1.895 + h = GETHOSTBYNAME2(name, af); 1.896 + } 1.897 + } 1.898 +#elif defined(_PR_HAVE_GETIPNODEBYNAME) 1.899 + h = getipnodebyname(name, md_af, tmp_flags, &error_num); 1.900 +#else 1.901 +#error "Unknown name-to-address translation function" 1.902 +#endif /* _PR_HAVE_GETHOSTBYNAME2 */ 1.903 +#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME) 1.904 + if (_pr_ipv6_is_present()) 1.905 + { 1.906 +#ifdef PR_GETIPNODE_NOT_THREADSAFE 1.907 + LOCK_DNS(); 1.908 +#endif 1.909 + h = (*((_pr_getipnodebyname_t)_pr_getipnodebyname_fp))(name, md_af, tmp_flags, &error_num); 1.910 + } 1.911 + else 1.912 + { 1.913 + LOCK_DNS(); 1.914 + h = GETHOSTBYNAME(name); 1.915 + } 1.916 +#else /* _PR_INET6 */ 1.917 + LOCK_DNS(); 1.918 + h = GETHOSTBYNAME(name); 1.919 +#endif /* _PR_INET6 */ 1.920 + 1.921 + if (NULL == h) 1.922 + { 1.923 +#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME) 1.924 + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num); 1.925 +#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME) 1.926 + if (_pr_ipv6_is_present()) 1.927 + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num); 1.928 + else 1.929 + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO()); 1.930 +#else 1.931 + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO()); 1.932 +#endif 1.933 + } 1.934 + else 1.935 + { 1.936 + _PRIPAddrConversion conversion = _PRIPAddrNoConversion; 1.937 + 1.938 + if (af == PR_AF_INET6) conversion = _PRIPAddrIPv4Mapped; 1.939 + rv = CopyHostent(h, &buf, &bufsize, conversion, hp); 1.940 + if (PR_SUCCESS != rv) 1.941 + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); 1.942 +#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME) 1.943 + freehostent(h); 1.944 +#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME) 1.945 + if (_pr_ipv6_is_present()) 1.946 + (*((_pr_freehostent_t)_pr_freehostent_fp))(h); 1.947 +#endif 1.948 +#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) 1.949 + if ((PR_SUCCESS == rv) && (flags & PR_AI_V4MAPPED) 1.950 + && ((flags & PR_AI_ALL) 1.951 + || ((flags & PR_AI_ADDRCONFIG) && _pr_have_inet_if)) 1.952 + && !did_af_inet && (h = GETHOSTBYNAME2(name, AF_INET)) != 0) { 1.953 + rv = AppendV4AddrsToHostent(h, &buf, &bufsize, hp); 1.954 + if (PR_SUCCESS != rv) 1.955 + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); 1.956 + } 1.957 +#endif 1.958 + } 1.959 + 1.960 + /* Must match the convoluted logic above for LOCK_DNS() */ 1.961 +#ifdef _PR_INET6 1.962 +#ifdef _PR_HAVE_GETHOSTBYNAME2 1.963 + UNLOCK_DNS(); 1.964 +#endif /* _PR_HAVE_GETHOSTBYNAME2 */ 1.965 +#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME) 1.966 +#ifdef PR_GETIPNODE_NOT_THREADSAFE 1.967 + UNLOCK_DNS(); 1.968 +#else 1.969 + if (!_pr_ipv6_is_present()) 1.970 + UNLOCK_DNS(); 1.971 +#endif 1.972 +#else /* _PR_INET6 */ 1.973 + UNLOCK_DNS(); 1.974 +#endif /* _PR_INET6 */ 1.975 + 1.976 +#if defined(_PR_HAVE_GETHOST_R) 1.977 + if (tmpbuf != localbuf) 1.978 + PR_Free(tmpbuf); 1.979 +#endif 1.980 + 1.981 + return rv; 1.982 +} 1.983 + 1.984 +PR_IMPLEMENT(PRStatus) PR_GetHostByAddr( 1.985 + const PRNetAddr *hostaddr, char *buf, PRIntn bufsize, PRHostEnt *hostentry) 1.986 +{ 1.987 + struct hostent *h; 1.988 + PRStatus rv = PR_FAILURE; 1.989 + const void *addr; 1.990 + PRUint32 tmp_ip; 1.991 + int addrlen; 1.992 + PRInt32 af; 1.993 +#if defined(_PR_HAVE_GETHOST_R) 1.994 + char localbuf[PR_NETDB_BUF_SIZE]; 1.995 + char *tmpbuf; 1.996 + struct hostent tmphe; 1.997 + int h_err; 1.998 +#endif 1.999 +#if defined(_PR_HAVE_GETIPNODEBYADDR) 1.1000 + int error_num; 1.1001 +#endif 1.1002 + 1.1003 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.1004 + 1.1005 + if (hostaddr->raw.family == PR_AF_INET6) 1.1006 + { 1.1007 +#if defined(_PR_INET6_PROBE) 1.1008 + af = _pr_ipv6_is_present() ? AF_INET6 : AF_INET; 1.1009 +#elif defined(_PR_INET6) 1.1010 + af = AF_INET6; 1.1011 +#else 1.1012 + af = AF_INET; 1.1013 +#endif 1.1014 +#if defined(_PR_GHBA_DISALLOW_V4MAPPED) 1.1015 + if (_PR_IN6_IS_ADDR_V4MAPPED(&hostaddr->ipv6.ip)) 1.1016 + af = AF_INET; 1.1017 +#endif 1.1018 + } 1.1019 + else 1.1020 + { 1.1021 + PR_ASSERT(hostaddr->raw.family == AF_INET); 1.1022 + af = AF_INET; 1.1023 + } 1.1024 + if (hostaddr->raw.family == PR_AF_INET6) { 1.1025 +#if defined(_PR_INET6) || defined(_PR_INET6_PROBE) 1.1026 + if (af == AF_INET6) { 1.1027 + addr = &hostaddr->ipv6.ip; 1.1028 + addrlen = sizeof(hostaddr->ipv6.ip); 1.1029 + } 1.1030 + else 1.1031 +#endif 1.1032 + { 1.1033 + PR_ASSERT(af == AF_INET); 1.1034 + if (!_PR_IN6_IS_ADDR_V4MAPPED(&hostaddr->ipv6.ip)) { 1.1035 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.1036 + return rv; 1.1037 + } 1.1038 + tmp_ip = _PR_IN6_V4MAPPED_TO_IPADDR((PRIPv6Addr *) 1.1039 + &hostaddr->ipv6.ip); 1.1040 + addr = &tmp_ip; 1.1041 + addrlen = sizeof(tmp_ip); 1.1042 + } 1.1043 + } else { 1.1044 + PR_ASSERT(hostaddr->raw.family == AF_INET); 1.1045 + PR_ASSERT(af == AF_INET); 1.1046 + addr = &hostaddr->inet.ip; 1.1047 + addrlen = sizeof(hostaddr->inet.ip); 1.1048 + } 1.1049 + 1.1050 +#if defined(_PR_HAVE_GETHOST_R) 1.1051 + tmpbuf = localbuf; 1.1052 + if (bufsize > sizeof(localbuf)) 1.1053 + { 1.1054 + tmpbuf = (char *)PR_Malloc(bufsize); 1.1055 + if (NULL == tmpbuf) 1.1056 + { 1.1057 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.1058 + return rv; 1.1059 + } 1.1060 + } 1.1061 +#endif 1.1062 + 1.1063 + /* Do not need to lock the DNS lock if getipnodebyaddr() is called */ 1.1064 +#if defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6) 1.1065 + h = getipnodebyaddr(addr, addrlen, af, &error_num); 1.1066 +#elif defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6_PROBE) 1.1067 + if (_pr_ipv6_is_present()) 1.1068 + { 1.1069 +#ifdef PR_GETIPNODE_NOT_THREADSAFE 1.1070 + LOCK_DNS(); 1.1071 +#endif 1.1072 + h = (*((_pr_getipnodebyaddr_t)_pr_getipnodebyaddr_fp))(addr, addrlen, 1.1073 + af, &error_num); 1.1074 + } 1.1075 + else 1.1076 + { 1.1077 + LOCK_DNS(); 1.1078 + h = GETHOSTBYADDR(addr, addrlen, af); 1.1079 + } 1.1080 +#else /* _PR_HAVE_GETIPNODEBYADDR */ 1.1081 + LOCK_DNS(); 1.1082 + h = GETHOSTBYADDR(addr, addrlen, af); 1.1083 +#endif /* _PR_HAVE_GETIPNODEBYADDR */ 1.1084 + if (NULL == h) 1.1085 + { 1.1086 +#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR) 1.1087 + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num); 1.1088 +#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYADDR) 1.1089 + if (_pr_ipv6_is_present()) 1.1090 + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num); 1.1091 + else 1.1092 + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO()); 1.1093 +#else 1.1094 + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO()); 1.1095 +#endif 1.1096 + } 1.1097 + else 1.1098 + { 1.1099 + _PRIPAddrConversion conversion = _PRIPAddrNoConversion; 1.1100 + if (hostaddr->raw.family == PR_AF_INET6) { 1.1101 + if (af == AF_INET) { 1.1102 + if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr*) 1.1103 + &hostaddr->ipv6.ip)) { 1.1104 + conversion = _PRIPAddrIPv4Mapped; 1.1105 + } else if (_PR_IN6_IS_ADDR_V4COMPAT((PRIPv6Addr *) 1.1106 + &hostaddr->ipv6.ip)) { 1.1107 + conversion = _PRIPAddrIPv4Compat; 1.1108 + } 1.1109 + } 1.1110 + } 1.1111 + rv = CopyHostent(h, &buf, &bufsize, conversion, hostentry); 1.1112 + if (PR_SUCCESS != rv) { 1.1113 + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); 1.1114 + } 1.1115 +#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR) 1.1116 + freehostent(h); 1.1117 +#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYADDR) 1.1118 + if (_pr_ipv6_is_present()) 1.1119 + (*((_pr_freehostent_t)_pr_freehostent_fp))(h); 1.1120 +#endif 1.1121 + } 1.1122 + 1.1123 + /* Must match the convoluted logic above for LOCK_DNS() */ 1.1124 +#if defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6) 1.1125 +#elif defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6_PROBE) 1.1126 +#ifdef PR_GETIPNODE_NOT_THREADSAFE 1.1127 + UNLOCK_DNS(); 1.1128 +#else 1.1129 + if (!_pr_ipv6_is_present()) 1.1130 + UNLOCK_DNS(); 1.1131 +#endif 1.1132 +#else /* _PR_HAVE_GETIPNODEBYADDR */ 1.1133 + UNLOCK_DNS(); 1.1134 +#endif /* _PR_HAVE_GETIPNODEBYADDR */ 1.1135 + 1.1136 +#if defined(_PR_HAVE_GETHOST_R) 1.1137 + if (tmpbuf != localbuf) 1.1138 + PR_Free(tmpbuf); 1.1139 +#endif 1.1140 + 1.1141 + return rv; 1.1142 +} 1.1143 + 1.1144 +/******************************************************************************/ 1.1145 +/* 1.1146 + * Some systems define a reentrant version of getprotobyname(). Too bad 1.1147 + * the signature isn't always the same. But hey, they tried. If there 1.1148 + * is such a definition, use it. Otherwise, grab a lock and do it here. 1.1149 + */ 1.1150 +/******************************************************************************/ 1.1151 + 1.1152 +#if !defined(_PR_HAVE_GETPROTO_R) 1.1153 +/* 1.1154 + * This may seem like a silly thing to do, but the compiler SHOULD 1.1155 + * complain if getprotobyname_r() is implemented on some system and 1.1156 + * we're not using it. For sure these signatures are different than 1.1157 + * any usable implementation. 1.1158 + */ 1.1159 + 1.1160 +#if defined(ANDROID) 1.1161 +/* Android's Bionic libc system includes prototypes for these in netdb.h, 1.1162 + * but doesn't actually include implementations. It uses the 5-arg form, 1.1163 + * so these functions end up not matching the prototype. So just rename 1.1164 + * them if not found. 1.1165 + */ 1.1166 +#define getprotobyname_r _pr_getprotobyname_r 1.1167 +#define getprotobynumber_r _pr_getprotobynumber_r 1.1168 +#endif 1.1169 + 1.1170 +static struct protoent *getprotobyname_r(const char* name) 1.1171 +{ 1.1172 + return getprotobyname(name); 1.1173 +} /* getprotobyname_r */ 1.1174 + 1.1175 +static struct protoent *getprotobynumber_r(PRInt32 number) 1.1176 +{ 1.1177 + return getprotobynumber(number); 1.1178 +} /* getprotobynumber_r */ 1.1179 + 1.1180 +#endif /* !defined(_PR_HAVE_GETPROTO_R) */ 1.1181 + 1.1182 +PR_IMPLEMENT(PRStatus) PR_GetProtoByName( 1.1183 + const char* name, char* buffer, PRInt32 buflen, PRProtoEnt* result) 1.1184 +{ 1.1185 + PRStatus rv = PR_SUCCESS; 1.1186 +#if defined(_PR_HAVE_GETPROTO_R) 1.1187 + struct protoent* res = (struct protoent*)result; 1.1188 +#endif 1.1189 + 1.1190 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.1191 + 1.1192 +#if defined(_PR_HAVE_GETPROTO_R_INT) 1.1193 + { 1.1194 + /* 1.1195 + ** The protoent_data has a pointer as the first field. 1.1196 + ** That implies the buffer better be aligned, and char* 1.1197 + ** doesn't promise much. 1.1198 + */ 1.1199 + PRUptrdiff aligned = (PRUptrdiff)buffer; 1.1200 + if (0 != (aligned & (sizeof(struct protoent_data*) - 1))) 1.1201 + { 1.1202 + aligned += sizeof(struct protoent_data*) - 1; 1.1203 + aligned &= ~(sizeof(struct protoent_data*) - 1); 1.1204 + buflen -= (aligned - (PRUptrdiff)buffer); 1.1205 + buffer = (char*)aligned; 1.1206 + } 1.1207 + } 1.1208 +#endif /* defined(_PR_HAVE_GETPROTO_R_INT) */ 1.1209 + 1.1210 + if (PR_NETDB_BUF_SIZE > buflen) 1.1211 + { 1.1212 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.1213 + return PR_FAILURE; 1.1214 + } 1.1215 + 1.1216 +#if defined(_PR_HAVE_GETPROTO_R_POINTER) 1.1217 + if (NULL == getprotobyname_r(name, res, buffer, buflen)) 1.1218 + { 1.1219 + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); 1.1220 + return PR_FAILURE; 1.1221 + } 1.1222 +#elif defined(_PR_HAVE_GETPROTO_R_INT) 1.1223 + /* 1.1224 + ** The buffer needs to be zero'd, and it should be 1.1225 + ** at least the size of a struct protoent_data. 1.1226 + */ 1.1227 + memset(buffer, 0, buflen); 1.1228 + if (-1 == getprotobyname_r(name, res, (struct protoent_data*)buffer)) 1.1229 + { 1.1230 + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); 1.1231 + return PR_FAILURE; 1.1232 + } 1.1233 +#elif defined(_PR_HAVE_5_ARG_GETPROTO_R) 1.1234 + /* The 5th argument for getprotobyname_r() cannot be NULL */ 1.1235 + if (-1 == getprotobyname_r(name, res, buffer, buflen, &res)) 1.1236 + { 1.1237 + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); 1.1238 + return PR_FAILURE; 1.1239 + } 1.1240 +#else /* do it the hard way */ 1.1241 + { 1.1242 + struct protoent *staticBuf; 1.1243 + PR_Lock(_getproto_lock); 1.1244 + staticBuf = getprotobyname_r(name); 1.1245 + if (NULL == staticBuf) 1.1246 + { 1.1247 + rv = PR_FAILURE; 1.1248 + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); 1.1249 + } 1.1250 + else 1.1251 + { 1.1252 +#if defined(SYMBIAN) 1.1253 + char* aliases[2]; 1.1254 + AssignAliases(staticBuf, aliases); 1.1255 +#endif 1.1256 + rv = CopyProtoent(staticBuf, buffer, buflen, result); 1.1257 + if (PR_FAILURE == rv) 1.1258 + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); 1.1259 + } 1.1260 + PR_Unlock(_getproto_lock); 1.1261 + } 1.1262 +#endif /* all that */ 1.1263 + return rv; 1.1264 +} 1.1265 + 1.1266 +PR_IMPLEMENT(PRStatus) PR_GetProtoByNumber( 1.1267 + PRInt32 number, char* buffer, PRInt32 buflen, PRProtoEnt* result) 1.1268 +{ 1.1269 + PRStatus rv = PR_SUCCESS; 1.1270 +#if defined(_PR_HAVE_GETPROTO_R) 1.1271 + struct protoent* res = (struct protoent*)result; 1.1272 +#endif 1.1273 + 1.1274 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.1275 + 1.1276 +#if defined(_PR_HAVE_GETPROTO_R_INT) 1.1277 + { 1.1278 + /* 1.1279 + ** The protoent_data has a pointer as the first field. 1.1280 + ** That implies the buffer better be aligned, and char* 1.1281 + ** doesn't promise much. 1.1282 + */ 1.1283 + PRUptrdiff aligned = (PRUptrdiff)buffer; 1.1284 + if (0 != (aligned & (sizeof(struct protoent_data*) - 1))) 1.1285 + { 1.1286 + aligned += sizeof(struct protoent_data*) - 1; 1.1287 + aligned &= ~(sizeof(struct protoent_data*) - 1); 1.1288 + buflen -= (aligned - (PRUptrdiff)buffer); 1.1289 + buffer = (char*)aligned; 1.1290 + } 1.1291 + } 1.1292 +#endif /* defined(_PR_HAVE_GETPROTO_R_INT) */ 1.1293 + 1.1294 + if (PR_NETDB_BUF_SIZE > buflen) 1.1295 + { 1.1296 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.1297 + return PR_FAILURE; 1.1298 + } 1.1299 + 1.1300 +#if defined(_PR_HAVE_GETPROTO_R_POINTER) 1.1301 + if (NULL == getprotobynumber_r(number, res, buffer, buflen)) 1.1302 + { 1.1303 + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); 1.1304 + return PR_FAILURE; 1.1305 + } 1.1306 + 1.1307 +#elif defined(_PR_HAVE_GETPROTO_R_INT) 1.1308 + /* 1.1309 + ** The buffer needs to be zero'd for these OS's. 1.1310 + */ 1.1311 + memset(buffer, 0, buflen); 1.1312 + if (-1 == getprotobynumber_r(number, res, (struct protoent_data*)buffer)) 1.1313 + { 1.1314 + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); 1.1315 + return PR_FAILURE; 1.1316 + } 1.1317 +#elif defined(_PR_HAVE_5_ARG_GETPROTO_R) 1.1318 + /* The 5th argument for getprotobynumber_r() cannot be NULL */ 1.1319 + if (-1 == getprotobynumber_r(number, res, buffer, buflen, &res)) 1.1320 + { 1.1321 + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); 1.1322 + return PR_FAILURE; 1.1323 + } 1.1324 +#else /* do it the hard way */ 1.1325 + { 1.1326 + struct protoent *staticBuf; 1.1327 + PR_Lock(_getproto_lock); 1.1328 + staticBuf = getprotobynumber_r(number); 1.1329 + if (NULL == staticBuf) 1.1330 + { 1.1331 + rv = PR_FAILURE; 1.1332 + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); 1.1333 + } 1.1334 + else 1.1335 + { 1.1336 +#if defined(SYMBIAN) 1.1337 + char* aliases[2]; 1.1338 + AssignAliases(staticBuf, aliases); 1.1339 +#endif 1.1340 + rv = CopyProtoent(staticBuf, buffer, buflen, result); 1.1341 + if (PR_FAILURE == rv) 1.1342 + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); 1.1343 + } 1.1344 + PR_Unlock(_getproto_lock); 1.1345 + } 1.1346 +#endif /* all that crap */ 1.1347 + return rv; 1.1348 + 1.1349 +} 1.1350 + 1.1351 +PRUintn _PR_NetAddrSize(const PRNetAddr* addr) 1.1352 +{ 1.1353 + PRUintn addrsize; 1.1354 + 1.1355 + /* 1.1356 + * RFC 2553 added a new field (sin6_scope_id) to 1.1357 + * struct sockaddr_in6. PRNetAddr's ipv6 member has a 1.1358 + * scope_id field to match the new field. In order to 1.1359 + * work with older implementations supporting RFC 2133, 1.1360 + * we take the size of struct sockaddr_in6 instead of 1.1361 + * addr->ipv6. 1.1362 + */ 1.1363 + if (AF_INET == addr->raw.family) 1.1364 + addrsize = sizeof(addr->inet); 1.1365 + else if (PR_AF_INET6 == addr->raw.family) 1.1366 +#if defined(_PR_INET6) 1.1367 + addrsize = sizeof(struct sockaddr_in6); 1.1368 +#else 1.1369 + addrsize = sizeof(addr->ipv6); 1.1370 +#endif 1.1371 +#if defined(XP_UNIX) || defined(XP_OS2) 1.1372 + else if (AF_UNIX == addr->raw.family) 1.1373 + addrsize = sizeof(addr->local); 1.1374 +#endif 1.1375 + else addrsize = 0; 1.1376 + 1.1377 + return addrsize; 1.1378 +} /* _PR_NetAddrSize */ 1.1379 + 1.1380 +PR_IMPLEMENT(PRIntn) PR_EnumerateHostEnt( 1.1381 + PRIntn enumIndex, const PRHostEnt *hostEnt, PRUint16 port, PRNetAddr *address) 1.1382 +{ 1.1383 + void *addr = hostEnt->h_addr_list[enumIndex++]; 1.1384 + memset(address, 0, sizeof(PRNetAddr)); 1.1385 + if (NULL == addr) enumIndex = 0; 1.1386 + else 1.1387 + { 1.1388 + address->raw.family = hostEnt->h_addrtype; 1.1389 + if (PR_AF_INET6 == hostEnt->h_addrtype) 1.1390 + { 1.1391 + address->ipv6.port = htons(port); 1.1392 + address->ipv6.flowinfo = 0; 1.1393 + address->ipv6.scope_id = 0; 1.1394 + memcpy(&address->ipv6.ip, addr, hostEnt->h_length); 1.1395 + } 1.1396 + else 1.1397 + { 1.1398 + PR_ASSERT(AF_INET == hostEnt->h_addrtype); 1.1399 + address->inet.port = htons(port); 1.1400 + memcpy(&address->inet.ip, addr, hostEnt->h_length); 1.1401 + } 1.1402 + } 1.1403 + return enumIndex; 1.1404 +} /* PR_EnumerateHostEnt */ 1.1405 + 1.1406 +PR_IMPLEMENT(PRStatus) PR_InitializeNetAddr( 1.1407 + PRNetAddrValue val, PRUint16 port, PRNetAddr *addr) 1.1408 +{ 1.1409 + PRStatus rv = PR_SUCCESS; 1.1410 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.1411 + 1.1412 + if (val != PR_IpAddrNull) memset(addr, 0, sizeof(addr->inet)); 1.1413 + addr->inet.family = AF_INET; 1.1414 + addr->inet.port = htons(port); 1.1415 + switch (val) 1.1416 + { 1.1417 + case PR_IpAddrNull: 1.1418 + break; /* don't overwrite the address */ 1.1419 + case PR_IpAddrAny: 1.1420 + addr->inet.ip = htonl(INADDR_ANY); 1.1421 + break; 1.1422 + case PR_IpAddrLoopback: 1.1423 + addr->inet.ip = htonl(INADDR_LOOPBACK); 1.1424 + break; 1.1425 + default: 1.1426 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.1427 + rv = PR_FAILURE; 1.1428 + } 1.1429 + return rv; 1.1430 +} /* PR_InitializeNetAddr */ 1.1431 + 1.1432 +PR_IMPLEMENT(PRStatus) PR_SetNetAddr( 1.1433 + PRNetAddrValue val, PRUint16 af, PRUint16 port, PRNetAddr *addr) 1.1434 +{ 1.1435 + PRStatus rv = PR_SUCCESS; 1.1436 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.1437 + 1.1438 + if (af == PR_AF_INET6) 1.1439 + { 1.1440 + if (val != PR_IpAddrNull) memset(addr, 0, sizeof(addr->ipv6)); 1.1441 + addr->ipv6.family = af; 1.1442 + addr->ipv6.port = htons(port); 1.1443 + addr->ipv6.flowinfo = 0; 1.1444 + addr->ipv6.scope_id = 0; 1.1445 + switch (val) 1.1446 + { 1.1447 + case PR_IpAddrNull: 1.1448 + break; /* don't overwrite the address */ 1.1449 + case PR_IpAddrAny: 1.1450 + addr->ipv6.ip = _pr_in6addr_any; 1.1451 + break; 1.1452 + case PR_IpAddrLoopback: 1.1453 + addr->ipv6.ip = _pr_in6addr_loopback; 1.1454 + break; 1.1455 + default: 1.1456 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.1457 + rv = PR_FAILURE; 1.1458 + } 1.1459 + } 1.1460 + else 1.1461 + { 1.1462 + if (val != PR_IpAddrNull) memset(addr, 0, sizeof(addr->inet)); 1.1463 + addr->inet.family = af; 1.1464 + addr->inet.port = htons(port); 1.1465 + switch (val) 1.1466 + { 1.1467 + case PR_IpAddrNull: 1.1468 + break; /* don't overwrite the address */ 1.1469 + case PR_IpAddrAny: 1.1470 + addr->inet.ip = htonl(INADDR_ANY); 1.1471 + break; 1.1472 + case PR_IpAddrLoopback: 1.1473 + addr->inet.ip = htonl(INADDR_LOOPBACK); 1.1474 + break; 1.1475 + default: 1.1476 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.1477 + rv = PR_FAILURE; 1.1478 + } 1.1479 + } 1.1480 + return rv; 1.1481 +} /* PR_SetNetAddr */ 1.1482 + 1.1483 +PR_IMPLEMENT(PRBool) 1.1484 +PR_IsNetAddrType(const PRNetAddr *addr, PRNetAddrValue val) 1.1485 +{ 1.1486 + if (addr->raw.family == PR_AF_INET6) { 1.1487 + if (val == PR_IpAddrAny) { 1.1488 + if (_PR_IN6_IS_ADDR_UNSPECIFIED((PRIPv6Addr *)&addr->ipv6.ip)) { 1.1489 + return PR_TRUE; 1.1490 + } else if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip) 1.1491 + && _PR_IN6_V4MAPPED_TO_IPADDR((PRIPv6Addr *)&addr->ipv6.ip) 1.1492 + == htonl(INADDR_ANY)) { 1.1493 + return PR_TRUE; 1.1494 + } 1.1495 + } else if (val == PR_IpAddrLoopback) { 1.1496 + if (_PR_IN6_IS_ADDR_LOOPBACK((PRIPv6Addr *)&addr->ipv6.ip)) { 1.1497 + return PR_TRUE; 1.1498 + } else if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip) 1.1499 + && _PR_IN6_V4MAPPED_TO_IPADDR((PRIPv6Addr *)&addr->ipv6.ip) 1.1500 + == htonl(INADDR_LOOPBACK)) { 1.1501 + return PR_TRUE; 1.1502 + } 1.1503 + } else if (val == PR_IpAddrV4Mapped 1.1504 + && _PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip)) { 1.1505 + return PR_TRUE; 1.1506 + } 1.1507 + } else { 1.1508 + if (addr->raw.family == AF_INET) { 1.1509 + if (val == PR_IpAddrAny && addr->inet.ip == htonl(INADDR_ANY)) { 1.1510 + return PR_TRUE; 1.1511 + } else if (val == PR_IpAddrLoopback 1.1512 + && addr->inet.ip == htonl(INADDR_LOOPBACK)) { 1.1513 + return PR_TRUE; 1.1514 + } 1.1515 + } 1.1516 + } 1.1517 + return PR_FALSE; 1.1518 +} 1.1519 + 1.1520 +extern int pr_inet_aton(const char *cp, PRUint32 *addr); 1.1521 + 1.1522 +#define XX 127 1.1523 +static const unsigned char index_hex[256] = { 1.1524 + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 1.1525 + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 1.1526 + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 1.1527 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,XX,XX, XX,XX,XX,XX, 1.1528 + XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX, 1.1529 + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 1.1530 + XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX, 1.1531 + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 1.1532 + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 1.1533 + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 1.1534 + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 1.1535 + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 1.1536 + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 1.1537 + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 1.1538 + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 1.1539 + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, 1.1540 +}; 1.1541 + 1.1542 +/* 1.1543 + * StringToV6Addr() returns 1 if the conversion succeeds, 1.1544 + * or 0 if the input is not a valid IPv6 address string. 1.1545 + * (Same as inet_pton(AF_INET6, string, addr).) 1.1546 + */ 1.1547 +static int StringToV6Addr(const char *string, PRIPv6Addr *addr) 1.1548 +{ 1.1549 + const unsigned char *s = (const unsigned char *)string; 1.1550 + int section = 0; /* index of the current section (a 16-bit 1.1551 + * piece of the address */ 1.1552 + int double_colon = -1; /* index of the section after the first 1.1553 + * 16-bit group of zeros represented by 1.1554 + * the double colon */ 1.1555 + unsigned int val; 1.1556 + int len; 1.1557 + 1.1558 + /* Handle initial (double) colon */ 1.1559 + if (*s == ':') { 1.1560 + if (s[1] != ':') return 0; 1.1561 + s += 2; 1.1562 + addr->pr_s6_addr16[0] = 0; 1.1563 + section = double_colon = 1; 1.1564 + } 1.1565 + 1.1566 + while (*s) { 1.1567 + if (section == 8) return 0; /* too long */ 1.1568 + if (*s == ':') { 1.1569 + if (double_colon != -1) return 0; /* two double colons */ 1.1570 + addr->pr_s6_addr16[section++] = 0; 1.1571 + double_colon = section; 1.1572 + s++; 1.1573 + continue; 1.1574 + } 1.1575 + for (len = val = 0; len < 4 && index_hex[*s] != XX; len++) { 1.1576 + val = (val << 4) + index_hex[*s++]; 1.1577 + } 1.1578 + if (*s == '.') { 1.1579 + if (len == 0) return 0; /* nothing between : and . */ 1.1580 + break; 1.1581 + } 1.1582 + if (*s == ':') { 1.1583 + s++; 1.1584 + if (!*s) return 0; /* cannot end with single colon */ 1.1585 + } else if (*s) { 1.1586 + return 0; /* bad character */ 1.1587 + } 1.1588 + addr->pr_s6_addr16[section++] = htons((unsigned short)val); 1.1589 + } 1.1590 + 1.1591 + if (*s == '.') { 1.1592 + /* Have a trailing v4 format address */ 1.1593 + if (section > 6) return 0; /* not enough room */ 1.1594 + 1.1595 + /* 1.1596 + * The number before the '.' is decimal, but we parsed it 1.1597 + * as hex. That means it is in BCD. Check it for validity 1.1598 + * and convert it to binary. 1.1599 + */ 1.1600 + if (val > 0x0255 || (val & 0xf0) > 0x90 || (val & 0xf) > 9) return 0; 1.1601 + val = (val >> 8) * 100 + ((val >> 4) & 0xf) * 10 + (val & 0xf); 1.1602 + addr->pr_s6_addr[2 * section] = val; 1.1603 + 1.1604 + s++; 1.1605 + val = index_hex[*s++]; 1.1606 + if (val > 9) return 0; 1.1607 + while (*s >= '0' && *s <= '9') { 1.1608 + val = val * 10 + *s++ - '0'; 1.1609 + if (val > 255) return 0; 1.1610 + } 1.1611 + if (*s != '.') return 0; /* must have exactly 4 decimal numbers */ 1.1612 + addr->pr_s6_addr[2 * section + 1] = val; 1.1613 + section++; 1.1614 + 1.1615 + s++; 1.1616 + val = index_hex[*s++]; 1.1617 + if (val > 9) return 0; 1.1618 + while (*s >= '0' && *s <= '9') { 1.1619 + val = val * 10 + *s++ - '0'; 1.1620 + if (val > 255) return 0; 1.1621 + } 1.1622 + if (*s != '.') return 0; /* must have exactly 4 decimal numbers */ 1.1623 + addr->pr_s6_addr[2 * section] = val; 1.1624 + 1.1625 + s++; 1.1626 + val = index_hex[*s++]; 1.1627 + if (val > 9) return 0; 1.1628 + while (*s >= '0' && *s <= '9') { 1.1629 + val = val * 10 + *s++ - '0'; 1.1630 + if (val > 255) return 0; 1.1631 + } 1.1632 + if (*s) return 0; /* must have exactly 4 decimal numbers */ 1.1633 + addr->pr_s6_addr[2 * section + 1] = val; 1.1634 + section++; 1.1635 + } 1.1636 + 1.1637 + if (double_colon != -1) { 1.1638 + /* Stretch the double colon */ 1.1639 + int tosection; 1.1640 + int ncopy = section - double_colon; 1.1641 + for (tosection = 7; ncopy--; tosection--) { 1.1642 + addr->pr_s6_addr16[tosection] = 1.1643 + addr->pr_s6_addr16[double_colon + ncopy]; 1.1644 + } 1.1645 + while (tosection >= double_colon) { 1.1646 + addr->pr_s6_addr16[tosection--] = 0; 1.1647 + } 1.1648 + } else if (section != 8) { 1.1649 + return 0; /* too short */ 1.1650 + } 1.1651 + return 1; 1.1652 +} 1.1653 +#undef XX 1.1654 + 1.1655 +#ifndef _PR_HAVE_INET_NTOP 1.1656 +static const char *basis_hex = "0123456789abcdef"; 1.1657 + 1.1658 +/* 1.1659 + * V6AddrToString() returns a pointer to the buffer containing 1.1660 + * the text string if the conversion succeeds, and NULL otherwise. 1.1661 + * (Same as inet_ntop(AF_INET6, addr, buf, size), except that errno 1.1662 + * is not set on failure.) 1.1663 + */ 1.1664 +static const char *V6AddrToString( 1.1665 + const PRIPv6Addr *addr, char *buf, PRUint32 size) 1.1666 +{ 1.1667 +#define STUFF(c) do { \ 1.1668 + if (!size--) return NULL; \ 1.1669 + *buf++ = (c); \ 1.1670 +} while (0) 1.1671 + 1.1672 + int double_colon = -1; /* index of the first 16-bit 1.1673 + * group of zeros represented 1.1674 + * by the double colon */ 1.1675 + int double_colon_length = 1; /* use double colon only if 1.1676 + * there are two or more 16-bit 1.1677 + * groups of zeros */ 1.1678 + int zero_length; 1.1679 + int section; 1.1680 + unsigned int val; 1.1681 + const char *bufcopy = buf; 1.1682 + 1.1683 + /* Scan to find the placement of the double colon */ 1.1684 + for (section = 0; section < 8; section++) { 1.1685 + if (addr->pr_s6_addr16[section] == 0) { 1.1686 + zero_length = 1; 1.1687 + section++; 1.1688 + while (section < 8 && addr->pr_s6_addr16[section] == 0) { 1.1689 + zero_length++; 1.1690 + section++; 1.1691 + } 1.1692 + /* Select the longest sequence of zeros */ 1.1693 + if (zero_length > double_colon_length) { 1.1694 + double_colon = section - zero_length; 1.1695 + double_colon_length = zero_length; 1.1696 + } 1.1697 + } 1.1698 + } 1.1699 + 1.1700 + /* Now start converting to a string */ 1.1701 + section = 0; 1.1702 + 1.1703 + if (double_colon == 0) { 1.1704 + if (double_colon_length == 6 || 1.1705 + (double_colon_length == 5 && addr->pr_s6_addr16[5] == 0xffff)) { 1.1706 + /* ipv4 format address */ 1.1707 + STUFF(':'); 1.1708 + STUFF(':'); 1.1709 + if (double_colon_length == 5) { 1.1710 + STUFF('f'); 1.1711 + STUFF('f'); 1.1712 + STUFF('f'); 1.1713 + STUFF('f'); 1.1714 + STUFF(':'); 1.1715 + } 1.1716 + if (addr->pr_s6_addr[12] > 99) STUFF(addr->pr_s6_addr[12]/100 + '0'); 1.1717 + if (addr->pr_s6_addr[12] > 9) STUFF((addr->pr_s6_addr[12]%100)/10 + '0'); 1.1718 + STUFF(addr->pr_s6_addr[12]%10 + '0'); 1.1719 + STUFF('.'); 1.1720 + if (addr->pr_s6_addr[13] > 99) STUFF(addr->pr_s6_addr[13]/100 + '0'); 1.1721 + if (addr->pr_s6_addr[13] > 9) STUFF((addr->pr_s6_addr[13]%100)/10 + '0'); 1.1722 + STUFF(addr->pr_s6_addr[13]%10 + '0'); 1.1723 + STUFF('.'); 1.1724 + if (addr->pr_s6_addr[14] > 99) STUFF(addr->pr_s6_addr[14]/100 + '0'); 1.1725 + if (addr->pr_s6_addr[14] > 9) STUFF((addr->pr_s6_addr[14]%100)/10 + '0'); 1.1726 + STUFF(addr->pr_s6_addr[14]%10 + '0'); 1.1727 + STUFF('.'); 1.1728 + if (addr->pr_s6_addr[15] > 99) STUFF(addr->pr_s6_addr[15]/100 + '0'); 1.1729 + if (addr->pr_s6_addr[15] > 9) STUFF((addr->pr_s6_addr[15]%100)/10 + '0'); 1.1730 + STUFF(addr->pr_s6_addr[15]%10 + '0'); 1.1731 + STUFF('\0'); 1.1732 + return bufcopy; 1.1733 + } 1.1734 + } 1.1735 + 1.1736 + while (section < 8) { 1.1737 + if (section == double_colon) { 1.1738 + STUFF(':'); 1.1739 + STUFF(':'); 1.1740 + section += double_colon_length; 1.1741 + continue; 1.1742 + } 1.1743 + val = ntohs(addr->pr_s6_addr16[section]); 1.1744 + if (val > 0xfff) { 1.1745 + STUFF(basis_hex[val >> 12]); 1.1746 + } 1.1747 + if (val > 0xff) { 1.1748 + STUFF(basis_hex[(val >> 8) & 0xf]); 1.1749 + } 1.1750 + if (val > 0xf) { 1.1751 + STUFF(basis_hex[(val >> 4) & 0xf]); 1.1752 + } 1.1753 + STUFF(basis_hex[val & 0xf]); 1.1754 + section++; 1.1755 + if (section < 8 && section != double_colon) STUFF(':'); 1.1756 + } 1.1757 + STUFF('\0'); 1.1758 + return bufcopy; 1.1759 +#undef STUFF 1.1760 +} 1.1761 +#endif /* !_PR_HAVE_INET_NTOP */ 1.1762 + 1.1763 +/* 1.1764 + * Convert an IPv4 addr to an (IPv4-mapped) IPv6 addr 1.1765 + */ 1.1766 +PR_IMPLEMENT(void) PR_ConvertIPv4AddrToIPv6(PRUint32 v4addr, PRIPv6Addr *v6addr) 1.1767 +{ 1.1768 + PRUint8 *dstp; 1.1769 + dstp = v6addr->pr_s6_addr; 1.1770 + memset(dstp, 0, 10); 1.1771 + memset(dstp + 10, 0xff, 2); 1.1772 + memcpy(dstp + 12,(char *) &v4addr, 4); 1.1773 +} 1.1774 + 1.1775 +PR_IMPLEMENT(PRUint16) PR_ntohs(PRUint16 n) { return ntohs(n); } 1.1776 +PR_IMPLEMENT(PRUint32) PR_ntohl(PRUint32 n) { return ntohl(n); } 1.1777 +PR_IMPLEMENT(PRUint16) PR_htons(PRUint16 n) { return htons(n); } 1.1778 +PR_IMPLEMENT(PRUint32) PR_htonl(PRUint32 n) { return htonl(n); } 1.1779 +PR_IMPLEMENT(PRUint64) PR_ntohll(PRUint64 n) 1.1780 +{ 1.1781 +#ifdef IS_BIG_ENDIAN 1.1782 + return n; 1.1783 +#else 1.1784 + PRUint64 tmp; 1.1785 + PRUint32 hi, lo; 1.1786 + LL_L2UI(lo, n); 1.1787 + LL_SHR(tmp, n, 32); 1.1788 + LL_L2UI(hi, tmp); 1.1789 + hi = PR_ntohl(hi); 1.1790 + lo = PR_ntohl(lo); 1.1791 + LL_UI2L(n, lo); 1.1792 + LL_SHL(n, n, 32); 1.1793 + LL_UI2L(tmp, hi); 1.1794 + LL_ADD(n, n, tmp); 1.1795 + return n; 1.1796 +#endif 1.1797 +} /* ntohll */ 1.1798 + 1.1799 +PR_IMPLEMENT(PRUint64) PR_htonll(PRUint64 n) 1.1800 +{ 1.1801 +#ifdef IS_BIG_ENDIAN 1.1802 + return n; 1.1803 +#else 1.1804 + PRUint64 tmp; 1.1805 + PRUint32 hi, lo; 1.1806 + LL_L2UI(lo, n); 1.1807 + LL_SHR(tmp, n, 32); 1.1808 + LL_L2UI(hi, tmp); 1.1809 + hi = htonl(hi); 1.1810 + lo = htonl(lo); 1.1811 + LL_UI2L(n, lo); 1.1812 + LL_SHL(n, n, 32); 1.1813 + LL_UI2L(tmp, hi); 1.1814 + LL_ADD(n, n, tmp); 1.1815 + return n; 1.1816 +#endif 1.1817 +} /* htonll */ 1.1818 + 1.1819 + 1.1820 +/* 1.1821 + * Implementation of PR_GetAddrInfoByName and friends 1.1822 + * 1.1823 + * Compile-time options: 1.1824 + * 1.1825 + * _PR_HAVE_GETADDRINFO Define this macro if the target system provides 1.1826 + * getaddrinfo. With this defined, NSPR will require 1.1827 + * getaddrinfo at run time. If this if not defined, 1.1828 + * then NSPR will attempt to dynamically resolve 1.1829 + * getaddrinfo, falling back to PR_GetHostByName if 1.1830 + * getaddrinfo does not exist on the target system. 1.1831 + * 1.1832 + * Since getaddrinfo is a relatively new system call on many systems, 1.1833 + * we are forced to dynamically resolve it at run time in most cases. 1.1834 + * The exception includes any system (such as Mac OS X) that is known to 1.1835 + * provide getaddrinfo in all versions that NSPR cares to support. 1.1836 + */ 1.1837 + 1.1838 +#if defined(_PR_HAVE_GETADDRINFO) 1.1839 + 1.1840 +#if defined(_PR_INET6) 1.1841 + 1.1842 +typedef struct addrinfo PRADDRINFO; 1.1843 +#define GETADDRINFO getaddrinfo 1.1844 +#define FREEADDRINFO freeaddrinfo 1.1845 +#define GETNAMEINFO getnameinfo 1.1846 + 1.1847 +#elif defined(_PR_INET6_PROBE) 1.1848 + 1.1849 +typedef struct addrinfo PRADDRINFO; 1.1850 + 1.1851 +/* getaddrinfo/freeaddrinfo/getnameinfo prototypes */ 1.1852 +#if defined(WIN32) 1.1853 +#define FUNC_MODIFIER __stdcall 1.1854 +#else 1.1855 +#define FUNC_MODIFIER 1.1856 +#endif 1.1857 +typedef int (FUNC_MODIFIER * FN_GETADDRINFO) 1.1858 + (const char *nodename, 1.1859 + const char *servname, 1.1860 + const PRADDRINFO *hints, 1.1861 + PRADDRINFO **res); 1.1862 +typedef int (FUNC_MODIFIER * FN_FREEADDRINFO) 1.1863 + (PRADDRINFO *ai); 1.1864 +typedef int (FUNC_MODIFIER * FN_GETNAMEINFO) 1.1865 + (const struct sockaddr *addr, int addrlen, 1.1866 + char *host, int hostlen, 1.1867 + char *serv, int servlen, int flags); 1.1868 + 1.1869 +/* global state */ 1.1870 +static FN_GETADDRINFO _pr_getaddrinfo = NULL; 1.1871 +static FN_FREEADDRINFO _pr_freeaddrinfo = NULL; 1.1872 +static FN_GETNAMEINFO _pr_getnameinfo = NULL; 1.1873 + 1.1874 +#define GETADDRINFO_SYMBOL "getaddrinfo" 1.1875 +#define FREEADDRINFO_SYMBOL "freeaddrinfo" 1.1876 +#define GETNAMEINFO_SYMBOL "getnameinfo" 1.1877 + 1.1878 +PRStatus 1.1879 +_pr_find_getaddrinfo(void) 1.1880 +{ 1.1881 + PRLibrary *lib; 1.1882 +#ifdef WIN32 1.1883 + /* 1.1884 + * On windows, we need to search ws2_32.dll or wship6.dll 1.1885 + * (Microsoft IPv6 Technology Preview for Windows 2000) for 1.1886 + * getaddrinfo and freeaddrinfo. These libraries might not 1.1887 + * be loaded yet. 1.1888 + */ 1.1889 + const char *libname[] = { "ws2_32.dll", "wship6.dll" }; 1.1890 + int i; 1.1891 + 1.1892 + for (i = 0; i < sizeof(libname)/sizeof(libname[0]); i++) { 1.1893 + lib = PR_LoadLibrary(libname[i]); 1.1894 + if (!lib) { 1.1895 + continue; 1.1896 + } 1.1897 + _pr_getaddrinfo = (FN_GETADDRINFO) 1.1898 + PR_FindFunctionSymbol(lib, GETADDRINFO_SYMBOL); 1.1899 + if (!_pr_getaddrinfo) { 1.1900 + PR_UnloadLibrary(lib); 1.1901 + continue; 1.1902 + } 1.1903 + _pr_freeaddrinfo = (FN_FREEADDRINFO) 1.1904 + PR_FindFunctionSymbol(lib, FREEADDRINFO_SYMBOL); 1.1905 + _pr_getnameinfo = (FN_GETNAMEINFO) 1.1906 + PR_FindFunctionSymbol(lib, GETNAMEINFO_SYMBOL); 1.1907 + if (!_pr_freeaddrinfo || !_pr_getnameinfo) { 1.1908 + PR_UnloadLibrary(lib); 1.1909 + continue; 1.1910 + } 1.1911 + /* Keep the library loaded. */ 1.1912 + return PR_SUCCESS; 1.1913 + } 1.1914 + return PR_FAILURE; 1.1915 +#else 1.1916 + /* 1.1917 + * Resolve getaddrinfo by searching all loaded libraries. Then 1.1918 + * search library containing getaddrinfo for freeaddrinfo. 1.1919 + */ 1.1920 + _pr_getaddrinfo = (FN_GETADDRINFO) 1.1921 + PR_FindFunctionSymbolAndLibrary(GETADDRINFO_SYMBOL, &lib); 1.1922 + if (!_pr_getaddrinfo) { 1.1923 + return PR_FAILURE; 1.1924 + } 1.1925 + _pr_freeaddrinfo = (FN_FREEADDRINFO) 1.1926 + PR_FindFunctionSymbol(lib, FREEADDRINFO_SYMBOL); 1.1927 + _pr_getnameinfo = (FN_GETNAMEINFO) 1.1928 + PR_FindFunctionSymbol(lib, GETNAMEINFO_SYMBOL); 1.1929 + PR_UnloadLibrary(lib); 1.1930 + if (!_pr_freeaddrinfo || !_pr_getnameinfo) { 1.1931 + return PR_FAILURE; 1.1932 + } 1.1933 + return PR_SUCCESS; 1.1934 +#endif 1.1935 +} 1.1936 + 1.1937 +#define GETADDRINFO (*_pr_getaddrinfo) 1.1938 +#define FREEADDRINFO (*_pr_freeaddrinfo) 1.1939 +#define GETNAMEINFO (*_pr_getnameinfo) 1.1940 + 1.1941 +#endif /* _PR_INET6 */ 1.1942 + 1.1943 +#endif /* _PR_HAVE_GETADDRINFO */ 1.1944 + 1.1945 +#if !defined(_PR_HAVE_GETADDRINFO) || defined(_PR_INET6_PROBE) 1.1946 +/* 1.1947 + * If getaddrinfo does not exist, then we will fall back on 1.1948 + * PR_GetHostByName, which requires that we allocate a buffer for the 1.1949 + * PRHostEnt data structure and its members. 1.1950 + */ 1.1951 +typedef struct PRAddrInfoFB { 1.1952 + char buf[PR_NETDB_BUF_SIZE]; 1.1953 + PRHostEnt hostent; 1.1954 + PRBool has_cname; 1.1955 +} PRAddrInfoFB; 1.1956 + 1.1957 +static PRAddrInfo * 1.1958 +pr_GetAddrInfoByNameFB(const char *hostname, 1.1959 + PRUint16 af, 1.1960 + PRIntn flags) 1.1961 +{ 1.1962 + PRStatus rv; 1.1963 + PRAddrInfoFB *ai; 1.1964 + /* fallback on PR_GetHostByName */ 1.1965 + ai = PR_NEW(PRAddrInfoFB); 1.1966 + if (!ai) { 1.1967 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.1968 + return NULL; 1.1969 + } 1.1970 + rv = PR_GetHostByName(hostname, ai->buf, sizeof ai->buf, &ai->hostent); 1.1971 + if (rv == PR_FAILURE) { 1.1972 + PR_Free(ai); 1.1973 + return NULL; 1.1974 + } 1.1975 + ai->has_cname = !(flags & PR_AI_NOCANONNAME); 1.1976 + 1.1977 + return (PRAddrInfo *) ai; 1.1978 +} 1.1979 +#endif /* !_PR_HAVE_GETADDRINFO || _PR_INET6_PROBE */ 1.1980 + 1.1981 +PR_IMPLEMENT(PRAddrInfo *) PR_GetAddrInfoByName(const char *hostname, 1.1982 + PRUint16 af, 1.1983 + PRIntn flags) 1.1984 +{ 1.1985 + /* restrict input to supported values */ 1.1986 + if ((af != PR_AF_INET && af != PR_AF_UNSPEC) || 1.1987 + (flags & ~ PR_AI_NOCANONNAME) != PR_AI_ADDRCONFIG) { 1.1988 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.1989 + return NULL; 1.1990 + } 1.1991 + 1.1992 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.1993 + 1.1994 +#if !defined(_PR_HAVE_GETADDRINFO) 1.1995 + return pr_GetAddrInfoByNameFB(hostname, af, flags); 1.1996 +#else 1.1997 +#if defined(_PR_INET6_PROBE) 1.1998 + if (!_pr_ipv6_is_present()) { 1.1999 + return pr_GetAddrInfoByNameFB(hostname, af, flags); 1.2000 + } 1.2001 +#endif 1.2002 + { 1.2003 + PRADDRINFO *res, hints; 1.2004 + int rv; 1.2005 + 1.2006 + /* 1.2007 + * we assume a RFC 2553 compliant getaddrinfo. this may at some 1.2008 + * point need to be customized as platforms begin to adopt the 1.2009 + * RFC 3493. 1.2010 + */ 1.2011 + 1.2012 + memset(&hints, 0, sizeof(hints)); 1.2013 + if (!(flags & PR_AI_NOCANONNAME)) 1.2014 + hints.ai_flags |= AI_CANONNAME; 1.2015 +#ifdef AI_ADDRCONFIG 1.2016 + /* 1.2017 + * Propagate AI_ADDRCONFIG to the GETADDRINFO call if PR_AI_ADDRCONFIG 1.2018 + * is set. 1.2019 + * 1.2020 + * Need a workaround for loopback host addresses: 1.2021 + * The problem is that in glibc and Windows, AI_ADDRCONFIG applies the 1.2022 + * existence of an outgoing network interface to IP addresses of the 1.2023 + * loopback interface, due to a strict interpretation of the 1.2024 + * specification. For example, if a computer does not have any 1.2025 + * outgoing IPv6 network interface, but its loopback network interface 1.2026 + * supports IPv6, a getaddrinfo call on "localhost" with AI_ADDRCONFIG 1.2027 + * won't return the IPv6 loopback address "::1", because getaddrinfo 1.2028 + * thinks the computer cannot connect to any IPv6 destination, 1.2029 + * ignoring the remote vs. local/loopback distinction. 1.2030 + */ 1.2031 + if ((flags & PR_AI_ADDRCONFIG) && 1.2032 + strcmp(hostname, "localhost") != 0 && 1.2033 + strcmp(hostname, "localhost.localdomain") != 0 && 1.2034 + strcmp(hostname, "localhost6") != 0 && 1.2035 + strcmp(hostname, "localhost6.localdomain6") != 0) { 1.2036 + hints.ai_flags |= AI_ADDRCONFIG; 1.2037 + } 1.2038 +#endif 1.2039 + hints.ai_family = (af == PR_AF_INET) ? AF_INET : AF_UNSPEC; 1.2040 + 1.2041 + /* 1.2042 + * it is important to select a socket type in the hints, otherwise we 1.2043 + * will get back repetitive entries: one for each socket type. since 1.2044 + * we do not expose ai_socktype through our API, it is okay to do this 1.2045 + * here. the application may still choose to create a socket of some 1.2046 + * other type. 1.2047 + */ 1.2048 + hints.ai_socktype = SOCK_STREAM; 1.2049 + 1.2050 + rv = GETADDRINFO(hostname, NULL, &hints, &res); 1.2051 +#ifdef AI_ADDRCONFIG 1.2052 + if (rv == EAI_BADFLAGS && (hints.ai_flags & AI_ADDRCONFIG)) { 1.2053 + hints.ai_flags &= ~AI_ADDRCONFIG; 1.2054 + rv = GETADDRINFO(hostname, NULL, &hints, &res); 1.2055 + } 1.2056 +#endif 1.2057 + if (rv == 0) 1.2058 + return (PRAddrInfo *) res; 1.2059 + 1.2060 + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, rv); 1.2061 + } 1.2062 + return NULL; 1.2063 +#endif 1.2064 +} 1.2065 + 1.2066 +PR_IMPLEMENT(void) PR_FreeAddrInfo(PRAddrInfo *ai) 1.2067 +{ 1.2068 +#if defined(_PR_HAVE_GETADDRINFO) 1.2069 +#if defined(_PR_INET6_PROBE) 1.2070 + if (!_pr_ipv6_is_present()) 1.2071 + PR_Free((PRAddrInfoFB *) ai); 1.2072 + else 1.2073 +#endif 1.2074 + FREEADDRINFO((PRADDRINFO *) ai); 1.2075 +#else 1.2076 + PR_Free((PRAddrInfoFB *) ai); 1.2077 +#endif 1.2078 +} 1.2079 + 1.2080 +PR_IMPLEMENT(void *) PR_EnumerateAddrInfo(void *iterPtr, 1.2081 + const PRAddrInfo *base, 1.2082 + PRUint16 port, 1.2083 + PRNetAddr *result) 1.2084 +{ 1.2085 +#if defined(_PR_HAVE_GETADDRINFO) 1.2086 + PRADDRINFO *ai; 1.2087 +#if defined(_PR_INET6_PROBE) 1.2088 + if (!_pr_ipv6_is_present()) { 1.2089 + /* using PRAddrInfoFB */ 1.2090 + PRIntn iter = (PRIntn)(PRPtrdiff) iterPtr; 1.2091 + iter = PR_EnumerateHostEnt(iter, &((PRAddrInfoFB *) base)->hostent, port, result); 1.2092 + if (iter < 0) 1.2093 + iter = 0; 1.2094 + return (void *)(PRPtrdiff) iter; 1.2095 + } 1.2096 +#endif 1.2097 + 1.2098 + if (iterPtr) 1.2099 + ai = ((PRADDRINFO *) iterPtr)->ai_next; 1.2100 + else 1.2101 + ai = (PRADDRINFO *) base; 1.2102 + 1.2103 + while (ai && ai->ai_addrlen > sizeof(PRNetAddr)) 1.2104 + ai = ai->ai_next; 1.2105 + 1.2106 + if (ai) { 1.2107 + /* copy sockaddr to PRNetAddr */ 1.2108 + memcpy(result, ai->ai_addr, ai->ai_addrlen); 1.2109 + result->raw.family = ai->ai_addr->sa_family; 1.2110 +#ifdef _PR_INET6 1.2111 + if (AF_INET6 == result->raw.family) 1.2112 + result->raw.family = PR_AF_INET6; 1.2113 +#endif 1.2114 + if (ai->ai_addrlen < sizeof(PRNetAddr)) 1.2115 + memset(((char*)result)+ai->ai_addrlen, 0, sizeof(PRNetAddr) - ai->ai_addrlen); 1.2116 + 1.2117 + if (result->raw.family == PR_AF_INET) 1.2118 + result->inet.port = htons(port); 1.2119 + else 1.2120 + result->ipv6.port = htons(port); 1.2121 + } 1.2122 + 1.2123 + return ai; 1.2124 +#else 1.2125 + /* using PRAddrInfoFB */ 1.2126 + PRIntn iter = (PRIntn) iterPtr; 1.2127 + iter = PR_EnumerateHostEnt(iter, &((PRAddrInfoFB *) base)->hostent, port, result); 1.2128 + if (iter < 0) 1.2129 + iter = 0; 1.2130 + return (void *) iter; 1.2131 +#endif 1.2132 +} 1.2133 + 1.2134 +PR_IMPLEMENT(const char *) PR_GetCanonNameFromAddrInfo(const PRAddrInfo *ai) 1.2135 +{ 1.2136 +#if defined(_PR_HAVE_GETADDRINFO) 1.2137 +#if defined(_PR_INET6_PROBE) 1.2138 + if (!_pr_ipv6_is_present()) { 1.2139 + const PRAddrInfoFB *fb = (const PRAddrInfoFB *) ai; 1.2140 + return fb->has_cname ? fb->hostent.h_name : NULL; 1.2141 + } 1.2142 +#endif 1.2143 + return ((const PRADDRINFO *) ai)->ai_canonname; 1.2144 +#else 1.2145 + const PRAddrInfoFB *fb = (const PRAddrInfoFB *) ai; 1.2146 + return fb->has_cname ? fb->hostent.h_name : NULL; 1.2147 +#endif 1.2148 +} 1.2149 + 1.2150 +#if defined(_PR_HAVE_GETADDRINFO) 1.2151 +static PRStatus pr_StringToNetAddrGAI(const char *string, PRNetAddr *addr) 1.2152 +{ 1.2153 + PRADDRINFO *res, hints; 1.2154 + int rv; /* 0 for success, or the error code EAI_xxx */ 1.2155 + PRNetAddr laddr; 1.2156 + PRStatus status = PR_SUCCESS; 1.2157 + 1.2158 + memset(&hints, 0, sizeof(hints)); 1.2159 + hints.ai_flags = AI_NUMERICHOST; 1.2160 + hints.ai_family = AF_UNSPEC; 1.2161 + hints.ai_socktype = SOCK_STREAM; 1.2162 + 1.2163 + rv = GETADDRINFO(string, NULL, &hints, &res); 1.2164 + if (rv != 0) 1.2165 + { 1.2166 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, rv); 1.2167 + return PR_FAILURE; 1.2168 + } 1.2169 + 1.2170 + /* pick up the first addr */ 1.2171 + memcpy(&laddr, res->ai_addr, res->ai_addrlen); 1.2172 + if (AF_INET6 == res->ai_addr->sa_family) 1.2173 + { 1.2174 + addr->ipv6.family = PR_AF_INET6; 1.2175 + addr->ipv6.ip = laddr.ipv6.ip; 1.2176 + addr->ipv6.scope_id = laddr.ipv6.scope_id; 1.2177 + } 1.2178 + else if (AF_INET == res->ai_addr->sa_family) 1.2179 + { 1.2180 + addr->inet.family = PR_AF_INET; 1.2181 + addr->inet.ip = laddr.inet.ip; 1.2182 + } 1.2183 + else 1.2184 + { 1.2185 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.2186 + status = PR_FAILURE; 1.2187 + } 1.2188 + 1.2189 + FREEADDRINFO(res); 1.2190 + return status; 1.2191 +} 1.2192 +#endif /* _PR_HAVE_GETADDRINFO */ 1.2193 + 1.2194 +static PRStatus pr_StringToNetAddrFB(const char *string, PRNetAddr *addr) 1.2195 +{ 1.2196 + PRIntn rv; 1.2197 + 1.2198 + rv = pr_inet_aton(string, &addr->inet.ip); 1.2199 + if (1 == rv) 1.2200 + { 1.2201 + addr->raw.family = AF_INET; 1.2202 + return PR_SUCCESS; 1.2203 + } 1.2204 + 1.2205 + PR_ASSERT(0 == rv); 1.2206 + /* clean up after the failed call */ 1.2207 + memset(&addr->inet.ip, 0, sizeof(addr->inet.ip)); 1.2208 + 1.2209 + rv = StringToV6Addr(string, &addr->ipv6.ip); 1.2210 + if (1 == rv) 1.2211 + { 1.2212 + addr->raw.family = PR_AF_INET6; 1.2213 + return PR_SUCCESS; 1.2214 + } 1.2215 + 1.2216 + PR_ASSERT(0 == rv); 1.2217 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.2218 + return PR_FAILURE; 1.2219 +} 1.2220 + 1.2221 +PR_IMPLEMENT(PRStatus) PR_StringToNetAddr(const char *string, PRNetAddr *addr) 1.2222 +{ 1.2223 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.2224 + 1.2225 + if (!addr || !string || !*string) 1.2226 + { 1.2227 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.2228 + return PR_FAILURE; 1.2229 + } 1.2230 + 1.2231 +#if !defined(_PR_HAVE_GETADDRINFO) 1.2232 + return pr_StringToNetAddrFB(string, addr); 1.2233 +#else 1.2234 + /* 1.2235 + * getaddrinfo with AI_NUMERICHOST is much slower than pr_inet_aton on some 1.2236 + * platforms, such as Mac OS X (bug 404399), Linux glibc 2.10 (bug 344809), 1.2237 + * and most likely others. So we only use it to convert literal IP addresses 1.2238 + * that contain IPv6 scope IDs, which pr_inet_aton cannot convert. 1.2239 + */ 1.2240 + if (!strchr(string, '%')) 1.2241 + return pr_StringToNetAddrFB(string, addr); 1.2242 + 1.2243 +#if defined(_PR_INET6_PROBE) 1.2244 + if (!_pr_ipv6_is_present()) 1.2245 + return pr_StringToNetAddrFB(string, addr); 1.2246 +#endif 1.2247 + 1.2248 + return pr_StringToNetAddrGAI(string, addr); 1.2249 +#endif 1.2250 +} 1.2251 + 1.2252 +#if defined(_PR_HAVE_GETADDRINFO) 1.2253 +static PRStatus pr_NetAddrToStringGNI( 1.2254 + const PRNetAddr *addr, char *string, PRUint32 size) 1.2255 +{ 1.2256 + int addrlen; 1.2257 + const PRNetAddr *addrp = addr; 1.2258 +#if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6) 1.2259 + PRUint16 md_af = addr->raw.family; 1.2260 + PRNetAddr addrcopy; 1.2261 +#endif 1.2262 + int rv; /* 0 for success, or the error code EAI_xxx */ 1.2263 + 1.2264 +#ifdef _PR_INET6 1.2265 + if (addr->raw.family == PR_AF_INET6) 1.2266 + { 1.2267 + md_af = AF_INET6; 1.2268 +#ifndef _PR_HAVE_SOCKADDR_LEN 1.2269 + addrcopy = *addr; 1.2270 + addrcopy.raw.family = md_af; 1.2271 + addrp = &addrcopy; 1.2272 +#endif 1.2273 + } 1.2274 +#endif 1.2275 + 1.2276 + addrlen = PR_NETADDR_SIZE(addr); 1.2277 +#ifdef _PR_HAVE_SOCKADDR_LEN 1.2278 + addrcopy = *addr; 1.2279 + ((struct sockaddr*)&addrcopy)->sa_len = addrlen; 1.2280 + ((struct sockaddr*)&addrcopy)->sa_family = md_af; 1.2281 + addrp = &addrcopy; 1.2282 +#endif 1.2283 + rv = GETNAMEINFO((const struct sockaddr *)addrp, addrlen, 1.2284 + string, size, NULL, 0, NI_NUMERICHOST); 1.2285 + if (rv != 0) 1.2286 + { 1.2287 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, rv); 1.2288 + return PR_FAILURE; 1.2289 + } 1.2290 + return PR_SUCCESS; 1.2291 +} 1.2292 +#endif /* _PR_HAVE_GETADDRINFO */ 1.2293 + 1.2294 +#if !defined(_PR_HAVE_GETADDRINFO) || defined(_PR_INET6_PROBE) 1.2295 +static PRStatus pr_NetAddrToStringFB( 1.2296 + const PRNetAddr *addr, char *string, PRUint32 size) 1.2297 +{ 1.2298 + if (PR_AF_INET6 == addr->raw.family) 1.2299 + { 1.2300 +#if defined(_PR_HAVE_INET_NTOP) 1.2301 + if (NULL == inet_ntop(AF_INET6, &addr->ipv6.ip, string, size)) 1.2302 +#else 1.2303 + if (NULL == V6AddrToString(&addr->ipv6.ip, string, size)) 1.2304 +#endif 1.2305 + { 1.2306 + /* the size of the result buffer is inadequate */ 1.2307 + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0); 1.2308 + return PR_FAILURE; 1.2309 + } 1.2310 + } 1.2311 + else 1.2312 + { 1.2313 + if (size < 16) goto failed; 1.2314 + if (AF_INET != addr->raw.family) goto failed; 1.2315 + else 1.2316 + { 1.2317 + unsigned char *byte = (unsigned char*)&addr->inet.ip; 1.2318 + PR_snprintf(string, size, "%u.%u.%u.%u", 1.2319 + byte[0], byte[1], byte[2], byte[3]); 1.2320 + } 1.2321 + } 1.2322 + 1.2323 + return PR_SUCCESS; 1.2324 + 1.2325 +failed: 1.2326 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.2327 + return PR_FAILURE; 1.2328 + 1.2329 +} /* pr_NetAddrToStringFB */ 1.2330 +#endif /* !_PR_HAVE_GETADDRINFO || _PR_INET6_PROBE */ 1.2331 + 1.2332 +PR_IMPLEMENT(PRStatus) PR_NetAddrToString( 1.2333 + const PRNetAddr *addr, char *string, PRUint32 size) 1.2334 +{ 1.2335 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.2336 + 1.2337 +#if !defined(_PR_HAVE_GETADDRINFO) 1.2338 + return pr_NetAddrToStringFB(addr, string, size); 1.2339 +#else 1.2340 +#if defined(_PR_INET6_PROBE) 1.2341 + if (!_pr_ipv6_is_present()) 1.2342 + return pr_NetAddrToStringFB(addr, string, size); 1.2343 +#endif 1.2344 + return pr_NetAddrToStringGNI(addr, string, size); 1.2345 +#endif 1.2346 +} /* PR_NetAddrToString */