nsprpub/pr/src/misc/prnetdb.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "primpl.h"
     8 #include <string.h>
    10 /*
    11  * On Unix, the error code for gethostbyname() and gethostbyaddr()
    12  * is returned in the global variable h_errno, instead of the usual
    13  * errno.
    14  */
    15 #if defined(XP_UNIX)
    16 #if defined(_PR_NEED_H_ERRNO)
    17 extern int h_errno;
    18 #endif
    19 #define _MD_GETHOST_ERRNO() h_errno
    20 #else
    21 #define _MD_GETHOST_ERRNO() _MD_ERRNO()
    22 #endif
    24 /*
    25  * The meaning of the macros related to gethostbyname, gethostbyaddr,
    26  * and gethostbyname2 is defined below.
    27  * - _PR_HAVE_THREADSAFE_GETHOST: the gethostbyXXX functions return
    28  *   the result in thread specific storage.  For example, AIX, HP-UX,
    29  *   and OSF1.
    30  * -  _PR_HAVE_GETHOST_R: have the gethostbyXXX_r functions. See next
    31  *   two macros.
    32  * - _PR_HAVE_GETHOST_R_INT: the gethostbyXXX_r functions return an
    33  *   int.  For example, Linux glibc.
    34  * - _PR_HAVE_GETHOST_R_POINTER: the gethostbyXXX_r functions return
    35  *   a struct hostent* pointer.  For example, Solaris and IRIX.
    36  */
    37 #if defined(_PR_NO_PREEMPT) || defined(_PR_HAVE_GETHOST_R) \
    38     || defined(_PR_HAVE_THREADSAFE_GETHOST)
    39 #define _PR_NO_DNS_LOCK
    40 #endif
    42 #if defined(_PR_NO_DNS_LOCK)
    43 #define LOCK_DNS()
    44 #define UNLOCK_DNS()
    45 #else
    46 PRLock *_pr_dnsLock = NULL;
    47 #define LOCK_DNS() PR_Lock(_pr_dnsLock)
    48 #define UNLOCK_DNS() PR_Unlock(_pr_dnsLock)
    49 #endif  /* defined(_PR_NO_DNS_LOCK) */
    51 /*
    52  * Some platforms have the reentrant getprotobyname_r() and
    53  * getprotobynumber_r().  However, they come in three flavors.
    54  * Some return a pointer to struct protoent, others return
    55  * an int, and glibc's flavor takes five arguments.
    56  */
    57 #if defined(XP_BEOS) && defined(BONE_VERSION)
    58 #include <arpa/inet.h>  /* pick up define for inet_addr */
    59 #include <sys/socket.h>
    60 #define _PR_HAVE_GETPROTO_R
    61 #define _PR_HAVE_GETPROTO_R_POINTER
    62 #endif
    64 #if defined(SOLARIS) || (defined(BSDI) && defined(_REENTRANT)) \
    65 	|| (defined(LINUX) && defined(_REENTRANT) \
    66         && !(defined(__GLIBC__) && __GLIBC__ >= 2) \
    67         && !defined(ANDROID))
    68 #define _PR_HAVE_GETPROTO_R
    69 #define _PR_HAVE_GETPROTO_R_POINTER
    70 #endif
    72 #if defined(OSF1) \
    73         || defined(AIX4_3_PLUS) || (defined(AIX) && defined(_THREAD_SAFE)) \
    74 	|| (defined(HPUX10_10) && defined(_REENTRANT)) \
    75         || (defined(HPUX10_20) && defined(_REENTRANT)) \
    76         || defined(OPENBSD)
    77 #define _PR_HAVE_GETPROTO_R
    78 #define _PR_HAVE_GETPROTO_R_INT
    79 #endif
    81 #if __FreeBSD_version >= 602000
    82 #define _PR_HAVE_GETPROTO_R
    83 #define _PR_HAVE_5_ARG_GETPROTO_R
    84 #endif
    86 /* BeOS has glibc but not the glibc-style getprotobyxxx_r functions. */
    87 #if (defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(XP_BEOS))
    88 #define _PR_HAVE_GETPROTO_R
    89 #define _PR_HAVE_5_ARG_GETPROTO_R
    90 #endif
    92 #if !defined(_PR_HAVE_GETPROTO_R)
    93 PRLock* _getproto_lock = NULL;
    94 #endif
    96 #if defined(_PR_INET6_PROBE)
    97 extern PRBool _pr_ipv6_is_present(void);
    98 #endif
   100 #define _PR_IN6_IS_ADDR_UNSPECIFIED(a)				\
   101 				(((a)->pr_s6_addr32[0] == 0) &&	\
   102 				((a)->pr_s6_addr32[1] == 0) &&		\
   103 				((a)->pr_s6_addr32[2] == 0) &&		\
   104 				((a)->pr_s6_addr32[3] == 0))
   106 #define _PR_IN6_IS_ADDR_LOOPBACK(a)					\
   107                (((a)->pr_s6_addr32[0] == 0)	&&	\
   108                ((a)->pr_s6_addr32[1] == 0)		&&	\
   109                ((a)->pr_s6_addr32[2] == 0)		&&	\
   110                ((a)->pr_s6_addr[12] == 0)		&&	\
   111                ((a)->pr_s6_addr[13] == 0)		&&	\
   112                ((a)->pr_s6_addr[14] == 0)		&&	\
   113                ((a)->pr_s6_addr[15] == 0x1U))
   115 const PRIPv6Addr _pr_in6addr_any =	{{{ 0, 0, 0, 0,
   116 										0, 0, 0, 0,
   117 										0, 0, 0, 0,
   118 										0, 0, 0, 0 }}};
   120 const PRIPv6Addr _pr_in6addr_loopback = {{{ 0, 0, 0, 0,
   121 											0, 0, 0, 0,
   122 											0, 0, 0, 0,
   123 											0, 0, 0, 0x1U }}};
   124 /*
   125  * The values at bytes 10 and 11 are compared using pointers to
   126  * 8-bit fields, and not 32-bit fields, to make the comparison work on
   127  * both big-endian and little-endian systems
   128  */
   130 #define _PR_IN6_IS_ADDR_V4MAPPED(a)			\
   131 		(((a)->pr_s6_addr32[0] == 0) 	&&	\
   132 		((a)->pr_s6_addr32[1] == 0)	&&	\
   133 		((a)->pr_s6_addr[8] == 0)		&&	\
   134 		((a)->pr_s6_addr[9] == 0)		&&	\
   135 		((a)->pr_s6_addr[10] == 0xff)	&&	\
   136 		((a)->pr_s6_addr[11] == 0xff))
   138 #define _PR_IN6_IS_ADDR_V4COMPAT(a)			\
   139 		(((a)->pr_s6_addr32[0] == 0) &&	\
   140 		((a)->pr_s6_addr32[1] == 0) &&		\
   141 		((a)->pr_s6_addr32[2] == 0))
   143 #define _PR_IN6_V4MAPPED_TO_IPADDR(a) ((a)->pr_s6_addr32[3])
   145 #if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
   147 /*
   148  * The _pr_QueryNetIfs() function finds out if the system has
   149  * IPv4 or IPv6 source addresses configured and sets _pr_have_inet_if
   150  * and _pr_have_inet6_if accordingly.
   151  *
   152  * We have an implementation using SIOCGIFCONF ioctl and a
   153  * default implementation that simply sets _pr_have_inet_if
   154  * and _pr_have_inet6_if to true.  A better implementation
   155  * would be to use the routing sockets (see Chapter 17 of
   156  * W. Richard Stevens' Unix Network Programming, Vol. 1, 2nd. Ed.)
   157  */
   159 static PRLock *_pr_query_ifs_lock = NULL;
   160 static PRBool _pr_have_inet_if = PR_FALSE;
   161 static PRBool _pr_have_inet6_if = PR_FALSE;
   163 #undef DEBUG_QUERY_IFS
   165 #if defined(AIX) \
   166     || (defined(DARWIN) && (!defined(HAVE_GETIFADDRS) \
   167         || (defined(XP_MACOSX) && (!defined(MAC_OS_X_VERSION_10_2) || \
   168         MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_2))))
   170 /*
   171  * Use SIOCGIFCONF ioctl on platforms that don't have routing
   172  * sockets.  Warning: whether SIOCGIFCONF ioctl returns AF_INET6
   173  * network interfaces is not portable.
   174  *
   175  * The _pr_QueryNetIfs() function is derived from the code in
   176  * src/lib/libc/net/getifaddrs.c in BSD Unix and the code in
   177  * Section 16.6 of W. Richard Stevens' Unix Network Programming,
   178  * Vol. 1, 2nd. Ed.
   179  */
   181 #include <sys/ioctl.h>
   182 #include <sys/socket.h>
   183 #include <netinet/in.h>
   184 #include <net/if.h>
   186 #ifdef DEBUG_QUERY_IFS
   187 static void
   188 _pr_PrintIfreq(struct ifreq *ifr)
   189 {
   190     PRNetAddr addr;
   191     struct sockaddr *sa;
   192     const char* family;
   193     char addrstr[64];
   195     sa = &ifr->ifr_addr;
   196     if (sa->sa_family == AF_INET) {
   197         struct sockaddr_in *sin = (struct sockaddr_in *)sa;
   198         family = "inet";
   199         memcpy(&addr.inet.ip, &sin->sin_addr, sizeof(sin->sin_addr));
   200     } else if (sa->sa_family == AF_INET6) {
   201         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
   202         family = "inet6";
   203         memcpy(&addr.ipv6.ip, &sin6->sin6_addr, sizeof(sin6->sin6_addr));
   204     } else {
   205         return;  /* skip if not AF_INET or AF_INET6 */
   206     }
   207     addr.raw.family = sa->sa_family;
   208     PR_NetAddrToString(&addr, addrstr, sizeof(addrstr));
   209     printf("%s: %s %s\n", ifr->ifr_name, family, addrstr);
   210 }
   211 #endif
   213 static void
   214 _pr_QueryNetIfs(void)
   215 {
   216     int sock;
   217     int rv;
   218     struct ifconf ifc;
   219     struct ifreq *ifr;
   220     struct ifreq *lifr;
   221     PRUint32 len, lastlen;
   222     char *buf;
   224     if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
   225         return;
   226     }
   228     /* Issue SIOCGIFCONF request in a loop. */
   229     lastlen = 0;
   230     len = 100 * sizeof(struct ifreq);  /* initial buffer size guess */
   231     for (;;) {
   232         buf = (char *)PR_Malloc(len);
   233         if (NULL == buf) {
   234             close(sock);
   235             return;
   236         }
   237         ifc.ifc_buf = buf;
   238         ifc.ifc_len = len;
   239         rv = ioctl(sock, SIOCGIFCONF, &ifc);
   240         if (rv < 0) {
   241             if (errno != EINVAL || lastlen != 0) {
   242                 close(sock);
   243                 PR_Free(buf);
   244                 return;
   245             }
   246         } else {
   247             if (ifc.ifc_len == lastlen)
   248                 break;  /* success, len has not changed */
   249             lastlen = ifc.ifc_len;
   250         }
   251         len += 10 * sizeof(struct ifreq);  /* increment */
   252         PR_Free(buf);
   253     }
   254     close(sock);
   256     ifr = ifc.ifc_req;
   257     lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
   259     while (ifr < lifr) {
   260         struct sockaddr *sa;
   261         int sa_len;
   263 #ifdef DEBUG_QUERY_IFS
   264         _pr_PrintIfreq(ifr);
   265 #endif
   266         sa = &ifr->ifr_addr;
   267         if (sa->sa_family == AF_INET) {
   268             struct sockaddr_in *sin = (struct sockaddr_in *) sa;
   269             if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) {
   270                 _pr_have_inet_if = PR_TRUE;
   271             } 
   272         } else if (sa->sa_family == AF_INET6) {
   273             struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
   274             if (!IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)
   275                     && !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
   276                 _pr_have_inet6_if = PR_TRUE;
   277             } 
   278         }
   280 #ifdef _PR_HAVE_SOCKADDR_LEN
   281         sa_len = PR_MAX(sa->sa_len, sizeof(struct sockaddr));
   282 #else
   283         switch (sa->sa_family) {
   284 #ifdef AF_LINK
   285         case AF_LINK:
   286             sa_len = sizeof(struct sockaddr_dl);
   287             break;
   288 #endif
   289         case AF_INET6:
   290             sa_len = sizeof(struct sockaddr_in6);
   291             break;
   292         default:
   293             sa_len = sizeof(struct sockaddr);
   294             break;
   295         }
   296 #endif
   297         ifr = (struct ifreq *)(((char *)sa) + sa_len);
   298     }
   299     PR_Free(buf);
   300 }
   302 #elif (defined(DARWIN) && defined(HAVE_GETIFADDRS)) || defined(FREEBSD) \
   303     || defined(NETBSD) || defined(OPENBSD)
   305 /*
   306  * Use the BSD getifaddrs function.
   307  */
   309 #include <sys/types.h>
   310 #include <sys/socket.h>
   311 #include <ifaddrs.h>
   312 #include <netinet/in.h>
   314 #ifdef DEBUG_QUERY_IFS
   315 static void
   316 _pr_PrintIfaddrs(struct ifaddrs *ifa)
   317 {
   318     struct sockaddr *sa;
   319     const char* family;
   320     void *addrp;
   321     char addrstr[64];
   323     sa = ifa->ifa_addr;
   324     if (sa->sa_family == AF_INET) {
   325         struct sockaddr_in *sin = (struct sockaddr_in *)sa;
   326         family = "inet";
   327         addrp = &sin->sin_addr;
   328     } else if (sa->sa_family == AF_INET6) {
   329         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
   330         family = "inet6";
   331         addrp = &sin6->sin6_addr;
   332     } else {
   333         return;  /* skip if not AF_INET or AF_INET6 */
   334     }
   335     inet_ntop(sa->sa_family, addrp, addrstr, sizeof(addrstr));
   336     printf("%s: %s %s\n", ifa->ifa_name, family, addrstr);
   337 }
   338 #endif
   340 static void
   341 _pr_QueryNetIfs(void)
   342 {
   343     struct ifaddrs *ifp;
   344     struct ifaddrs *ifa;
   346     if (getifaddrs(&ifp) == -1) {
   347         return;
   348     }
   349     for (ifa = ifp; ifa; ifa = ifa->ifa_next) {
   350         struct sockaddr *sa;
   352 #ifdef DEBUG_QUERY_IFS
   353         _pr_PrintIfaddrs(ifa);
   354 #endif
   355         sa = ifa->ifa_addr;
   356         if (sa->sa_family == AF_INET) {
   357             struct sockaddr_in *sin = (struct sockaddr_in *) sa;
   358             if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) {
   359                 _pr_have_inet_if = 1;
   360             } 
   361         } else if (sa->sa_family == AF_INET6) {
   362             struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
   363             if (!IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)
   364                     && !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
   365                 _pr_have_inet6_if = 1;
   366             } 
   367         }
   368     } 
   369     freeifaddrs(ifp);
   370 }
   372 #else  /* default */
   374 /*
   375  * Emulate the code in NSPR 4.2 or older.  PR_GetIPNodeByName behaves
   376  * as if the system had both IPv4 and IPv6 source addresses configured.
   377  */
   378 static void
   379 _pr_QueryNetIfs(void)
   380 {
   381     _pr_have_inet_if = PR_TRUE;
   382     _pr_have_inet6_if = PR_TRUE;
   383 }
   385 #endif
   387 #endif  /* _PR_INET6 && _PR_HAVE_GETHOSTBYNAME2 */
   389 void _PR_InitNet(void)
   390 {
   391 #if defined(XP_UNIX)
   392 #ifdef HAVE_NETCONFIG
   393 	/*
   394 	 * This one-liner prevents the endless re-open's and re-read's of
   395 	 * /etc/netconfig on EACH and EVERY call to accept(), connect(), etc.
   396 	 */
   397 	 (void)setnetconfig();
   398 #endif
   399 #endif
   400 #if !defined(_PR_NO_DNS_LOCK)
   401 	_pr_dnsLock = PR_NewLock();
   402 #endif
   403 #if !defined(_PR_HAVE_GETPROTO_R)
   404 	_getproto_lock = PR_NewLock();
   405 #endif
   406 #if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
   407 	_pr_query_ifs_lock = PR_NewLock();
   408 #endif
   409 }
   411 void _PR_CleanupNet(void)
   412 {
   413 #if !defined(_PR_NO_DNS_LOCK)
   414     if (_pr_dnsLock) {
   415         PR_DestroyLock(_pr_dnsLock);
   416         _pr_dnsLock = NULL;
   417     }
   418 #endif
   419 #if !defined(_PR_HAVE_GETPROTO_R)
   420     if (_getproto_lock) {
   421         PR_DestroyLock(_getproto_lock);
   422         _getproto_lock = NULL;
   423     }
   424 #endif
   425 #if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
   426     if (_pr_query_ifs_lock) {
   427         PR_DestroyLock(_pr_query_ifs_lock);
   428         _pr_query_ifs_lock = NULL;
   429     }
   430 #endif
   431 }
   433 /*
   434 ** Allocate space from the buffer, aligning it to "align" before doing
   435 ** the allocation. "align" must be a power of 2.
   436 */
   437 static char *Alloc(PRIntn amount, char **bufp, PRIntn *buflenp, PRIntn align)
   438 {
   439 	char *buf = *bufp;
   440 	PRIntn buflen = *buflenp;
   442 	if (align && ((long)buf & (align - 1))) {
   443 		PRIntn skip = align - ((ptrdiff_t)buf & (align - 1));
   444 		if (buflen < skip) {
   445 			return 0;
   446 		}
   447 		buf += skip;
   448 		buflen -= skip;
   449 	}
   450 	if (buflen < amount) {
   451 		return 0;
   452 	}
   453 	*bufp = buf + amount;
   454 	*buflenp = buflen - amount;
   455 	return buf;
   456 }
   458 typedef enum _PRIPAddrConversion {
   459     _PRIPAddrNoConversion,
   460     _PRIPAddrIPv4Mapped,
   461     _PRIPAddrIPv4Compat
   462 } _PRIPAddrConversion;
   464 /*
   465 ** Convert an IPv4 address (v4) to an IPv4-mapped IPv6 address (v6).
   466 */
   467 static void MakeIPv4MappedAddr(const char *v4, char *v6)
   468 {
   469     memset(v6, 0, 10);
   470     memset(v6 + 10, 0xff, 2);
   471     memcpy(v6 + 12, v4, 4);
   472 }
   474 /*
   475 ** Convert an IPv4 address (v4) to an IPv4-compatible IPv6 address (v6).
   476 */
   477 static void MakeIPv4CompatAddr(const char *v4, char *v6)
   478 {
   479     memset(v6, 0, 12);
   480     memcpy(v6 + 12, v4, 4);
   481 }
   483 /*
   484 ** Copy a hostent, and all of the memory that it refers to into
   485 ** (hopefully) stacked buffers.
   486 */
   487 static PRStatus CopyHostent(
   488     struct hostent *from,
   489     char **buf,
   490     PRIntn *bufsize,
   491     _PRIPAddrConversion conversion,
   492     PRHostEnt *to)
   493 {
   494 	PRIntn len, na;
   495 	char **ap;
   497 	if (conversion != _PRIPAddrNoConversion
   498 			&& from->h_addrtype == AF_INET) {
   499 		PR_ASSERT(from->h_length == 4);
   500 		to->h_addrtype = PR_AF_INET6;
   501 		to->h_length = 16;
   502 	} else {
   503 #if defined(_PR_INET6) || defined(_PR_INET6_PROBE)
   504 		if (AF_INET6 == from->h_addrtype)
   505 			to->h_addrtype = PR_AF_INET6;
   506 		else
   507 #endif
   508 			to->h_addrtype = from->h_addrtype;
   509 		to->h_length = from->h_length;
   510 	}
   512 	/* Copy the official name */
   513 	if (!from->h_name) return PR_FAILURE;
   514 	len = strlen(from->h_name) + 1;
   515 	to->h_name = Alloc(len, buf, bufsize, 0);
   516 	if (!to->h_name) return PR_FAILURE;
   517 	memcpy(to->h_name, from->h_name, len);
   519 	/* Count the aliases, then allocate storage for the pointers */
   520 	if (!from->h_aliases) {
   521 		na = 1;
   522 	} else {
   523 		for (na = 1, ap = from->h_aliases; *ap != 0; na++, ap++){;} /* nothing to execute */
   524 	}
   525 	to->h_aliases = (char**)Alloc(
   526 	    na * sizeof(char*), buf, bufsize, sizeof(char**));
   527 	if (!to->h_aliases) return PR_FAILURE;
   529 	/* Copy the aliases, one at a time */
   530 	if (!from->h_aliases) {
   531 		to->h_aliases[0] = 0;
   532 	} else {
   533 		for (na = 0, ap = from->h_aliases; *ap != 0; na++, ap++) {
   534 			len = strlen(*ap) + 1;
   535 			to->h_aliases[na] = Alloc(len, buf, bufsize, 0);
   536 			if (!to->h_aliases[na]) return PR_FAILURE;
   537 			memcpy(to->h_aliases[na], *ap, len);
   538 		}
   539 		to->h_aliases[na] = 0;
   540 	}
   542 	/* Count the addresses, then allocate storage for the pointers */
   543 	for (na = 1, ap = from->h_addr_list; *ap != 0; na++, ap++){;} /* nothing to execute */
   544 	to->h_addr_list = (char**)Alloc(
   545 	    na * sizeof(char*), buf, bufsize, sizeof(char**));
   546 	if (!to->h_addr_list) return PR_FAILURE;
   548 	/* Copy the addresses, one at a time */
   549 	for (na = 0, ap = from->h_addr_list; *ap != 0; na++, ap++) {
   550 		to->h_addr_list[na] = Alloc(to->h_length, buf, bufsize, 0);
   551 		if (!to->h_addr_list[na]) return PR_FAILURE;
   552 		if (conversion != _PRIPAddrNoConversion
   553 				&& from->h_addrtype == AF_INET) {
   554 			if (conversion == _PRIPAddrIPv4Mapped) {
   555 				MakeIPv4MappedAddr(*ap, to->h_addr_list[na]);
   556 			} else {
   557 				PR_ASSERT(conversion == _PRIPAddrIPv4Compat);
   558 				MakeIPv4CompatAddr(*ap, to->h_addr_list[na]);
   559 			}
   560 		} else {
   561 			memcpy(to->h_addr_list[na], *ap, to->h_length);
   562 		}
   563 	}
   564 	to->h_addr_list[na] = 0;
   565 	return PR_SUCCESS;
   566 }
   568 #ifdef SYMBIAN
   569 /* Set p_aliases by hand because Symbian's getprotobyname() returns NULL. */
   570 static void AssignAliases(struct protoent *Protoent, char** aliases)
   571 {
   572     if (NULL == Protoent->p_aliases) {
   573         if (0 == strcmp(Protoent->p_name, "ip"))
   574             aliases[0] = "IP";
   575         else if (0 == strcmp(Protoent->p_name, "tcp"))
   576             aliases[0] = "TCP";
   577         else if (0 == strcmp(Protoent->p_name, "udp"))
   578             aliases[0] = "UDP";
   579         else
   580             aliases[0] = "UNKNOWN";
   581         aliases[1] = NULL;
   582         Protoent->p_aliases = aliases;
   583     }
   584 }
   585 #endif
   587 #if !defined(_PR_HAVE_GETPROTO_R)
   588 /*
   589 ** Copy a protoent, and all of the memory that it refers to into
   590 ** (hopefully) stacked buffers.
   591 */
   592 static PRStatus CopyProtoent(
   593     struct protoent *from, char *buf, PRIntn bufsize, PRProtoEnt *to)
   594 {
   595 	PRIntn len, na;
   596 	char **ap;
   598 	/* Do the easy stuff */
   599 	to->p_num = from->p_proto;
   601 	/* Copy the official name */
   602 	if (!from->p_name) return PR_FAILURE;
   603 	len = strlen(from->p_name) + 1;
   604 	to->p_name = Alloc(len, &buf, &bufsize, 0);
   605 	if (!to->p_name) return PR_FAILURE;
   606 	memcpy(to->p_name, from->p_name, len);
   608 	/* Count the aliases, then allocate storage for the pointers */
   609 	for (na = 1, ap = from->p_aliases; *ap != 0; na++, ap++){;} /* nothing to execute */
   610 	to->p_aliases = (char**)Alloc(
   611 	    na * sizeof(char*), &buf, &bufsize, sizeof(char**));
   612 	if (!to->p_aliases) return PR_FAILURE;
   614 	/* Copy the aliases, one at a time */
   615 	for (na = 0, ap = from->p_aliases; *ap != 0; na++, ap++) {
   616 		len = strlen(*ap) + 1;
   617 		to->p_aliases[na] = Alloc(len, &buf, &bufsize, 0);
   618 		if (!to->p_aliases[na]) return PR_FAILURE;
   619 		memcpy(to->p_aliases[na], *ap, len);
   620 	}
   621 	to->p_aliases[na] = 0;
   623 	return PR_SUCCESS;
   624 }
   625 #endif /* !defined(_PR_HAVE_GETPROTO_R) */
   627 /*
   628  * #################################################################
   629  * NOTE: tmphe, tmpbuf, bufsize, h, and h_err are local variables
   630  * or arguments of PR_GetHostByName, PR_GetIPNodeByName, and
   631  * PR_GetHostByAddr.  DO NOT CHANGE THE NAMES OF THESE LOCAL 
   632  * VARIABLES OR ARGUMENTS.
   633  * #################################################################
   634  */
   635 #if defined(_PR_HAVE_GETHOST_R_INT)
   637 #define GETHOSTBYNAME(name) \
   638     (gethostbyname_r(name, &tmphe, tmpbuf, bufsize, &h, &h_err), h)
   639 #define GETHOSTBYNAME2(name, af) \
   640     (gethostbyname2_r(name, af, &tmphe, tmpbuf, bufsize, &h, &h_err), h)
   641 #define GETHOSTBYADDR(addr, addrlen, af) \
   642     (gethostbyaddr_r(addr, addrlen, af, \
   643     &tmphe, tmpbuf, bufsize, &h, &h_err), h)
   645 #elif defined(_PR_HAVE_GETHOST_R_POINTER)
   647 #define GETHOSTBYNAME(name) \
   648     gethostbyname_r(name, &tmphe, tmpbuf, bufsize, &h_err)
   649 #define GETHOSTBYNAME2(name, af) \
   650     gethostbyname2_r(name, af, &tmphe, tmpbuf, bufsize, &h_err)
   651 #define GETHOSTBYADDR(addr, addrlen, af) \
   652     gethostbyaddr_r(addr, addrlen, af, &tmphe, tmpbuf, bufsize, &h_err)
   654 #else
   656 #define GETHOSTBYNAME(name) gethostbyname(name)
   657 #define GETHOSTBYNAME2(name, af) gethostbyname2(name, af)
   658 #define GETHOSTBYADDR(addr, addrlen, af) gethostbyaddr(addr, addrlen, af)
   660 #endif  /* definition of GETHOSTBYXXX */
   662 PR_IMPLEMENT(PRStatus) PR_GetHostByName(
   663     const char *name, char *buf, PRIntn bufsize, PRHostEnt *hp)
   664 {
   665 	struct hostent *h;
   666 	PRStatus rv = PR_FAILURE;
   667 #if defined(_PR_HAVE_GETHOST_R)
   668     char localbuf[PR_NETDB_BUF_SIZE];
   669     char *tmpbuf;
   670     struct hostent tmphe;
   671     int h_err;
   672 #endif
   674     if (!_pr_initialized) _PR_ImplicitInitialization();
   676 #if defined(_PR_HAVE_GETHOST_R)
   677     tmpbuf = localbuf;
   678     if (bufsize > sizeof(localbuf))
   679     {
   680         tmpbuf = (char *)PR_Malloc(bufsize);
   681         if (NULL == tmpbuf)
   682         {
   683             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   684             return rv;
   685         }
   686     }
   687 #endif
   689 	LOCK_DNS();
   691 	h = GETHOSTBYNAME(name);
   693 	if (NULL == h)
   694 	{
   695 	    PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
   696 	}
   697 	else
   698 	{
   699 		_PRIPAddrConversion conversion = _PRIPAddrNoConversion;
   700 		rv = CopyHostent(h, &buf, &bufsize, conversion, hp);
   701 		if (PR_SUCCESS != rv)
   702 		    PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
   703 	}
   704 	UNLOCK_DNS();
   705 #if defined(_PR_HAVE_GETHOST_R)
   706     if (tmpbuf != localbuf)
   707         PR_Free(tmpbuf);
   708 #endif
   709 	return rv;
   710 }
   712 #if !defined(_PR_INET6) && \
   713         defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME)
   714 typedef struct hostent  * (*_pr_getipnodebyname_t)(const char *, int,
   715 										int, int *);
   716 typedef struct hostent  * (*_pr_getipnodebyaddr_t)(const void *, size_t,
   717 													int, int *);
   718 typedef void (*_pr_freehostent_t)(struct hostent *);
   719 static void * _pr_getipnodebyname_fp;
   720 static void * _pr_getipnodebyaddr_fp;
   721 static void * _pr_freehostent_fp;
   723 /*
   724  * Look up the addresses of getipnodebyname, getipnodebyaddr,
   725  * and freehostent.
   726  */
   727 PRStatus
   728 _pr_find_getipnodebyname(void)
   729 {
   730     PRLibrary *lib;	
   731     PRStatus rv;
   732 #define GETIPNODEBYNAME "getipnodebyname"
   733 #define GETIPNODEBYADDR "getipnodebyaddr"
   734 #define FREEHOSTENT     "freehostent"
   736     _pr_getipnodebyname_fp = PR_FindSymbolAndLibrary(GETIPNODEBYNAME, &lib);
   737     if (NULL != _pr_getipnodebyname_fp) {
   738         _pr_freehostent_fp = PR_FindSymbol(lib, FREEHOSTENT);
   739         if (NULL != _pr_freehostent_fp) {
   740             _pr_getipnodebyaddr_fp = PR_FindSymbol(lib, GETIPNODEBYADDR);
   741             if (NULL != _pr_getipnodebyaddr_fp)
   742                 rv = PR_SUCCESS;
   743             else
   744                 rv = PR_FAILURE;
   745         } else
   746             rv = PR_FAILURE;
   747         (void)PR_UnloadLibrary(lib);
   748     } else
   749         rv = PR_FAILURE;
   750     return rv;
   751 }
   752 #endif
   754 #if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
   755 /*
   756 ** Append the V4 addresses to the end of the list
   757 */
   758 static PRStatus AppendV4AddrsToHostent(
   759     struct hostent *from,
   760     char **buf,
   761     PRIntn *bufsize,
   762     PRHostEnt *to)
   763 {
   764     PRIntn na, na_old;
   765     char **ap;
   766     char **new_addr_list;
   768     /* Count the addresses, then grow storage for the pointers */
   769     for (na_old = 0, ap = to->h_addr_list; *ap != 0; na_old++, ap++)
   770         {;} /* nothing to execute */
   771     for (na = na_old + 1, ap = from->h_addr_list; *ap != 0; na++, ap++)
   772         {;} /* nothing to execute */
   773     new_addr_list = (char**)Alloc(
   774         na * sizeof(char*), buf, bufsize, sizeof(char**));
   775     if (!new_addr_list) return PR_FAILURE;
   777     /* Copy the V6 addresses, one at a time */
   778     for (na = 0, ap = to->h_addr_list; *ap != 0; na++, ap++) {
   779         new_addr_list[na] = to->h_addr_list[na];
   780     }
   781     to->h_addr_list = new_addr_list;
   783     /* Copy the V4 addresses, one at a time */
   784     for (ap = from->h_addr_list; *ap != 0; na++, ap++) {
   785         to->h_addr_list[na] = Alloc(to->h_length, buf, bufsize, 0);
   786         if (!to->h_addr_list[na]) return PR_FAILURE;
   787         MakeIPv4MappedAddr(*ap, to->h_addr_list[na]);
   788     }
   789     to->h_addr_list[na] = 0;
   790     return PR_SUCCESS;
   791 }
   792 #endif
   794 PR_IMPLEMENT(PRStatus) PR_GetIPNodeByName(
   795     const char *name, PRUint16 af, PRIntn flags,
   796     char *buf, PRIntn bufsize, PRHostEnt *hp)
   797 {
   798 	struct hostent *h = 0;
   799 	PRStatus rv = PR_FAILURE;
   800 #if defined(_PR_HAVE_GETHOST_R)
   801     char localbuf[PR_NETDB_BUF_SIZE];
   802     char *tmpbuf;
   803     struct hostent tmphe;
   804     int h_err;
   805 #endif
   806 #if defined(_PR_HAVE_GETIPNODEBYNAME)
   807 	PRUint16 md_af = af;
   808 	int error_num;
   809 	int tmp_flags = 0;
   810 #endif
   811 #if defined(_PR_HAVE_GETHOSTBYNAME2)
   812     PRBool did_af_inet = PR_FALSE;
   813 #endif
   815     if (!_pr_initialized) _PR_ImplicitInitialization();
   817     if (af != PR_AF_INET && af != PR_AF_INET6) {
   818         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   819         return PR_FAILURE;
   820     }
   822 #if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
   823     PR_Lock(_pr_query_ifs_lock);
   824     /*
   825      * Keep querying the presence of IPv4 and IPv6 interfaces until
   826      * at least one is up.  This allows us to detect the local
   827      * machine going from offline to online.
   828      */
   829     if (!_pr_have_inet_if && !_pr_have_inet6_if) {
   830 	_pr_QueryNetIfs();
   831 #ifdef DEBUG_QUERY_IFS
   832 	if (_pr_have_inet_if)
   833 		printf("Have IPv4 source address\n");
   834 	if (_pr_have_inet6_if)
   835 		printf("Have IPv6 source address\n");
   836 #endif
   837     }
   838     PR_Unlock(_pr_query_ifs_lock);
   839 #endif
   841 #if defined(_PR_HAVE_GETIPNODEBYNAME)
   842 	if (flags & PR_AI_V4MAPPED)
   843 		tmp_flags |= AI_V4MAPPED;
   844 	if (flags & PR_AI_ADDRCONFIG)
   845 		tmp_flags |= AI_ADDRCONFIG;
   846 	if (flags & PR_AI_ALL)
   847 		tmp_flags |= AI_ALL;
   848     if (af == PR_AF_INET6)
   849     	md_af = AF_INET6;
   850 	else
   851     	md_af = af;
   852 #endif
   854 #if defined(_PR_HAVE_GETHOST_R)
   855     tmpbuf = localbuf;
   856     if (bufsize > sizeof(localbuf))
   857     {
   858         tmpbuf = (char *)PR_Malloc(bufsize);
   859         if (NULL == tmpbuf)
   860         {
   861             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   862             return rv;
   863         }
   864     }
   865 #endif
   867     /* Do not need to lock the DNS lock if getipnodebyname() is called */
   868 #ifdef _PR_INET6
   869 #ifdef _PR_HAVE_GETHOSTBYNAME2
   870     LOCK_DNS();
   871     if (af == PR_AF_INET6)
   872     {
   873         if ((flags & PR_AI_ADDRCONFIG) == 0 || _pr_have_inet6_if)
   874         {
   875 #ifdef _PR_INET6_PROBE
   876           if (_pr_ipv6_is_present())
   877 #endif
   878             h = GETHOSTBYNAME2(name, AF_INET6); 
   879         }
   880         if ((NULL == h) && (flags & PR_AI_V4MAPPED)
   881         && ((flags & PR_AI_ADDRCONFIG) == 0 || _pr_have_inet_if))
   882         {
   883             did_af_inet = PR_TRUE;
   884             h = GETHOSTBYNAME2(name, AF_INET);
   885         }
   886     }
   887     else
   888     {
   889         if ((flags & PR_AI_ADDRCONFIG) == 0 || _pr_have_inet_if)
   890         {
   891             did_af_inet = PR_TRUE;
   892             h = GETHOSTBYNAME2(name, af);
   893         }
   894     }
   895 #elif defined(_PR_HAVE_GETIPNODEBYNAME)
   896     h = getipnodebyname(name, md_af, tmp_flags, &error_num);
   897 #else
   898 #error "Unknown name-to-address translation function"
   899 #endif	/* _PR_HAVE_GETHOSTBYNAME2 */
   900 #elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME)
   901     if (_pr_ipv6_is_present())
   902     {
   903 #ifdef PR_GETIPNODE_NOT_THREADSAFE
   904         LOCK_DNS();
   905 #endif
   906     	h = (*((_pr_getipnodebyname_t)_pr_getipnodebyname_fp))(name, md_af, tmp_flags, &error_num);
   907     }
   908     else
   909     {
   910         LOCK_DNS();
   911     	h = GETHOSTBYNAME(name);
   912     }
   913 #else /* _PR_INET6 */
   914     LOCK_DNS();
   915     h = GETHOSTBYNAME(name);
   916 #endif /* _PR_INET6 */
   918 	if (NULL == h)
   919 	{
   920 #if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
   921 	    PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num);
   922 #elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME)
   923     	if (_pr_ipv6_is_present())
   924 	    	PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num);
   925 		else
   926 	    	PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
   927 #else
   928 	    PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
   929 #endif
   930 	}
   931 	else
   932 	{
   933 		_PRIPAddrConversion conversion = _PRIPAddrNoConversion;
   935 		if (af == PR_AF_INET6) conversion = _PRIPAddrIPv4Mapped;
   936 		rv = CopyHostent(h, &buf, &bufsize, conversion, hp);
   937 		if (PR_SUCCESS != rv)
   938 		    PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
   939 #if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
   940 		freehostent(h);
   941 #elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME)
   942     	if (_pr_ipv6_is_present())
   943 			(*((_pr_freehostent_t)_pr_freehostent_fp))(h);
   944 #endif
   945 #if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
   946 		if ((PR_SUCCESS == rv) && (flags & PR_AI_V4MAPPED)
   947 				&& ((flags & PR_AI_ALL)
   948 				|| ((flags & PR_AI_ADDRCONFIG) && _pr_have_inet_if))
   949 				&& !did_af_inet && (h = GETHOSTBYNAME2(name, AF_INET)) != 0) {
   950 			rv = AppendV4AddrsToHostent(h, &buf, &bufsize, hp);
   951 			if (PR_SUCCESS != rv)
   952 				PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
   953 		}
   954 #endif
   955 	}
   957     /* Must match the convoluted logic above for LOCK_DNS() */
   958 #ifdef _PR_INET6
   959 #ifdef _PR_HAVE_GETHOSTBYNAME2
   960     UNLOCK_DNS();
   961 #endif	/* _PR_HAVE_GETHOSTBYNAME2 */
   962 #elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME)
   963 #ifdef PR_GETIPNODE_NOT_THREADSAFE
   964     UNLOCK_DNS();
   965 #else
   966     if (!_pr_ipv6_is_present())
   967         UNLOCK_DNS();
   968 #endif
   969 #else /* _PR_INET6 */
   970     UNLOCK_DNS();
   971 #endif /* _PR_INET6 */
   973 #if defined(_PR_HAVE_GETHOST_R)
   974     if (tmpbuf != localbuf)
   975         PR_Free(tmpbuf);
   976 #endif
   978 	return rv;
   979 }
   981 PR_IMPLEMENT(PRStatus) PR_GetHostByAddr(
   982     const PRNetAddr *hostaddr, char *buf, PRIntn bufsize, PRHostEnt *hostentry)
   983 {
   984 	struct hostent *h;
   985 	PRStatus rv = PR_FAILURE;
   986 	const void *addr;
   987 	PRUint32 tmp_ip;
   988 	int addrlen;
   989 	PRInt32 af;
   990 #if defined(_PR_HAVE_GETHOST_R)
   991     char localbuf[PR_NETDB_BUF_SIZE];
   992     char *tmpbuf;
   993     struct hostent tmphe;
   994     int h_err;
   995 #endif
   996 #if defined(_PR_HAVE_GETIPNODEBYADDR)
   997 	int error_num;
   998 #endif
  1000     if (!_pr_initialized) _PR_ImplicitInitialization();
  1002 	if (hostaddr->raw.family == PR_AF_INET6)
  1004 #if defined(_PR_INET6_PROBE)
  1005 		af = _pr_ipv6_is_present() ? AF_INET6 : AF_INET;
  1006 #elif defined(_PR_INET6)
  1007 		af = AF_INET6;
  1008 #else
  1009 		af = AF_INET;
  1010 #endif
  1011 #if defined(_PR_GHBA_DISALLOW_V4MAPPED)
  1012 		if (_PR_IN6_IS_ADDR_V4MAPPED(&hostaddr->ipv6.ip))
  1013 			af = AF_INET;
  1014 #endif
  1016 	else
  1018 		PR_ASSERT(hostaddr->raw.family == AF_INET);
  1019 		af = AF_INET;
  1021 	if (hostaddr->raw.family == PR_AF_INET6) {
  1022 #if defined(_PR_INET6) || defined(_PR_INET6_PROBE)
  1023 		if (af == AF_INET6) {
  1024 			addr = &hostaddr->ipv6.ip;
  1025 			addrlen = sizeof(hostaddr->ipv6.ip);
  1027 		else
  1028 #endif
  1030 			PR_ASSERT(af == AF_INET);
  1031 			if (!_PR_IN6_IS_ADDR_V4MAPPED(&hostaddr->ipv6.ip)) {
  1032 				PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1033 				return rv;
  1035 			tmp_ip = _PR_IN6_V4MAPPED_TO_IPADDR((PRIPv6Addr *)
  1036 												&hostaddr->ipv6.ip);
  1037 			addr = &tmp_ip;
  1038 			addrlen = sizeof(tmp_ip);
  1040 	} else {
  1041 		PR_ASSERT(hostaddr->raw.family == AF_INET);
  1042 		PR_ASSERT(af == AF_INET);
  1043 		addr = &hostaddr->inet.ip;
  1044 		addrlen = sizeof(hostaddr->inet.ip);
  1047 #if defined(_PR_HAVE_GETHOST_R)
  1048     tmpbuf = localbuf;
  1049     if (bufsize > sizeof(localbuf))
  1051         tmpbuf = (char *)PR_Malloc(bufsize);
  1052         if (NULL == tmpbuf)
  1054             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  1055             return rv;
  1058 #endif
  1060     /* Do not need to lock the DNS lock if getipnodebyaddr() is called */
  1061 #if defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6)
  1062 	h = getipnodebyaddr(addr, addrlen, af, &error_num);
  1063 #elif defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6_PROBE)
  1064     if (_pr_ipv6_is_present())
  1066 #ifdef PR_GETIPNODE_NOT_THREADSAFE
  1067         LOCK_DNS();
  1068 #endif
  1069     	h = (*((_pr_getipnodebyaddr_t)_pr_getipnodebyaddr_fp))(addr, addrlen,
  1070 				af, &error_num);
  1072 	else
  1074         LOCK_DNS();
  1075 		h = GETHOSTBYADDR(addr, addrlen, af);
  1077 #else	/* _PR_HAVE_GETIPNODEBYADDR */
  1078     LOCK_DNS();
  1079 	h = GETHOSTBYADDR(addr, addrlen, af);
  1080 #endif /* _PR_HAVE_GETIPNODEBYADDR */
  1081 	if (NULL == h)
  1083 #if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR)
  1084 		PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num);
  1085 #elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYADDR)
  1086     	if (_pr_ipv6_is_present())
  1087 	    	PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num);
  1088 		else
  1089 	    	PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
  1090 #else
  1091 		PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
  1092 #endif
  1094 	else
  1096 		_PRIPAddrConversion conversion = _PRIPAddrNoConversion;
  1097 		if (hostaddr->raw.family == PR_AF_INET6) {
  1098 			if (af == AF_INET) {
  1099 				if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr*)
  1100 												&hostaddr->ipv6.ip)) {
  1101 					conversion = _PRIPAddrIPv4Mapped;
  1102 				} else if (_PR_IN6_IS_ADDR_V4COMPAT((PRIPv6Addr *)
  1103 													&hostaddr->ipv6.ip)) {
  1104 					conversion = _PRIPAddrIPv4Compat;
  1108 		rv = CopyHostent(h, &buf, &bufsize, conversion, hostentry);
  1109 		if (PR_SUCCESS != rv) {
  1110 		    PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
  1112 #if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR)
  1113 		freehostent(h);
  1114 #elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYADDR)
  1115     	if (_pr_ipv6_is_present())
  1116 			(*((_pr_freehostent_t)_pr_freehostent_fp))(h);
  1117 #endif
  1120     /* Must match the convoluted logic above for LOCK_DNS() */
  1121 #if defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6)
  1122 #elif defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6_PROBE)
  1123 #ifdef PR_GETIPNODE_NOT_THREADSAFE
  1124     UNLOCK_DNS();
  1125 #else
  1126     if (!_pr_ipv6_is_present())
  1127         UNLOCK_DNS();
  1128 #endif
  1129 #else	/* _PR_HAVE_GETIPNODEBYADDR */
  1130     UNLOCK_DNS();
  1131 #endif /* _PR_HAVE_GETIPNODEBYADDR */
  1133 #if defined(_PR_HAVE_GETHOST_R)
  1134     if (tmpbuf != localbuf)
  1135         PR_Free(tmpbuf);
  1136 #endif
  1138 	return rv;
  1141 /******************************************************************************/
  1142 /*
  1143  * Some systems define a reentrant version of getprotobyname(). Too bad
  1144  * the signature isn't always the same. But hey, they tried. If there
  1145  * is such a definition, use it. Otherwise, grab a lock and do it here.
  1146  */
  1147 /******************************************************************************/
  1149 #if !defined(_PR_HAVE_GETPROTO_R)
  1150 /*
  1151  * This may seem like a silly thing to do, but the compiler SHOULD
  1152  * complain if getprotobyname_r() is implemented on some system and
  1153  * we're not using it. For sure these signatures are different than
  1154  * any usable implementation.
  1155  */
  1157 #if defined(ANDROID)
  1158 /* Android's Bionic libc system includes prototypes for these in netdb.h,
  1159  * but doesn't actually include implementations.  It uses the 5-arg form,
  1160  * so these functions end up not matching the prototype.  So just rename
  1161  * them if not found.
  1162  */
  1163 #define getprotobyname_r _pr_getprotobyname_r
  1164 #define getprotobynumber_r _pr_getprotobynumber_r
  1165 #endif
  1167 static struct protoent *getprotobyname_r(const char* name)
  1169 	return getprotobyname(name);
  1170 } /* getprotobyname_r */
  1172 static struct protoent *getprotobynumber_r(PRInt32 number)
  1174 	return getprotobynumber(number);
  1175 } /* getprotobynumber_r */
  1177 #endif /* !defined(_PR_HAVE_GETPROTO_R) */
  1179 PR_IMPLEMENT(PRStatus) PR_GetProtoByName(
  1180     const char* name, char* buffer, PRInt32 buflen, PRProtoEnt* result)
  1182 	PRStatus rv = PR_SUCCESS;
  1183 #if defined(_PR_HAVE_GETPROTO_R)
  1184 	struct protoent* res = (struct protoent*)result;
  1185 #endif
  1187     if (!_pr_initialized) _PR_ImplicitInitialization();
  1189 #if defined(_PR_HAVE_GETPROTO_R_INT)
  1191         /*
  1192         ** The protoent_data has a pointer as the first field.
  1193         ** That implies the buffer better be aligned, and char*
  1194         ** doesn't promise much.
  1195         */
  1196         PRUptrdiff aligned = (PRUptrdiff)buffer;
  1197         if (0 != (aligned & (sizeof(struct protoent_data*) - 1)))
  1199             aligned += sizeof(struct protoent_data*) - 1;
  1200             aligned &= ~(sizeof(struct protoent_data*) - 1);
  1201             buflen -= (aligned - (PRUptrdiff)buffer);
  1202             buffer = (char*)aligned;
  1205 #endif  /* defined(_PR_HAVE_GETPROTO_R_INT) */
  1207     if (PR_NETDB_BUF_SIZE > buflen)
  1209         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1210         return PR_FAILURE;
  1213 #if defined(_PR_HAVE_GETPROTO_R_POINTER)
  1214     if (NULL == getprotobyname_r(name, res, buffer, buflen))
  1216         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
  1217         return PR_FAILURE;
  1219 #elif defined(_PR_HAVE_GETPROTO_R_INT)
  1220     /*
  1221     ** The buffer needs to be zero'd, and it should be
  1222     ** at least the size of a struct protoent_data.
  1223     */
  1224     memset(buffer, 0, buflen);
  1225 	if (-1 == getprotobyname_r(name, res, (struct protoent_data*)buffer))
  1227         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
  1228         return PR_FAILURE;
  1230 #elif defined(_PR_HAVE_5_ARG_GETPROTO_R)
  1231     /* The 5th argument for getprotobyname_r() cannot be NULL */
  1232     if (-1 == getprotobyname_r(name, res, buffer, buflen, &res))
  1234         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
  1235         return PR_FAILURE;
  1237 #else  /* do it the hard way */
  1239 		struct protoent *staticBuf;
  1240 		PR_Lock(_getproto_lock);
  1241 		staticBuf = getprotobyname_r(name);
  1242 		if (NULL == staticBuf)
  1244 		    rv = PR_FAILURE;
  1245 		    PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
  1247 		else
  1249 #if defined(SYMBIAN)
  1250 			char* aliases[2];
  1251 			AssignAliases(staticBuf, aliases);
  1252 #endif
  1253 			rv = CopyProtoent(staticBuf, buffer, buflen, result);
  1254 			if (PR_FAILURE == rv)
  1255 			    PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
  1257 		PR_Unlock(_getproto_lock);
  1259 #endif  /* all that */
  1260     return rv;
  1263 PR_IMPLEMENT(PRStatus) PR_GetProtoByNumber(
  1264     PRInt32 number, char* buffer, PRInt32 buflen, PRProtoEnt* result)
  1266 	PRStatus rv = PR_SUCCESS;
  1267 #if defined(_PR_HAVE_GETPROTO_R)
  1268 	struct protoent* res = (struct protoent*)result;
  1269 #endif
  1271     if (!_pr_initialized) _PR_ImplicitInitialization();
  1273 #if defined(_PR_HAVE_GETPROTO_R_INT)
  1275         /*
  1276         ** The protoent_data has a pointer as the first field.
  1277         ** That implies the buffer better be aligned, and char*
  1278         ** doesn't promise much.
  1279         */
  1280         PRUptrdiff aligned = (PRUptrdiff)buffer;
  1281         if (0 != (aligned & (sizeof(struct protoent_data*) - 1)))
  1283             aligned += sizeof(struct protoent_data*) - 1;
  1284             aligned &= ~(sizeof(struct protoent_data*) - 1);
  1285             buflen -= (aligned - (PRUptrdiff)buffer);
  1286             buffer = (char*)aligned;
  1289 #endif /* defined(_PR_HAVE_GETPROTO_R_INT) */
  1291     if (PR_NETDB_BUF_SIZE > buflen)
  1293         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1294         return PR_FAILURE;
  1297 #if defined(_PR_HAVE_GETPROTO_R_POINTER)
  1298     if (NULL == getprotobynumber_r(number, res, buffer, buflen))
  1300         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
  1301         return PR_FAILURE;
  1304 #elif defined(_PR_HAVE_GETPROTO_R_INT)
  1305     /*
  1306     ** The buffer needs to be zero'd for these OS's.
  1307     */
  1308     memset(buffer, 0, buflen);
  1309 	if (-1 == getprotobynumber_r(number, res, (struct protoent_data*)buffer))
  1311         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
  1312         return PR_FAILURE;
  1314 #elif defined(_PR_HAVE_5_ARG_GETPROTO_R)
  1315     /* The 5th argument for getprotobynumber_r() cannot be NULL */
  1316     if (-1 == getprotobynumber_r(number, res, buffer, buflen, &res))
  1318         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
  1319         return PR_FAILURE;
  1321 #else  /* do it the hard way */
  1323 		struct protoent *staticBuf;
  1324 		PR_Lock(_getproto_lock);
  1325 		staticBuf = getprotobynumber_r(number);
  1326 		if (NULL == staticBuf)
  1328 		    rv = PR_FAILURE;
  1329 		    PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
  1331 		else
  1333 #if defined(SYMBIAN)
  1334 			char* aliases[2];
  1335 			AssignAliases(staticBuf, aliases);
  1336 #endif
  1337 			rv = CopyProtoent(staticBuf, buffer, buflen, result);
  1338 			if (PR_FAILURE == rv)
  1339 			    PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
  1341 		PR_Unlock(_getproto_lock);
  1343 #endif  /* all that crap */
  1344     return rv;
  1348 PRUintn _PR_NetAddrSize(const PRNetAddr* addr)
  1350     PRUintn addrsize;
  1352     /*
  1353      * RFC 2553 added a new field (sin6_scope_id) to
  1354      * struct sockaddr_in6.  PRNetAddr's ipv6 member has a
  1355      * scope_id field to match the new field.  In order to
  1356      * work with older implementations supporting RFC 2133,
  1357      * we take the size of struct sockaddr_in6 instead of
  1358      * addr->ipv6.
  1359      */
  1360     if (AF_INET == addr->raw.family)
  1361         addrsize = sizeof(addr->inet);
  1362     else if (PR_AF_INET6 == addr->raw.family)
  1363 #if defined(_PR_INET6)
  1364         addrsize = sizeof(struct sockaddr_in6);
  1365 #else
  1366         addrsize = sizeof(addr->ipv6);
  1367 #endif
  1368 #if defined(XP_UNIX) || defined(XP_OS2)
  1369     else if (AF_UNIX == addr->raw.family)
  1370         addrsize = sizeof(addr->local);
  1371 #endif
  1372     else addrsize = 0;
  1374     return addrsize;
  1375 }  /* _PR_NetAddrSize */
  1377 PR_IMPLEMENT(PRIntn) PR_EnumerateHostEnt(
  1378     PRIntn enumIndex, const PRHostEnt *hostEnt, PRUint16 port, PRNetAddr *address)
  1380     void *addr = hostEnt->h_addr_list[enumIndex++];
  1381     memset(address, 0, sizeof(PRNetAddr));
  1382     if (NULL == addr) enumIndex = 0;
  1383     else
  1385         address->raw.family = hostEnt->h_addrtype;
  1386         if (PR_AF_INET6 == hostEnt->h_addrtype)
  1388             address->ipv6.port = htons(port);
  1389         	address->ipv6.flowinfo = 0;
  1390         	address->ipv6.scope_id = 0;
  1391             memcpy(&address->ipv6.ip, addr, hostEnt->h_length);
  1393         else
  1395             PR_ASSERT(AF_INET == hostEnt->h_addrtype);
  1396             address->inet.port = htons(port);
  1397             memcpy(&address->inet.ip, addr, hostEnt->h_length);
  1400     return enumIndex;
  1401 }  /* PR_EnumerateHostEnt */
  1403 PR_IMPLEMENT(PRStatus) PR_InitializeNetAddr(
  1404     PRNetAddrValue val, PRUint16 port, PRNetAddr *addr)
  1406     PRStatus rv = PR_SUCCESS;
  1407     if (!_pr_initialized) _PR_ImplicitInitialization();
  1409 	if (val != PR_IpAddrNull) memset(addr, 0, sizeof(addr->inet));
  1410 	addr->inet.family = AF_INET;
  1411 	addr->inet.port = htons(port);
  1412 	switch (val)
  1414 	case PR_IpAddrNull:
  1415 		break;  /* don't overwrite the address */
  1416 	case PR_IpAddrAny:
  1417 		addr->inet.ip = htonl(INADDR_ANY);
  1418 		break;
  1419 	case PR_IpAddrLoopback:
  1420 		addr->inet.ip = htonl(INADDR_LOOPBACK);
  1421 		break;
  1422 	default:
  1423 		PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1424 		rv = PR_FAILURE;
  1426     return rv;
  1427 }  /* PR_InitializeNetAddr */
  1429 PR_IMPLEMENT(PRStatus) PR_SetNetAddr(
  1430     PRNetAddrValue val, PRUint16 af, PRUint16 port, PRNetAddr *addr)
  1432     PRStatus rv = PR_SUCCESS;
  1433     if (!_pr_initialized) _PR_ImplicitInitialization();
  1435     if (af == PR_AF_INET6)
  1437         if (val != PR_IpAddrNull) memset(addr, 0, sizeof(addr->ipv6));
  1438         addr->ipv6.family = af;
  1439         addr->ipv6.port = htons(port);
  1440         addr->ipv6.flowinfo = 0;
  1441         addr->ipv6.scope_id = 0;
  1442         switch (val)
  1444         case PR_IpAddrNull:
  1445             break;  /* don't overwrite the address */
  1446         case PR_IpAddrAny:
  1447             addr->ipv6.ip = _pr_in6addr_any;
  1448             break;
  1449         case PR_IpAddrLoopback:
  1450             addr->ipv6.ip = _pr_in6addr_loopback;
  1451             break;
  1452         default:
  1453             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1454             rv = PR_FAILURE;
  1457     else
  1459         if (val != PR_IpAddrNull) memset(addr, 0, sizeof(addr->inet));
  1460         addr->inet.family = af;
  1461         addr->inet.port = htons(port);
  1462         switch (val)
  1464         case PR_IpAddrNull:
  1465             break;  /* don't overwrite the address */
  1466         case PR_IpAddrAny:
  1467             addr->inet.ip = htonl(INADDR_ANY);
  1468             break;
  1469         case PR_IpAddrLoopback:
  1470             addr->inet.ip = htonl(INADDR_LOOPBACK);
  1471             break;
  1472         default:
  1473             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1474             rv = PR_FAILURE;
  1477     return rv;
  1478 }  /* PR_SetNetAddr */
  1480 PR_IMPLEMENT(PRBool)
  1481 PR_IsNetAddrType(const PRNetAddr *addr, PRNetAddrValue val)
  1483     if (addr->raw.family == PR_AF_INET6) {
  1484         if (val == PR_IpAddrAny) {
  1485 			if (_PR_IN6_IS_ADDR_UNSPECIFIED((PRIPv6Addr *)&addr->ipv6.ip)) {
  1486             	return PR_TRUE;
  1487 			} else if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip)
  1488 					&& _PR_IN6_V4MAPPED_TO_IPADDR((PRIPv6Addr *)&addr->ipv6.ip)
  1489 							== htonl(INADDR_ANY)) {
  1490             	return PR_TRUE;
  1492         } else if (val == PR_IpAddrLoopback) {
  1493             if (_PR_IN6_IS_ADDR_LOOPBACK((PRIPv6Addr *)&addr->ipv6.ip)) {
  1494             	return PR_TRUE;
  1495 			} else if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip)
  1496 					&& _PR_IN6_V4MAPPED_TO_IPADDR((PRIPv6Addr *)&addr->ipv6.ip)
  1497 							== htonl(INADDR_LOOPBACK)) {
  1498             	return PR_TRUE;
  1500         } else if (val == PR_IpAddrV4Mapped
  1501                 && _PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip)) {
  1502             return PR_TRUE;
  1504     } else {
  1505         if (addr->raw.family == AF_INET) {
  1506             if (val == PR_IpAddrAny && addr->inet.ip == htonl(INADDR_ANY)) {
  1507                 return PR_TRUE;
  1508             } else if (val == PR_IpAddrLoopback
  1509                     && addr->inet.ip == htonl(INADDR_LOOPBACK)) {
  1510                 return PR_TRUE;
  1514     return PR_FALSE;
  1517 extern int pr_inet_aton(const char *cp, PRUint32 *addr);
  1519 #define XX 127
  1520 static const unsigned char index_hex[256] = {
  1521     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  1522     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  1523     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  1524      0, 1, 2, 3,  4, 5, 6, 7,  8, 9,XX,XX, XX,XX,XX,XX,
  1525     XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  1526     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  1527     XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  1528     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  1529     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  1530     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  1531     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  1532     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  1533     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  1534     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  1535     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  1536     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  1537 };
  1539 /*
  1540  * StringToV6Addr() returns 1 if the conversion succeeds,
  1541  * or 0 if the input is not a valid IPv6 address string.
  1542  * (Same as inet_pton(AF_INET6, string, addr).)
  1543  */
  1544 static int StringToV6Addr(const char *string, PRIPv6Addr *addr)
  1546     const unsigned char *s = (const unsigned char *)string;
  1547     int section = 0;        /* index of the current section (a 16-bit
  1548                              * piece of the address */
  1549     int double_colon = -1;  /* index of the section after the first
  1550                              * 16-bit group of zeros represented by
  1551                              * the double colon */
  1552     unsigned int val;
  1553     int len;
  1555     /* Handle initial (double) colon */
  1556     if (*s == ':') {
  1557         if (s[1] != ':') return 0;
  1558         s += 2;
  1559         addr->pr_s6_addr16[0] = 0;
  1560         section = double_colon = 1;
  1563     while (*s) {
  1564         if (section == 8) return 0; /* too long */
  1565         if (*s == ':') {
  1566             if (double_colon != -1) return 0; /* two double colons */
  1567             addr->pr_s6_addr16[section++] = 0;
  1568             double_colon = section;
  1569             s++;
  1570             continue;
  1572         for (len = val = 0; len < 4 && index_hex[*s] != XX; len++) {
  1573             val = (val << 4) + index_hex[*s++];
  1575         if (*s == '.') {
  1576             if (len == 0) return 0; /* nothing between : and . */
  1577             break;
  1579         if (*s == ':') {
  1580             s++;
  1581             if (!*s) return 0; /* cannot end with single colon */
  1582         } else if (*s) {
  1583             return 0; /* bad character */
  1585         addr->pr_s6_addr16[section++] = htons((unsigned short)val);
  1588     if (*s == '.') {
  1589         /* Have a trailing v4 format address */
  1590         if (section > 6) return 0; /* not enough room */
  1592         /*
  1593          * The number before the '.' is decimal, but we parsed it
  1594          * as hex.  That means it is in BCD.  Check it for validity
  1595          * and convert it to binary.
  1596          */
  1597         if (val > 0x0255 || (val & 0xf0) > 0x90 || (val & 0xf) > 9) return 0;
  1598         val = (val >> 8) * 100 + ((val >> 4) & 0xf) * 10 + (val & 0xf);
  1599         addr->pr_s6_addr[2 * section] = val;
  1601         s++;
  1602         val = index_hex[*s++];
  1603         if (val > 9) return 0;
  1604         while (*s >= '0' && *s <= '9') {
  1605             val = val * 10 + *s++ - '0';
  1606             if (val > 255) return 0;
  1608         if (*s != '.') return 0; /* must have exactly 4 decimal numbers */
  1609         addr->pr_s6_addr[2 * section + 1] = val;
  1610         section++;
  1612         s++;
  1613         val = index_hex[*s++];
  1614         if (val > 9) return 0;
  1615         while (*s >= '0' && *s <= '9') {
  1616             val = val * 10 + *s++ - '0';
  1617             if (val > 255) return 0;
  1619         if (*s != '.') return 0; /* must have exactly 4 decimal numbers */
  1620         addr->pr_s6_addr[2 * section] = val;
  1622         s++;
  1623         val = index_hex[*s++];
  1624         if (val > 9) return 0;
  1625         while (*s >= '0' && *s <= '9') {
  1626             val = val * 10 + *s++ - '0';
  1627             if (val > 255) return 0;
  1629         if (*s) return 0; /* must have exactly 4 decimal numbers */
  1630         addr->pr_s6_addr[2 * section + 1] = val;
  1631         section++;
  1634     if (double_colon != -1) {
  1635         /* Stretch the double colon */
  1636         int tosection;
  1637         int ncopy = section - double_colon;
  1638         for (tosection = 7; ncopy--; tosection--) {
  1639             addr->pr_s6_addr16[tosection] = 
  1640                 addr->pr_s6_addr16[double_colon + ncopy];
  1642         while (tosection >= double_colon) {
  1643             addr->pr_s6_addr16[tosection--] = 0;
  1645     } else if (section != 8) {
  1646         return 0; /* too short */
  1648     return 1;
  1650 #undef XX
  1652 #ifndef _PR_HAVE_INET_NTOP
  1653 static const char *basis_hex = "0123456789abcdef";
  1655 /*
  1656  * V6AddrToString() returns a pointer to the buffer containing
  1657  * the text string if the conversion succeeds, and NULL otherwise.
  1658  * (Same as inet_ntop(AF_INET6, addr, buf, size), except that errno
  1659  * is not set on failure.)
  1660  */
  1661 static const char *V6AddrToString(
  1662     const PRIPv6Addr *addr, char *buf, PRUint32 size)
  1664 #define STUFF(c) do { \
  1665     if (!size--) return NULL; \
  1666     *buf++ = (c); \
  1667 } while (0)
  1669     int double_colon = -1;          /* index of the first 16-bit
  1670                                      * group of zeros represented
  1671                                      * by the double colon */
  1672     int double_colon_length = 1;    /* use double colon only if
  1673                                      * there are two or more 16-bit
  1674                                      * groups of zeros */
  1675     int zero_length;
  1676     int section;
  1677     unsigned int val;
  1678     const char *bufcopy = buf;
  1680     /* Scan to find the placement of the double colon */
  1681     for (section = 0; section < 8; section++) {
  1682         if (addr->pr_s6_addr16[section] == 0) {
  1683             zero_length = 1;
  1684             section++;
  1685             while (section < 8 && addr->pr_s6_addr16[section] == 0) {
  1686                 zero_length++;
  1687                 section++;
  1689             /* Select the longest sequence of zeros */
  1690             if (zero_length > double_colon_length) {
  1691                 double_colon = section - zero_length;
  1692                 double_colon_length = zero_length;
  1697     /* Now start converting to a string */
  1698     section = 0;
  1700     if (double_colon == 0) {
  1701         if (double_colon_length == 6 ||
  1702             (double_colon_length == 5 && addr->pr_s6_addr16[5] == 0xffff)) {
  1703             /* ipv4 format address */
  1704             STUFF(':');
  1705             STUFF(':');
  1706             if (double_colon_length == 5) {
  1707                 STUFF('f');
  1708                 STUFF('f');
  1709                 STUFF('f');
  1710                 STUFF('f');
  1711                 STUFF(':');
  1713             if (addr->pr_s6_addr[12] > 99) STUFF(addr->pr_s6_addr[12]/100 + '0');
  1714             if (addr->pr_s6_addr[12] > 9) STUFF((addr->pr_s6_addr[12]%100)/10 + '0');
  1715             STUFF(addr->pr_s6_addr[12]%10 + '0');
  1716             STUFF('.');
  1717             if (addr->pr_s6_addr[13] > 99) STUFF(addr->pr_s6_addr[13]/100 + '0');
  1718             if (addr->pr_s6_addr[13] > 9) STUFF((addr->pr_s6_addr[13]%100)/10 + '0');
  1719             STUFF(addr->pr_s6_addr[13]%10 + '0');
  1720             STUFF('.');
  1721             if (addr->pr_s6_addr[14] > 99) STUFF(addr->pr_s6_addr[14]/100 + '0');
  1722             if (addr->pr_s6_addr[14] > 9) STUFF((addr->pr_s6_addr[14]%100)/10 + '0');
  1723             STUFF(addr->pr_s6_addr[14]%10 + '0');
  1724             STUFF('.');
  1725             if (addr->pr_s6_addr[15] > 99) STUFF(addr->pr_s6_addr[15]/100 + '0');
  1726             if (addr->pr_s6_addr[15] > 9) STUFF((addr->pr_s6_addr[15]%100)/10 + '0');
  1727             STUFF(addr->pr_s6_addr[15]%10 + '0');
  1728             STUFF('\0');
  1729             return bufcopy;
  1733     while (section < 8) {
  1734         if (section == double_colon) {
  1735             STUFF(':');
  1736             STUFF(':');
  1737             section += double_colon_length;
  1738             continue;
  1740         val = ntohs(addr->pr_s6_addr16[section]);
  1741         if (val > 0xfff) {
  1742             STUFF(basis_hex[val >> 12]);
  1744         if (val > 0xff) {
  1745             STUFF(basis_hex[(val >> 8) & 0xf]);
  1747         if (val > 0xf) {
  1748             STUFF(basis_hex[(val >> 4) & 0xf]);
  1750         STUFF(basis_hex[val & 0xf]);
  1751         section++;
  1752         if (section < 8 && section != double_colon) STUFF(':');
  1754     STUFF('\0');
  1755     return bufcopy;
  1756 #undef STUFF    
  1758 #endif /* !_PR_HAVE_INET_NTOP */
  1760 /*
  1761  * Convert an IPv4 addr to an (IPv4-mapped) IPv6 addr
  1762  */
  1763 PR_IMPLEMENT(void) PR_ConvertIPv4AddrToIPv6(PRUint32 v4addr, PRIPv6Addr *v6addr)
  1765     PRUint8 *dstp;
  1766     dstp = v6addr->pr_s6_addr;
  1767     memset(dstp, 0, 10);
  1768     memset(dstp + 10, 0xff, 2);
  1769     memcpy(dstp + 12,(char *) &v4addr, 4);
  1772 PR_IMPLEMENT(PRUint16) PR_ntohs(PRUint16 n) { return ntohs(n); }
  1773 PR_IMPLEMENT(PRUint32) PR_ntohl(PRUint32 n) { return ntohl(n); }
  1774 PR_IMPLEMENT(PRUint16) PR_htons(PRUint16 n) { return htons(n); }
  1775 PR_IMPLEMENT(PRUint32) PR_htonl(PRUint32 n) { return htonl(n); }
  1776 PR_IMPLEMENT(PRUint64) PR_ntohll(PRUint64 n)
  1778 #ifdef IS_BIG_ENDIAN
  1779     return n;
  1780 #else
  1781     PRUint64 tmp;
  1782     PRUint32 hi, lo;
  1783     LL_L2UI(lo, n);
  1784     LL_SHR(tmp, n, 32);
  1785     LL_L2UI(hi, tmp);
  1786     hi = PR_ntohl(hi);
  1787     lo = PR_ntohl(lo);
  1788     LL_UI2L(n, lo);
  1789     LL_SHL(n, n, 32);
  1790     LL_UI2L(tmp, hi);
  1791     LL_ADD(n, n, tmp);
  1792     return n;
  1793 #endif
  1794 }  /* ntohll */
  1796 PR_IMPLEMENT(PRUint64) PR_htonll(PRUint64 n)
  1798 #ifdef IS_BIG_ENDIAN
  1799     return n;
  1800 #else
  1801     PRUint64 tmp;
  1802     PRUint32 hi, lo;
  1803     LL_L2UI(lo, n);
  1804     LL_SHR(tmp, n, 32);
  1805     LL_L2UI(hi, tmp);
  1806     hi = htonl(hi);
  1807     lo = htonl(lo);
  1808     LL_UI2L(n, lo);
  1809     LL_SHL(n, n, 32);
  1810     LL_UI2L(tmp, hi);
  1811     LL_ADD(n, n, tmp);
  1812     return n;
  1813 #endif
  1814 }  /* htonll */
  1817 /*
  1818  * Implementation of PR_GetAddrInfoByName and friends
  1820  * Compile-time options:
  1822  *  _PR_HAVE_GETADDRINFO  Define this macro if the target system provides
  1823  *                        getaddrinfo. With this defined, NSPR will require
  1824  *                        getaddrinfo at run time. If this if not defined,
  1825  *                        then NSPR will attempt to dynamically resolve
  1826  *                        getaddrinfo, falling back to PR_GetHostByName if
  1827  *                        getaddrinfo does not exist on the target system.
  1829  * Since getaddrinfo is a relatively new system call on many systems,
  1830  * we are forced to dynamically resolve it at run time in most cases.
  1831  * The exception includes any system (such as Mac OS X) that is known to
  1832  * provide getaddrinfo in all versions that NSPR cares to support.
  1833  */
  1835 #if defined(_PR_HAVE_GETADDRINFO)
  1837 #if defined(_PR_INET6)
  1839 typedef struct addrinfo PRADDRINFO;
  1840 #define GETADDRINFO getaddrinfo
  1841 #define FREEADDRINFO freeaddrinfo
  1842 #define GETNAMEINFO getnameinfo
  1844 #elif defined(_PR_INET6_PROBE)
  1846 typedef struct addrinfo PRADDRINFO;
  1848 /* getaddrinfo/freeaddrinfo/getnameinfo prototypes */ 
  1849 #if defined(WIN32)
  1850 #define FUNC_MODIFIER __stdcall
  1851 #else
  1852 #define FUNC_MODIFIER
  1853 #endif
  1854 typedef int (FUNC_MODIFIER * FN_GETADDRINFO)
  1855     (const char *nodename,
  1856      const char *servname,
  1857      const PRADDRINFO *hints,
  1858      PRADDRINFO **res);
  1859 typedef int (FUNC_MODIFIER * FN_FREEADDRINFO)
  1860     (PRADDRINFO *ai);
  1861 typedef int (FUNC_MODIFIER * FN_GETNAMEINFO)
  1862     (const struct sockaddr *addr, int addrlen,
  1863      char *host, int hostlen,
  1864      char *serv, int servlen, int flags);
  1866 /* global state */
  1867 static FN_GETADDRINFO   _pr_getaddrinfo   = NULL;
  1868 static FN_FREEADDRINFO  _pr_freeaddrinfo  = NULL;
  1869 static FN_GETNAMEINFO   _pr_getnameinfo   = NULL;
  1871 #define GETADDRINFO_SYMBOL "getaddrinfo"
  1872 #define FREEADDRINFO_SYMBOL "freeaddrinfo"
  1873 #define GETNAMEINFO_SYMBOL "getnameinfo"
  1875 PRStatus
  1876 _pr_find_getaddrinfo(void)
  1878     PRLibrary *lib;
  1879 #ifdef WIN32
  1880     /*
  1881      * On windows, we need to search ws2_32.dll or wship6.dll
  1882      * (Microsoft IPv6 Technology Preview for Windows 2000) for
  1883      * getaddrinfo and freeaddrinfo.  These libraries might not
  1884      * be loaded yet.
  1885      */
  1886     const char *libname[] = { "ws2_32.dll", "wship6.dll" };
  1887     int i;
  1889     for (i = 0; i < sizeof(libname)/sizeof(libname[0]); i++) {
  1890         lib = PR_LoadLibrary(libname[i]);
  1891         if (!lib) {
  1892             continue;
  1894         _pr_getaddrinfo = (FN_GETADDRINFO)
  1895             PR_FindFunctionSymbol(lib, GETADDRINFO_SYMBOL);
  1896         if (!_pr_getaddrinfo) {
  1897             PR_UnloadLibrary(lib);
  1898             continue;
  1900         _pr_freeaddrinfo = (FN_FREEADDRINFO)
  1901             PR_FindFunctionSymbol(lib, FREEADDRINFO_SYMBOL);
  1902         _pr_getnameinfo = (FN_GETNAMEINFO)
  1903             PR_FindFunctionSymbol(lib, GETNAMEINFO_SYMBOL);
  1904         if (!_pr_freeaddrinfo || !_pr_getnameinfo) {
  1905             PR_UnloadLibrary(lib);
  1906             continue;
  1908         /* Keep the library loaded. */
  1909         return PR_SUCCESS;
  1911     return PR_FAILURE;
  1912 #else
  1913     /*
  1914      * Resolve getaddrinfo by searching all loaded libraries.  Then
  1915      * search library containing getaddrinfo for freeaddrinfo.
  1916      */
  1917     _pr_getaddrinfo = (FN_GETADDRINFO)
  1918         PR_FindFunctionSymbolAndLibrary(GETADDRINFO_SYMBOL, &lib);
  1919     if (!_pr_getaddrinfo) {
  1920         return PR_FAILURE;
  1922     _pr_freeaddrinfo = (FN_FREEADDRINFO)
  1923         PR_FindFunctionSymbol(lib, FREEADDRINFO_SYMBOL);
  1924     _pr_getnameinfo = (FN_GETNAMEINFO)
  1925         PR_FindFunctionSymbol(lib, GETNAMEINFO_SYMBOL);
  1926     PR_UnloadLibrary(lib);
  1927     if (!_pr_freeaddrinfo || !_pr_getnameinfo) {
  1928         return PR_FAILURE;
  1930     return PR_SUCCESS;
  1931 #endif
  1934 #define GETADDRINFO (*_pr_getaddrinfo)
  1935 #define FREEADDRINFO (*_pr_freeaddrinfo)
  1936 #define GETNAMEINFO (*_pr_getnameinfo)
  1938 #endif /* _PR_INET6 */
  1940 #endif /* _PR_HAVE_GETADDRINFO */
  1942 #if !defined(_PR_HAVE_GETADDRINFO) || defined(_PR_INET6_PROBE)
  1943 /*
  1944  * If getaddrinfo does not exist, then we will fall back on
  1945  * PR_GetHostByName, which requires that we allocate a buffer for the 
  1946  * PRHostEnt data structure and its members.
  1947  */
  1948 typedef struct PRAddrInfoFB {
  1949     char      buf[PR_NETDB_BUF_SIZE];
  1950     PRHostEnt hostent;
  1951     PRBool    has_cname;
  1952 } PRAddrInfoFB;
  1954 static PRAddrInfo *
  1955 pr_GetAddrInfoByNameFB(const char  *hostname,
  1956                        PRUint16     af,
  1957                        PRIntn       flags)
  1959     PRStatus rv;
  1960     PRAddrInfoFB *ai;
  1961     /* fallback on PR_GetHostByName */
  1962     ai = PR_NEW(PRAddrInfoFB);
  1963     if (!ai) {
  1964         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  1965         return NULL;
  1967     rv = PR_GetHostByName(hostname, ai->buf, sizeof ai->buf, &ai->hostent);
  1968     if (rv == PR_FAILURE) {
  1969         PR_Free(ai);
  1970         return NULL;
  1972     ai->has_cname = !(flags & PR_AI_NOCANONNAME);
  1974     return (PRAddrInfo *) ai;
  1976 #endif /* !_PR_HAVE_GETADDRINFO || _PR_INET6_PROBE */
  1978 PR_IMPLEMENT(PRAddrInfo *) PR_GetAddrInfoByName(const char  *hostname,
  1979                                                 PRUint16     af,
  1980                                                 PRIntn       flags)
  1982     /* restrict input to supported values */
  1983     if ((af != PR_AF_INET && af != PR_AF_UNSPEC) ||
  1984         (flags & ~ PR_AI_NOCANONNAME) != PR_AI_ADDRCONFIG) {
  1985         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1986         return NULL;
  1989     if (!_pr_initialized) _PR_ImplicitInitialization();
  1991 #if !defined(_PR_HAVE_GETADDRINFO)
  1992     return pr_GetAddrInfoByNameFB(hostname, af, flags);
  1993 #else
  1994 #if defined(_PR_INET6_PROBE)
  1995     if (!_pr_ipv6_is_present()) {
  1996         return pr_GetAddrInfoByNameFB(hostname, af, flags);
  1998 #endif
  2000         PRADDRINFO *res, hints;
  2001         int rv;
  2003         /*
  2004          * we assume a RFC 2553 compliant getaddrinfo.  this may at some
  2005          * point need to be customized as platforms begin to adopt the
  2006          * RFC 3493.
  2007          */
  2009         memset(&hints, 0, sizeof(hints));
  2010         if (!(flags & PR_AI_NOCANONNAME))
  2011             hints.ai_flags |= AI_CANONNAME;
  2012 #ifdef AI_ADDRCONFIG
  2013         /* 
  2014          * Propagate AI_ADDRCONFIG to the GETADDRINFO call if PR_AI_ADDRCONFIG
  2015          * is set.
  2017          * Need a workaround for loopback host addresses:         
  2018          * The problem is that in glibc and Windows, AI_ADDRCONFIG applies the
  2019          * existence of an outgoing network interface to IP addresses of the
  2020          * loopback interface, due to a strict interpretation of the
  2021          * specification.  For example, if a computer does not have any
  2022          * outgoing IPv6 network interface, but its loopback network interface
  2023          * supports IPv6, a getaddrinfo call on "localhost" with AI_ADDRCONFIG
  2024          * won't return the IPv6 loopback address "::1", because getaddrinfo
  2025          * thinks the computer cannot connect to any IPv6 destination,
  2026          * ignoring the remote vs. local/loopback distinction.
  2027          */
  2028         if ((flags & PR_AI_ADDRCONFIG) &&
  2029             strcmp(hostname, "localhost") != 0 &&
  2030             strcmp(hostname, "localhost.localdomain") != 0 &&
  2031             strcmp(hostname, "localhost6") != 0 &&
  2032             strcmp(hostname, "localhost6.localdomain6") != 0) {
  2033             hints.ai_flags |= AI_ADDRCONFIG;
  2035 #endif
  2036         hints.ai_family = (af == PR_AF_INET) ? AF_INET : AF_UNSPEC;
  2038         /*
  2039          * it is important to select a socket type in the hints, otherwise we
  2040          * will get back repetitive entries: one for each socket type.  since
  2041          * we do not expose ai_socktype through our API, it is okay to do this
  2042          * here.  the application may still choose to create a socket of some
  2043          * other type.
  2044          */
  2045         hints.ai_socktype = SOCK_STREAM;
  2047         rv = GETADDRINFO(hostname, NULL, &hints, &res);
  2048 #ifdef AI_ADDRCONFIG
  2049         if (rv == EAI_BADFLAGS && (hints.ai_flags & AI_ADDRCONFIG)) {
  2050             hints.ai_flags &= ~AI_ADDRCONFIG;
  2051             rv = GETADDRINFO(hostname, NULL, &hints, &res);
  2053 #endif
  2054         if (rv == 0)
  2055             return (PRAddrInfo *) res;
  2057         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, rv);
  2059     return NULL;
  2060 #endif
  2063 PR_IMPLEMENT(void) PR_FreeAddrInfo(PRAddrInfo *ai)
  2065 #if defined(_PR_HAVE_GETADDRINFO)
  2066 #if defined(_PR_INET6_PROBE)
  2067     if (!_pr_ipv6_is_present())
  2068         PR_Free((PRAddrInfoFB *) ai);
  2069     else
  2070 #endif
  2071         FREEADDRINFO((PRADDRINFO *) ai);
  2072 #else
  2073     PR_Free((PRAddrInfoFB *) ai);
  2074 #endif
  2077 PR_IMPLEMENT(void *) PR_EnumerateAddrInfo(void             *iterPtr,
  2078                                           const PRAddrInfo *base,
  2079                                           PRUint16          port,
  2080                                           PRNetAddr        *result)
  2082 #if defined(_PR_HAVE_GETADDRINFO)
  2083     PRADDRINFO *ai;
  2084 #if defined(_PR_INET6_PROBE)
  2085     if (!_pr_ipv6_is_present()) {
  2086         /* using PRAddrInfoFB */
  2087         PRIntn iter = (PRIntn)(PRPtrdiff) iterPtr;
  2088         iter = PR_EnumerateHostEnt(iter, &((PRAddrInfoFB *) base)->hostent, port, result);
  2089         if (iter < 0)
  2090             iter = 0;
  2091         return (void *)(PRPtrdiff) iter;
  2093 #endif
  2095     if (iterPtr)
  2096         ai = ((PRADDRINFO *) iterPtr)->ai_next;
  2097     else
  2098         ai = (PRADDRINFO *) base;
  2100     while (ai && ai->ai_addrlen > sizeof(PRNetAddr))
  2101         ai = ai->ai_next;
  2103     if (ai) {
  2104         /* copy sockaddr to PRNetAddr */
  2105         memcpy(result, ai->ai_addr, ai->ai_addrlen);
  2106         result->raw.family = ai->ai_addr->sa_family;
  2107 #ifdef _PR_INET6
  2108         if (AF_INET6 == result->raw.family)
  2109             result->raw.family = PR_AF_INET6;
  2110 #endif
  2111         if (ai->ai_addrlen < sizeof(PRNetAddr))
  2112             memset(((char*)result)+ai->ai_addrlen, 0, sizeof(PRNetAddr) - ai->ai_addrlen);
  2114         if (result->raw.family == PR_AF_INET)
  2115             result->inet.port = htons(port);
  2116         else
  2117             result->ipv6.port = htons(port);
  2120     return ai;
  2121 #else
  2122     /* using PRAddrInfoFB */
  2123     PRIntn iter = (PRIntn) iterPtr;
  2124     iter = PR_EnumerateHostEnt(iter, &((PRAddrInfoFB *) base)->hostent, port, result);
  2125     if (iter < 0)
  2126         iter = 0;
  2127     return (void *) iter;
  2128 #endif
  2131 PR_IMPLEMENT(const char *) PR_GetCanonNameFromAddrInfo(const PRAddrInfo *ai)
  2133 #if defined(_PR_HAVE_GETADDRINFO)
  2134 #if defined(_PR_INET6_PROBE)
  2135     if (!_pr_ipv6_is_present()) {
  2136         const PRAddrInfoFB *fb = (const PRAddrInfoFB *) ai;
  2137         return fb->has_cname ? fb->hostent.h_name : NULL;
  2139 #endif
  2140     return ((const PRADDRINFO *) ai)->ai_canonname;
  2141 #else
  2142     const PRAddrInfoFB *fb = (const PRAddrInfoFB *) ai;
  2143     return fb->has_cname ? fb->hostent.h_name : NULL;
  2144 #endif
  2147 #if defined(_PR_HAVE_GETADDRINFO)
  2148 static PRStatus pr_StringToNetAddrGAI(const char *string, PRNetAddr *addr)
  2150     PRADDRINFO *res, hints;
  2151     int rv;  /* 0 for success, or the error code EAI_xxx */
  2152     PRNetAddr laddr;
  2153     PRStatus status = PR_SUCCESS;
  2155     memset(&hints, 0, sizeof(hints));
  2156     hints.ai_flags = AI_NUMERICHOST;
  2157     hints.ai_family = AF_UNSPEC;
  2158     hints.ai_socktype = SOCK_STREAM;
  2160     rv = GETADDRINFO(string, NULL, &hints, &res);
  2161     if (rv != 0)
  2163         PR_SetError(PR_INVALID_ARGUMENT_ERROR, rv);
  2164         return PR_FAILURE;
  2167     /* pick up the first addr */
  2168     memcpy(&laddr, res->ai_addr, res->ai_addrlen);
  2169     if (AF_INET6 == res->ai_addr->sa_family)
  2171         addr->ipv6.family = PR_AF_INET6;
  2172         addr->ipv6.ip = laddr.ipv6.ip;
  2173         addr->ipv6.scope_id = laddr.ipv6.scope_id;
  2175     else if (AF_INET == res->ai_addr->sa_family)
  2177         addr->inet.family = PR_AF_INET;
  2178         addr->inet.ip = laddr.inet.ip;
  2180     else
  2182         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  2183         status = PR_FAILURE;
  2186     FREEADDRINFO(res);
  2187     return status;
  2189 #endif  /* _PR_HAVE_GETADDRINFO */
  2191 static PRStatus pr_StringToNetAddrFB(const char *string, PRNetAddr *addr)
  2193     PRIntn rv;
  2195     rv = pr_inet_aton(string, &addr->inet.ip);
  2196     if (1 == rv)
  2198         addr->raw.family = AF_INET;
  2199         return PR_SUCCESS;
  2202     PR_ASSERT(0 == rv);
  2203     /* clean up after the failed call */
  2204     memset(&addr->inet.ip, 0, sizeof(addr->inet.ip));
  2206     rv = StringToV6Addr(string, &addr->ipv6.ip);
  2207     if (1 == rv)
  2209         addr->raw.family = PR_AF_INET6;
  2210         return PR_SUCCESS;
  2213     PR_ASSERT(0 == rv);
  2214     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  2215     return PR_FAILURE;
  2218 PR_IMPLEMENT(PRStatus) PR_StringToNetAddr(const char *string, PRNetAddr *addr)
  2220     if (!_pr_initialized) _PR_ImplicitInitialization();
  2222     if (!addr || !string || !*string)
  2224         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  2225         return PR_FAILURE;
  2228 #if !defined(_PR_HAVE_GETADDRINFO)
  2229     return pr_StringToNetAddrFB(string, addr);
  2230 #else
  2231     /*
  2232      * getaddrinfo with AI_NUMERICHOST is much slower than pr_inet_aton on some
  2233      * platforms, such as Mac OS X (bug 404399), Linux glibc 2.10 (bug 344809),
  2234      * and most likely others. So we only use it to convert literal IP addresses
  2235      * that contain IPv6 scope IDs, which pr_inet_aton cannot convert.
  2236      */
  2237     if (!strchr(string, '%'))
  2238         return pr_StringToNetAddrFB(string, addr);
  2240 #if defined(_PR_INET6_PROBE)
  2241     if (!_pr_ipv6_is_present())
  2242         return pr_StringToNetAddrFB(string, addr);
  2243 #endif
  2245     return pr_StringToNetAddrGAI(string, addr);
  2246 #endif
  2249 #if defined(_PR_HAVE_GETADDRINFO)
  2250 static PRStatus pr_NetAddrToStringGNI(
  2251     const PRNetAddr *addr, char *string, PRUint32 size)
  2253     int addrlen;
  2254     const PRNetAddr *addrp = addr;
  2255 #if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
  2256     PRUint16 md_af = addr->raw.family;
  2257     PRNetAddr addrcopy;
  2258 #endif
  2259     int rv;  /* 0 for success, or the error code EAI_xxx */
  2261 #ifdef _PR_INET6
  2262     if (addr->raw.family == PR_AF_INET6)
  2264         md_af = AF_INET6;
  2265 #ifndef _PR_HAVE_SOCKADDR_LEN
  2266         addrcopy = *addr;
  2267         addrcopy.raw.family = md_af;
  2268         addrp = &addrcopy;
  2269 #endif
  2271 #endif
  2273     addrlen = PR_NETADDR_SIZE(addr);
  2274 #ifdef _PR_HAVE_SOCKADDR_LEN
  2275     addrcopy = *addr;
  2276     ((struct sockaddr*)&addrcopy)->sa_len = addrlen;
  2277     ((struct sockaddr*)&addrcopy)->sa_family = md_af;
  2278     addrp = &addrcopy;
  2279 #endif
  2280     rv = GETNAMEINFO((const struct sockaddr *)addrp, addrlen,
  2281         string, size, NULL, 0, NI_NUMERICHOST);
  2282     if (rv != 0)
  2284         PR_SetError(PR_INVALID_ARGUMENT_ERROR, rv);
  2285         return PR_FAILURE;
  2287     return PR_SUCCESS;
  2289 #endif  /* _PR_HAVE_GETADDRINFO */
  2291 #if !defined(_PR_HAVE_GETADDRINFO) || defined(_PR_INET6_PROBE)
  2292 static PRStatus pr_NetAddrToStringFB(
  2293     const PRNetAddr *addr, char *string, PRUint32 size)
  2295     if (PR_AF_INET6 == addr->raw.family)
  2297 #if defined(_PR_HAVE_INET_NTOP)
  2298         if (NULL == inet_ntop(AF_INET6, &addr->ipv6.ip, string, size))
  2299 #else
  2300         if (NULL == V6AddrToString(&addr->ipv6.ip, string, size))
  2301 #endif
  2303             /* the size of the result buffer is inadequate */
  2304             PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
  2305             return PR_FAILURE;
  2308     else
  2310         if (size < 16) goto failed;
  2311         if (AF_INET != addr->raw.family) goto failed;
  2312         else
  2314             unsigned char *byte = (unsigned char*)&addr->inet.ip;
  2315             PR_snprintf(string, size, "%u.%u.%u.%u",
  2316                 byte[0], byte[1], byte[2], byte[3]);
  2320     return PR_SUCCESS;
  2322 failed:
  2323     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  2324     return PR_FAILURE;
  2326 }  /* pr_NetAddrToStringFB */
  2327 #endif  /* !_PR_HAVE_GETADDRINFO || _PR_INET6_PROBE */
  2329 PR_IMPLEMENT(PRStatus) PR_NetAddrToString(
  2330     const PRNetAddr *addr, char *string, PRUint32 size)
  2332     if (!_pr_initialized) _PR_ImplicitInitialization();
  2334 #if !defined(_PR_HAVE_GETADDRINFO)
  2335     return pr_NetAddrToStringFB(addr, string, size);
  2336 #else
  2337 #if defined(_PR_INET6_PROBE)
  2338     if (!_pr_ipv6_is_present())
  2339         return pr_NetAddrToStringFB(addr, string, size);
  2340 #endif
  2341     return pr_NetAddrToStringGNI(addr, string, size);
  2342 #endif
  2343 }  /* PR_NetAddrToString */

mercurial