LCOV - app.info - nsprpub/pr/src/misc/prnetdb.c

LCOV - code coverage report
| Current view: | directory - nsprpub/pr/src/misc - prnetdb.c (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 569 | 3 | 0.5 %
| Date: | 2012-04-07 | Functions: | 37 | 1 | 2.7 %

           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           18667 : 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           18667 :         _pr_query_ifs_lock = PR_NewLock();
         440                 : #endif
         441           18667 : }
         442                 :
         443               0 : 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               0 :     if (_pr_query_ifs_lock) {
         459               0 :         PR_DestroyLock(_pr_query_ifs_lock);
         460               0 :         _pr_query_ifs_lock = NULL;
         461                 :     }
         462                 : #endif
         463               0 : }
         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               0 : 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               0 :     if (AF_INET == addr->raw.family)
        1393               0 :         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               0 :     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               0 : PR_IMPLEMENT(PRStatus) PR_SetNetAddr(
        1462                 :     PRNetAddrValue val, PRUint16 af, PRUint16 port, PRNetAddr *addr)
        1463                 : {
        1464               0 :     PRStatus rv = PR_SUCCESS;
        1465               0 :     if (!_pr_initialized) _PR_ImplicitInitialization();
        1466                 :
        1467               0 :     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               0 :         if (val != PR_IpAddrNull) memset(addr, 0, sizeof(addr->inet));
        1492               0 :         addr->inet.family = af;
        1493               0 :         addr->inet.port = htons(port);
        1494               0 :         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               0 :             addr->inet.ip = htonl(INADDR_LOOPBACK);
        1503               0 :             break;
        1504                 :         default:
        1505               0 :             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
        1506               0 :             rv = PR_FAILURE;
        1507                 :         }
        1508                 :     }
        1509               0 :     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               0 : static int StringToV6Addr(const char *string, PRIPv6Addr *addr)
        1577                 : {
        1578               0 :     const unsigned char *s = (const unsigned char *)string;
        1579               0 :     int section = 0;        /* index of the current section (a 16-bit
        1580                 :                              * piece of the address */
        1581               0 :     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               0 :     if (*s == ':') {
        1589               0 :         if (s[1] != ':') return 0;
        1590               0 :         s += 2;
        1591               0 :         addr->pr_s6_addr16[0] = 0;
        1592               0 :         section = double_colon = 1;
        1593                 :     }
        1594                 :
        1595               0 :     while (*s) {
        1596               0 :         if (section == 8) return 0; /* too long */
        1597               0 :         if (*s == ':') {
        1598               0 :             if (double_colon != -1) return 0; /* two double colons */
        1599               0 :             addr->pr_s6_addr16[section++] = 0;
        1600               0 :             double_colon = section;
        1601               0 :             s++;
        1602               0 :             continue;
        1603                 :         }
        1604               0 :         for (len = val = 0; len < 4 && index_hex[*s] != XX; len++) {
        1605               0 :             val = (val << 4) + index_hex[*s++];
        1606                 :         }
        1607               0 :         if (*s == '.') {
        1608               0 :             if (len == 0) return 0; /* nothing between : and . */
        1609               0 :             break;
        1610                 :         }
        1611               0 :         if (*s == ':') {
        1612               0 :             s++;
        1613               0 :             if (!*s) return 0; /* cannot end with single colon */
        1614               0 :         } else if (*s) {
        1615               0 :             return 0; /* bad character */
        1616                 :         }
        1617               0 :         addr->pr_s6_addr16[section++] = htons((unsigned short)val);
        1618                 :     }
        1619                 :
        1620               0 :     if (*s == '.') {
        1621                 :         /* Have a trailing v4 format address */
        1622               0 :         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               0 :         if (val > 0x0255 || (val & 0xf0) > 0x90 || (val & 0xf) > 9) return 0;
        1630               0 :         val = (val >> 8) * 100 + ((val >> 4) & 0xf) * 10 + (val & 0xf);
        1631               0 :         addr->pr_s6_addr[2 * section] = val;
        1632                 :
        1633               0 :         s++;
        1634               0 :         val = index_hex[*s++];
        1635               0 :         if (val > 9) return 0;
        1636               0 :         while (*s >= '0' && *s <= '9') {
        1637               0 :             val = val * 10 + *s++ - '0';
        1638               0 :             if (val > 255) return 0;
        1639                 :         }
        1640               0 :         if (*s != '.') return 0; /* must have exactly 4 decimal numbers */
        1641               0 :         addr->pr_s6_addr[2 * section + 1] = val;
        1642               0 :         section++;
        1643                 :
        1644               0 :         s++;
        1645               0 :         val = index_hex[*s++];
        1646               0 :         if (val > 9) return 0;
        1647               0 :         while (*s >= '0' && *s <= '9') {
        1648               0 :             val = val * 10 + *s++ - '0';
        1649               0 :             if (val > 255) return 0;
        1650                 :         }
        1651               0 :         if (*s != '.') return 0; /* must have exactly 4 decimal numbers */
        1652               0 :         addr->pr_s6_addr[2 * section] = val;
        1653                 :
        1654               0 :         s++;
        1655               0 :         val = index_hex[*s++];
        1656               0 :         if (val > 9) return 0;
        1657               0 :         while (*s >= '0' && *s <= '9') {
        1658               0 :             val = val * 10 + *s++ - '0';
        1659               0 :             if (val > 255) return 0;
        1660                 :         }
        1661               0 :         if (*s) return 0; /* must have exactly 4 decimal numbers */
        1662               0 :         addr->pr_s6_addr[2 * section + 1] = val;
        1663               0 :         section++;
        1664                 :     }
        1665                 :
        1666               0 :     if (double_colon != -1) {
        1667                 :         /* Stretch the double colon */
        1668                 :         int tosection;
        1669               0 :         int ncopy = section - double_colon;
        1670               0 :         for (tosection = 7; ncopy--; tosection--) {
        1671               0 :             addr->pr_s6_addr16[tosection] =
        1672               0 :                 addr->pr_s6_addr16[double_colon + ncopy];
        1673                 :         }
        1674               0 :         while (tosection >= double_colon) {
        1675               0 :             addr->pr_s6_addr16[tosection--] = 0;
        1676                 :         }
        1677               0 :     } else if (section != 8) {
        1678               0 :         return 0; /* too short */
        1679                 :     }
        1680               0 :     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               0 : PR_IMPLEMENT(void) PR_ConvertIPv4AddrToIPv6(PRUint32 v4addr, PRIPv6Addr *v6addr)
        1796                 : {
        1797                 :     PRUint8 *dstp;
        1798               0 :     dstp = v6addr->pr_s6_addr;
        1799               0 :     memset(dstp, 0, 10);
        1800               0 :     memset(dstp + 10, 0xff, 2);
        1801               0 :     memcpy(dstp + 12,(char *) &v4addr, 4);
        1802               0 : }
        1803                 :
        1804               0 : PR_IMPLEMENT(PRUint16) PR_ntohs(PRUint16 n) { return ntohs(n); }
        1805               0 : PR_IMPLEMENT(PRUint32) PR_ntohl(PRUint32 n) { return ntohl(n); }
        1806               0 : PR_IMPLEMENT(PRUint16) PR_htons(PRUint16 n) { return htons(n); }
        1807               0 : 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               0 : PR_IMPLEMENT(PRAddrInfo *) PR_GetAddrInfoByName(const char  *hostname,
        2011                 :                                                 PRUint16     af,
        2012                 :                                                 PRIntn       flags)
        2013                 : {
        2014                 :     /* restrict input to supported values */
        2015               0 :     if ((af != PR_AF_INET && af != PR_AF_UNSPEC) ||
        2016               0 :         (flags & ~ PR_AI_NOCANONNAME) != PR_AI_ADDRCONFIG) {
        2017               0 :         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
        2018               0 :         return NULL;
        2019                 :     }
        2020                 :
        2021               0 :     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               0 :     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               0 :         memset(&hints, 0, sizeof(hints));
        2042               0 :         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               0 :         if ((flags & PR_AI_ADDRCONFIG) &&
        2061               0 :             strcmp(hostname, "localhost") != 0 &&
        2062               0 :             strcmp(hostname, "localhost.localdomain") != 0 &&
        2063               0 :             strcmp(hostname, "localhost6") != 0 &&
        2064               0 :             strcmp(hostname, "localhost6.localdomain6") != 0) {
        2065               0 :             hints.ai_flags |= AI_ADDRCONFIG;
        2066                 :         }
        2067                 : #endif
        2068               0 :         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               0 :         hints.ai_socktype = SOCK_STREAM;
        2078                 :
        2079               0 :         rv = GETADDRINFO(hostname, NULL, &hints, &res);
        2080                 : #ifdef AI_ADDRCONFIG
        2081               0 :         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               0 :         if (rv == 0)
        2087               0 :             return (PRAddrInfo *) res;
        2088                 :
        2089               0 :         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, rv);
        2090                 :     }
        2091               0 :     return NULL;
        2092                 : #endif
        2093                 : }
        2094                 :
        2095               0 : PR_IMPLEMENT(void) PR_FreeAddrInfo(PRAddrInfo *ai)
        2096                 : {
        2097                 : #if defined(_PR_HAVE_GETADDRINFO)
        2098                 : #if defined(_PR_INET6_PROBE)
        2099               0 :     if (!_pr_ipv6_is_present())
        2100               0 :         PR_Free((PRAddrInfoFB *) ai);
        2101                 :     else
        2102                 : #endif
        2103               0 :         FREEADDRINFO((PRADDRINFO *) ai);
        2104                 : #else
        2105                 :     PR_Free((PRAddrInfoFB *) ai);
        2106                 : #endif
        2107               0 : }
        2108                 :
        2109               0 : 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               0 :     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               0 :     if (iterPtr)
        2128               0 :         ai = ((PRADDRINFO *) iterPtr)->ai_next;
        2129                 :     else
        2130               0 :         ai = (PRADDRINFO *) base;
        2131                 :
        2132               0 :     while (ai && ai->ai_addrlen > sizeof(PRNetAddr))
        2133               0 :         ai = ai->ai_next;
        2134                 :
        2135               0 :     if (ai) {
        2136                 :         /* copy sockaddr to PRNetAddr */
        2137               0 :         memcpy(result, ai->ai_addr, ai->ai_addrlen);
        2138               0 :         result->raw.family = ai->ai_addr->sa_family;
        2139                 : #ifdef _PR_INET6
        2140               0 :         if (AF_INET6 == result->raw.family)
        2141               0 :             result->raw.family = PR_AF_INET6;
        2142                 : #endif
        2143               0 :         if (ai->ai_addrlen < sizeof(PRNetAddr))
        2144               0 :             memset(((char*)result)+ai->ai_addrlen, 0, sizeof(PRNetAddr) - ai->ai_addrlen);
        2145                 :
        2146               0 :         if (result->raw.family == PR_AF_INET)
        2147               0 :             result->inet.port = htons(port);
        2148                 :         else
        2149               0 :             result->ipv6.port = htons(port);
        2150                 :     }
        2151                 :
        2152               0 :     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               0 : static PRStatus pr_StringToNetAddrFB(const char *string, PRNetAddr *addr)
        2224                 : {
        2225                 :     PRIntn rv;
        2226                 :
        2227               0 :     rv = pr_inet_aton(string, &addr->inet.ip);
        2228               0 :     if (1 == rv)
        2229                 :     {
        2230               0 :         addr->raw.family = AF_INET;
        2231               0 :         return PR_SUCCESS;
        2232                 :     }
        2233                 :
        2234               0 :     PR_ASSERT(0 == rv);
        2235                 :     /* clean up after the failed call */
        2236               0 :     memset(&addr->inet.ip, 0, sizeof(addr->inet.ip));
        2237                 :
        2238               0 :     rv = StringToV6Addr(string, &addr->ipv6.ip);
        2239               0 :     if (1 == rv)
        2240                 :     {
        2241               0 :         addr->raw.family = PR_AF_INET6;
        2242               0 :         return PR_SUCCESS;
        2243                 :     }
        2244                 :
        2245               0 :     PR_ASSERT(0 == rv);
        2246               0 :     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
        2247               0 :     return PR_FAILURE;
        2248                 : }
        2249                 :
        2250               0 : PR_IMPLEMENT(PRStatus) PR_StringToNetAddr(const char *string, PRNetAddr *addr)
        2251                 : {
        2252               0 :     if (!_pr_initialized) _PR_ImplicitInitialization();
        2253                 :
        2254               0 :     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               0 :     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               0 :     if (!strchr(string, '%'))
        2274               0 :         return pr_StringToNetAddrFB(string, addr);
        2275                 :
        2276               0 :     return pr_StringToNetAddrGAI(string, addr);
        2277                 : #endif
        2278                 : }
        2279                 :
        2280                 : #if defined(_PR_HAVE_GETADDRINFO)
        2281               0 : static PRStatus pr_NetAddrToStringGNI(
        2282                 :     const PRNetAddr *addr, char *string, PRUint32 size)
        2283                 : {
        2284                 :     int addrlen;
        2285               0 :     const PRNetAddr *addrp = addr;
        2286                 : #if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
        2287               0 :     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               0 :     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               0 :     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               0 :     rv = GETNAMEINFO((const struct sockaddr *)addrp, addrlen,
        2312                 :         string, size, NULL, 0, NI_NUMERICHOST);
        2313               0 :     if (rv != 0)
        2314                 :     {
        2315               0 :         PR_SetError(PR_INVALID_ARGUMENT_ERROR, rv);
        2316               0 :         return PR_FAILURE;
        2317                 :     }
        2318               0 :     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               0 : PR_IMPLEMENT(PRStatus) PR_NetAddrToString(
        2361                 :     const PRNetAddr *addr, char *string, PRUint32 size)
        2362                 : {
        2363               0 :     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               0 :     if (!_pr_ipv6_is_present())
        2370               0 :         return pr_NetAddrToStringFB(addr, string, size);
        2371                 : #endif
        2372               0 :     return pr_NetAddrToStringGNI(addr, string, size);
        2373                 : #endif
        2374                 : }  /* PR_NetAddrToString */

Generated by: LCOV version 1.7