nsprpub/pr/src/misc/prnetdb.c

changeset 0
6474c204b198
     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 */

mercurial