tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

prnetdb.c (67981B)


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