LCOV - code coverage report
Current view: directory - nsprpub/pr/src/misc - prnetdb.c (source / functions) Found Hit Coverage
Test: app.info Lines: 569 167 29.3 %
Date: 2012-06-02 Functions: 37 16 43.2 %

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

Generated by: LCOV version 1.7