LCOV - code coverage report
Current view: top level - nsprpub/pr/src/misc - prnetdb.c (source / functions) Hit Total Coverage
Test: output.info Lines: 125 541 23.1 %
Date: 2017-07-14 16:53:18 Functions: 6 15 40.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13