Back to index

lightning-sunbird  0.9+nobinonly
prnetdb.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "primpl.h"
00039 
00040 #include <string.h>
00041 
00042 /*
00043  * On Unix, the error code for gethostbyname() and gethostbyaddr()
00044  * is returned in the global variable h_errno, instead of the usual
00045  * errno.
00046  */
00047 #if defined(XP_UNIX)
00048 #if defined(_PR_NEED_H_ERRNO)
00049 extern int h_errno;
00050 #endif
00051 #define _MD_GETHOST_ERRNO() h_errno
00052 #else
00053 #define _MD_GETHOST_ERRNO() _MD_ERRNO()
00054 #endif
00055 
00056 /*
00057  * The meaning of the macros related to gethostbyname, gethostbyaddr,
00058  * and gethostbyname2 is defined below.
00059  * - _PR_HAVE_THREADSAFE_GETHOST: the gethostbyXXX functions return
00060  *   the result in thread specific storage.  For example, AIX, HP-UX,
00061  *   and OSF1.
00062  * -  _PR_HAVE_GETHOST_R: have the gethostbyXXX_r functions. See next
00063  *   two macros.
00064  * - _PR_HAVE_GETHOST_R_INT: the gethostbyXXX_r functions return an
00065  *   int.  For example, Linux glibc.
00066  * - _PR_HAVE_GETHOST_R_POINTER: the gethostbyXXX_r functions return
00067  *   a struct hostent* pointer.  For example, Solaris and IRIX.
00068  */
00069 #if defined(_PR_NO_PREEMPT) || defined(_PR_HAVE_GETHOST_R) \
00070     || defined(_PR_HAVE_THREADSAFE_GETHOST)
00071 #define _PR_NO_DNS_LOCK
00072 #endif
00073 
00074 #if defined(_PR_NO_DNS_LOCK)
00075 #define LOCK_DNS()
00076 #define UNLOCK_DNS()
00077 #else
00078 PRLock *_pr_dnsLock = NULL;
00079 #define LOCK_DNS() PR_Lock(_pr_dnsLock)
00080 #define UNLOCK_DNS() PR_Unlock(_pr_dnsLock)
00081 #endif  /* defined(_PR_NO_DNS_LOCK) */
00082 
00083 /*
00084  * Some platforms have the reentrant getprotobyname_r() and
00085  * getprotobynumber_r().  However, they come in two flavors.
00086  * Some return a pointer to struct protoent, others return
00087  * an int.
00088  */
00089 #if defined(XP_BEOS) && defined(BONE_VERSION)
00090 #include <arpa/inet.h>  /* pick up define for inet_addr */
00091 #include <sys/socket.h>
00092 #define _PR_HAVE_GETPROTO_R
00093 #define _PR_HAVE_GETPROTO_R_POINTER
00094 #endif
00095 
00096 #if defined(SOLARIS) || (defined(BSDI) && defined(_REENTRANT)) \
00097        || (defined(LINUX) && defined(_REENTRANT) \
00098         && !(defined(__GLIBC__) && __GLIBC__ >= 2))
00099 #define _PR_HAVE_GETPROTO_R
00100 #define _PR_HAVE_GETPROTO_R_POINTER
00101 #endif
00102 
00103 #if defined(OSF1) \
00104         || defined(AIX4_3_PLUS) || (defined(AIX) && defined(_THREAD_SAFE)) \
00105        || (defined(HPUX10_10) && defined(_REENTRANT)) \
00106         || (defined(HPUX10_20) && defined(_REENTRANT))
00107 #define _PR_HAVE_GETPROTO_R
00108 #define _PR_HAVE_GETPROTO_R_INT
00109 #endif
00110 
00111 #if __FreeBSD_version >= 602000
00112 #define _PR_HAVE_GETPROTO_R
00113 #define _PR_HAVE_5_ARG_GETPROTO_R
00114 #endif
00115 
00116 #if (defined(LINUX) && defined(__GLIBC__) && __GLIBC__ >= 2)
00117 #define _PR_HAVE_GETPROTO_R
00118 #define _PR_HAVE_5_ARG_GETPROTO_R
00119 #endif
00120 
00121 #if !defined(_PR_HAVE_GETPROTO_R)
00122 PRLock* _getproto_lock = NULL;
00123 #endif
00124 
00125 #if defined(_PR_INET6_PROBE)
00126 PR_EXTERN(PRBool) _pr_ipv6_is_present;
00127 #endif
00128 
00129 #define _PR_IN6_IS_ADDR_UNSPECIFIED(a)                         \
00130                             (((a)->pr_s6_addr32[0] == 0) &&    \
00131                             ((a)->pr_s6_addr32[1] == 0) &&            \
00132                             ((a)->pr_s6_addr32[2] == 0) &&            \
00133                             ((a)->pr_s6_addr32[3] == 0))
00134  
00135 #define _PR_IN6_IS_ADDR_LOOPBACK(a)                                   \
00136                (((a)->pr_s6_addr32[0] == 0)      &&     \
00137                ((a)->pr_s6_addr32[1] == 0)              &&     \
00138                ((a)->pr_s6_addr32[2] == 0)              &&     \
00139                ((a)->pr_s6_addr[12] == 0)        &&     \
00140                ((a)->pr_s6_addr[13] == 0)        &&     \
00141                ((a)->pr_s6_addr[14] == 0)        &&     \
00142                ((a)->pr_s6_addr[15] == 0x1U))
00143  
00144 const PRIPv6Addr _pr_in6addr_any = {{{ 0, 0, 0, 0,
00145                                                                       0, 0, 0, 0,
00146                                                                       0, 0, 0, 0,
00147                                                                       0, 0, 0, 0 }}};
00148 
00149 const PRIPv6Addr _pr_in6addr_loopback = {{{ 0, 0, 0, 0,
00150                                                                              0, 0, 0, 0,
00151                                                                              0, 0, 0, 0,
00152                                                                              0, 0, 0, 0x1U }}};
00153 /*
00154  * The values at bytes 10 and 11 are compared using pointers to
00155  * 8-bit fields, and not 32-bit fields, to make the comparison work on
00156  * both big-endian and little-endian systems
00157  */
00158 
00159 #define _PR_IN6_IS_ADDR_V4MAPPED(a)                     \
00160               (((a)->pr_s6_addr32[0] == 0)       &&     \
00161               ((a)->pr_s6_addr32[1] == 0) &&     \
00162               ((a)->pr_s6_addr[8] == 0)          &&     \
00163               ((a)->pr_s6_addr[9] == 0)          &&     \
00164               ((a)->pr_s6_addr[10] == 0xff)      &&     \
00165               ((a)->pr_s6_addr[11] == 0xff))
00166 
00167 #define _PR_IN6_IS_ADDR_V4COMPAT(a)                     \
00168               (((a)->pr_s6_addr32[0] == 0) &&    \
00169               ((a)->pr_s6_addr32[1] == 0) &&            \
00170               ((a)->pr_s6_addr32[2] == 0))
00171 
00172 #define _PR_IN6_V4MAPPED_TO_IPADDR(a) ((a)->pr_s6_addr32[3])
00173 
00174 #if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
00175 
00176 /*
00177  * The _pr_QueryNetIfs() function finds out if the system has
00178  * IPv4 or IPv6 source addresses configured and sets _pr_have_inet_if
00179  * and _pr_have_inet6_if accordingly.
00180  *
00181  * We have an implementation using SIOCGIFCONF ioctl and a
00182  * default implementation that simply sets _pr_have_inet_if
00183  * and _pr_have_inet6_if to true.  A better implementation
00184  * would be to use the routing sockets (see Chapter 17 of
00185  * W. Richard Stevens' Unix Network Programming, Vol. 1, 2nd. Ed.)
00186  */
00187 
00188 static PRLock *_pr_query_ifs_lock = NULL;
00189 static PRBool _pr_have_inet_if = PR_FALSE;
00190 static PRBool _pr_have_inet6_if = PR_FALSE;
00191 
00192 #undef DEBUG_QUERY_IFS
00193 
00194 #if defined(AIX) \
00195     || (defined(DARWIN) && (!defined(HAVE_GETIFADDRS) \
00196         || (defined(XP_MACOSX) && (!defined(MAC_OS_X_VERSION_10_2) || \
00197         MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_2))))
00198 
00199 /*
00200  * Use SIOCGIFCONF ioctl on platforms that don't have routing
00201  * sockets.  Warning: whether SIOCGIFCONF ioctl returns AF_INET6
00202  * network interfaces is not portable.
00203  *
00204  * The _pr_QueryNetIfs() function is derived from the code in
00205  * src/lib/libc/net/getifaddrs.c in BSD Unix and the code in
00206  * Section 16.6 of W. Richard Stevens' Unix Network Programming,
00207  * Vol. 1, 2nd. Ed.
00208  */
00209 
00210 #include <sys/ioctl.h>
00211 #include <sys/socket.h>
00212 #include <netinet/in.h>
00213 #include <net/if.h>
00214 
00215 #ifdef DEBUG_QUERY_IFS
00216 static void
00217 _pr_PrintIfreq(struct ifreq *ifr)
00218 {
00219     PRNetAddr addr;
00220     struct sockaddr *sa;
00221     const char* family;
00222     char addrstr[64];
00223 
00224     sa = &ifr->ifr_addr;
00225     if (sa->sa_family == AF_INET) {
00226         struct sockaddr_in *sin = (struct sockaddr_in *)sa;
00227         family = "inet";
00228         memcpy(&addr.inet.ip, &sin->sin_addr, sizeof(sin->sin_addr));
00229     } else if (sa->sa_family == AF_INET6) {
00230         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
00231         family = "inet6";
00232         memcpy(&addr.ipv6.ip, &sin6->sin6_addr, sizeof(sin6->sin6_addr));
00233     } else {
00234         return;  /* skip if not AF_INET or AF_INET6 */
00235     }
00236     addr.raw.family = sa->sa_family;
00237     PR_NetAddrToString(&addr, addrstr, sizeof(addrstr));
00238     printf("%s: %s %s\n", ifr->ifr_name, family, addrstr);
00239 }
00240 #endif
00241 
00242 static void
00243 _pr_QueryNetIfs(void)
00244 {
00245     int sock;
00246     int rv;
00247     struct ifconf ifc;
00248     struct ifreq *ifr;
00249     struct ifreq *lifr;
00250     PRUint32 len, lastlen;
00251     char *buf;
00252 
00253     if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
00254         return;
00255     }
00256 
00257     /* Issue SIOCGIFCONF request in a loop. */
00258     lastlen = 0;
00259     len = 100 * sizeof(struct ifreq);  /* initial buffer size guess */
00260     for (;;) {
00261         buf = (char *)PR_Malloc(len);
00262         if (NULL == buf) {
00263             close(sock);
00264             return;
00265         }
00266         ifc.ifc_buf = buf;
00267         ifc.ifc_len = len;
00268         rv = ioctl(sock, SIOCGIFCONF, &ifc);
00269         if (rv < 0) {
00270             if (errno != EINVAL || lastlen != 0) {
00271                 close(sock);
00272                 PR_Free(buf);
00273                 return;
00274             }
00275         } else {
00276             if (ifc.ifc_len == lastlen)
00277                 break;  /* success, len has not changed */
00278             lastlen = ifc.ifc_len;
00279         }
00280         len += 10 * sizeof(struct ifreq);  /* increment */
00281         PR_Free(buf);
00282     }
00283     close(sock);
00284 
00285     ifr = ifc.ifc_req;
00286     lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
00287 
00288     while (ifr < lifr) {
00289         struct sockaddr *sa;
00290         int sa_len;
00291 
00292 #ifdef DEBUG_QUERY_IFS
00293         _pr_PrintIfreq(ifr);
00294 #endif
00295         sa = &ifr->ifr_addr;
00296         if (sa->sa_family == AF_INET) {
00297             struct sockaddr_in *sin = (struct sockaddr_in *) sa;
00298             if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) {
00299                 _pr_have_inet_if = PR_TRUE;
00300             } 
00301         } else if (sa->sa_family == AF_INET6) {
00302             struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
00303             if (!IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)
00304                     && !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
00305                 _pr_have_inet6_if = PR_TRUE;
00306             } 
00307         }
00308 
00309 #ifdef _PR_HAVE_SOCKADDR_LEN
00310         sa_len = PR_MAX(sa->sa_len, sizeof(struct sockaddr));
00311 #else
00312         switch (sa->sa_family) {
00313 #ifdef AF_LINK
00314         case AF_LINK:
00315             sa_len = sizeof(struct sockaddr_dl);
00316             break;
00317 #endif
00318         case AF_INET6:
00319             sa_len = sizeof(struct sockaddr_in6);
00320             break;
00321         default:
00322             sa_len = sizeof(struct sockaddr);
00323             break;
00324         }
00325 #endif
00326         ifr = (struct ifreq *)(((char *)sa) + sa_len);
00327     }
00328     PR_Free(buf);
00329 }
00330 
00331 #elif (defined(DARWIN) && defined(HAVE_GETIFADDRS)) || defined(FREEBSD) \
00332     || defined(NETBSD) || defined(OPENBSD)
00333 
00334 /*
00335  * Use the BSD getifaddrs function.
00336  */
00337 
00338 #include <sys/types.h>
00339 #include <sys/socket.h>
00340 #include <ifaddrs.h>
00341 #include <netinet/in.h>
00342 
00343 #ifdef DEBUG_QUERY_IFS
00344 static void
00345 _pr_PrintIfaddrs(struct ifaddrs *ifa)
00346 {
00347     struct sockaddr *sa;
00348     const char* family;
00349     void *addrp;
00350     char addrstr[64];
00351 
00352     sa = ifa->ifa_addr;
00353     if (sa->sa_family == AF_INET) {
00354         struct sockaddr_in *sin = (struct sockaddr_in *)sa;
00355         family = "inet";
00356         addrp = &sin->sin_addr;
00357     } else if (sa->sa_family == AF_INET6) {
00358         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
00359         family = "inet6";
00360         addrp = &sin6->sin6_addr;
00361     } else {
00362         return;  /* skip if not AF_INET or AF_INET6 */
00363     }
00364     inet_ntop(sa->sa_family, addrp, addrstr, sizeof(addrstr));
00365     printf("%s: %s %s\n", ifa->ifa_name, family, addrstr);
00366 }
00367 #endif
00368 
00369 static void
00370 _pr_QueryNetIfs(void)
00371 {
00372     struct ifaddrs *ifp;
00373     struct ifaddrs *ifa;
00374 
00375     if (getifaddrs(&ifp) == -1) {
00376         return;
00377     }
00378     for (ifa = ifp; ifa; ifa = ifa->ifa_next) {
00379         struct sockaddr *sa;
00380 
00381 #ifdef DEBUG_QUERY_IFS
00382         _pr_PrintIfaddrs(ifa);
00383 #endif
00384         sa = ifa->ifa_addr;
00385         if (sa->sa_family == AF_INET) {
00386             struct sockaddr_in *sin = (struct sockaddr_in *) sa;
00387             if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) {
00388                 _pr_have_inet_if = 1;
00389             } 
00390         } else if (sa->sa_family == AF_INET6) {
00391             struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
00392             if (!IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)
00393                     && !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
00394                 _pr_have_inet6_if = 1;
00395             } 
00396         }
00397     } 
00398     freeifaddrs(ifp);
00399 }
00400 
00401 #else  /* default */
00402 
00403 /*
00404  * Emulate the code in NSPR 4.2 or older.  PR_GetIPNodeByName behaves
00405  * as if the system had both IPv4 and IPv6 source addresses configured.
00406  */
00407 static void
00408 _pr_QueryNetIfs(void)
00409 {
00410     _pr_have_inet_if = PR_TRUE;
00411     _pr_have_inet6_if = PR_TRUE;
00412 }
00413 
00414 #endif
00415 
00416 #endif  /* _PR_INET6 && _PR_HAVE_GETHOSTBYNAME2 */
00417 
00418 void _PR_InitNet(void)
00419 {
00420 #if defined(XP_UNIX)
00421 #ifdef HAVE_NETCONFIG
00422        /*
00423         * This one-liner prevents the endless re-open's and re-read's of
00424         * /etc/netconfig on EACH and EVERY call to accept(), connect(), etc.
00425         */
00426         (void)setnetconfig();
00427 #endif
00428 #endif
00429 #if !defined(_PR_NO_DNS_LOCK)
00430        _pr_dnsLock = PR_NewLock();
00431 #endif
00432 #if !defined(_PR_HAVE_GETPROTO_R)
00433        _getproto_lock = PR_NewLock();
00434 #endif
00435 #if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
00436        _pr_query_ifs_lock = PR_NewLock();
00437 #endif
00438 }
00439 
00440 void _PR_CleanupNet(void)
00441 {
00442 #if !defined(_PR_NO_DNS_LOCK)
00443     if (_pr_dnsLock) {
00444         PR_DestroyLock(_pr_dnsLock);
00445         _pr_dnsLock = NULL;
00446     }
00447 #endif
00448 #if !defined(_PR_HAVE_GETPROTO_R)
00449     if (_getproto_lock) {
00450         PR_DestroyLock(_getproto_lock);
00451         _getproto_lock = NULL;
00452     }
00453 #endif
00454 #if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
00455     if (_pr_query_ifs_lock) {
00456         PR_DestroyLock(_pr_query_ifs_lock);
00457         _pr_query_ifs_lock = NULL;
00458     }
00459 #endif
00460 }
00461 
00462 /*
00463 ** Allocate space from the buffer, aligning it to "align" before doing
00464 ** the allocation. "align" must be a power of 2.
00465 */
00466 static char *Alloc(PRIntn amount, char **bufp, PRIntn *buflenp, PRIntn align)
00467 {
00468        char *buf = *bufp;
00469        PRIntn buflen = *buflenp;
00470 
00471        if (align && ((long)buf & (align - 1))) {
00472               PRIntn skip = align - ((ptrdiff_t)buf & (align - 1));
00473               if (buflen < skip) {
00474                      return 0;
00475               }
00476               buf += skip;
00477               buflen -= skip;
00478        }
00479        if (buflen < amount) {
00480               return 0;
00481        }
00482        *bufp = buf + amount;
00483        *buflenp = buflen - amount;
00484        return buf;
00485 }
00486 
00487 typedef enum _PRIPAddrConversion {
00488     _PRIPAddrNoConversion,
00489     _PRIPAddrIPv4Mapped,
00490     _PRIPAddrIPv4Compat
00491 } _PRIPAddrConversion;
00492 
00493 /*
00494 ** Convert an IPv4 address (v4) to an IPv4-mapped IPv6 address (v6).
00495 */
00496 static void MakeIPv4MappedAddr(const char *v4, char *v6)
00497 {
00498     memset(v6, 0, 10);
00499     memset(v6 + 10, 0xff, 2);
00500     memcpy(v6 + 12, v4, 4);
00501 }
00502 
00503 /*
00504 ** Convert an IPv4 address (v4) to an IPv4-compatible IPv6 address (v6).
00505 */
00506 static void MakeIPv4CompatAddr(const char *v4, char *v6)
00507 {
00508     memset(v6, 0, 12);
00509     memcpy(v6 + 12, v4, 4);
00510 }
00511 
00512 /*
00513 ** Copy a hostent, and all of the memory that it refers to into
00514 ** (hopefully) stacked buffers.
00515 */
00516 static PRStatus CopyHostent(
00517     struct hostent *from,
00518     char **buf,
00519     PRIntn *bufsize,
00520     _PRIPAddrConversion conversion,
00521     PRHostEnt *to)
00522 {
00523        PRIntn len, na;
00524        char **ap;
00525 
00526        if (conversion != _PRIPAddrNoConversion
00527                      && from->h_addrtype == AF_INET) {
00528               PR_ASSERT(from->h_length == 4);
00529               to->h_addrtype = PR_AF_INET6;
00530               to->h_length = 16;
00531        } else {
00532 #if defined(_PR_INET6) || defined(_PR_INET6_PROBE)
00533               if (AF_INET6 == from->h_addrtype)
00534                      to->h_addrtype = PR_AF_INET6;
00535               else
00536 #endif
00537                      to->h_addrtype = from->h_addrtype;
00538               to->h_length = from->h_length;
00539        }
00540 
00541        /* Copy the official name */
00542        if (!from->h_name) return PR_FAILURE;
00543        len = strlen(from->h_name) + 1;
00544        to->h_name = Alloc(len, buf, bufsize, 0);
00545        if (!to->h_name) return PR_FAILURE;
00546        memcpy(to->h_name, from->h_name, len);
00547 
00548        /* Count the aliases, then allocate storage for the pointers */
00549        if (!from->h_aliases) {
00550               na = 1;
00551        } else {
00552               for (na = 1, ap = from->h_aliases; *ap != 0; na++, ap++){;} /* nothing to execute */
00553        }
00554        to->h_aliases = (char**)Alloc(
00555            na * sizeof(char*), buf, bufsize, sizeof(char**));
00556        if (!to->h_aliases) return PR_FAILURE;
00557 
00558        /* Copy the aliases, one at a time */
00559        if (!from->h_aliases) {
00560               to->h_aliases[0] = 0;
00561        } else {
00562               for (na = 0, ap = from->h_aliases; *ap != 0; na++, ap++) {
00563                      len = strlen(*ap) + 1;
00564                      to->h_aliases[na] = Alloc(len, buf, bufsize, 0);
00565                      if (!to->h_aliases[na]) return PR_FAILURE;
00566                      memcpy(to->h_aliases[na], *ap, len);
00567               }
00568               to->h_aliases[na] = 0;
00569        }
00570 
00571        /* Count the addresses, then allocate storage for the pointers */
00572        for (na = 1, ap = from->h_addr_list; *ap != 0; na++, ap++){;} /* nothing to execute */
00573        to->h_addr_list = (char**)Alloc(
00574            na * sizeof(char*), buf, bufsize, sizeof(char**));
00575        if (!to->h_addr_list) return PR_FAILURE;
00576 
00577        /* Copy the addresses, one at a time */
00578        for (na = 0, ap = from->h_addr_list; *ap != 0; na++, ap++) {
00579               to->h_addr_list[na] = Alloc(to->h_length, buf, bufsize, 0);
00580               if (!to->h_addr_list[na]) return PR_FAILURE;
00581               if (conversion != _PRIPAddrNoConversion
00582                             && from->h_addrtype == AF_INET) {
00583                      if (conversion == _PRIPAddrIPv4Mapped) {
00584                             MakeIPv4MappedAddr(*ap, to->h_addr_list[na]);
00585                      } else {
00586                             PR_ASSERT(conversion == _PRIPAddrIPv4Compat);
00587                             MakeIPv4CompatAddr(*ap, to->h_addr_list[na]);
00588                      }
00589               } else {
00590                      memcpy(to->h_addr_list[na], *ap, to->h_length);
00591               }
00592        }
00593        to->h_addr_list[na] = 0;
00594        return PR_SUCCESS;
00595 }
00596 
00597 #if !defined(_PR_HAVE_GETPROTO_R)
00598 /*
00599 ** Copy a protoent, and all of the memory that it refers to into
00600 ** (hopefully) stacked buffers.
00601 */
00602 static PRStatus CopyProtoent(
00603     struct protoent *from, char *buf, PRIntn bufsize, PRProtoEnt *to)
00604 {
00605        PRIntn len, na;
00606        char **ap;
00607 
00608        /* Do the easy stuff */
00609        to->p_num = from->p_proto;
00610 
00611        /* Copy the official name */
00612        if (!from->p_name) return PR_FAILURE;
00613        len = strlen(from->p_name) + 1;
00614        to->p_name = Alloc(len, &buf, &bufsize, 0);
00615        if (!to->p_name) return PR_FAILURE;
00616        memcpy(to->p_name, from->p_name, len);
00617 
00618        /* Count the aliases, then allocate storage for the pointers */
00619        for (na = 1, ap = from->p_aliases; *ap != 0; na++, ap++){;} /* nothing to execute */
00620        to->p_aliases = (char**)Alloc(
00621            na * sizeof(char*), &buf, &bufsize, sizeof(char**));
00622        if (!to->p_aliases) return PR_FAILURE;
00623 
00624        /* Copy the aliases, one at a time */
00625        for (na = 0, ap = from->p_aliases; *ap != 0; na++, ap++) {
00626               len = strlen(*ap) + 1;
00627               to->p_aliases[na] = Alloc(len, &buf, &bufsize, 0);
00628               if (!to->p_aliases[na]) return PR_FAILURE;
00629               memcpy(to->p_aliases[na], *ap, len);
00630        }
00631        to->p_aliases[na] = 0;
00632 
00633        return PR_SUCCESS;
00634 }
00635 #endif /* !defined(_PR_HAVE_GETPROTO_R) */
00636 
00637 /*
00638  * #################################################################
00639  * NOTE: tmphe, tmpbuf, bufsize, h, and h_err are local variables
00640  * or arguments of PR_GetHostByName, PR_GetIPNodeByName, and
00641  * PR_GetHostByAddr.  DO NOT CHANGE THE NAMES OF THESE LOCAL 
00642  * VARIABLES OR ARGUMENTS.
00643  * #################################################################
00644  */
00645 #if defined(_PR_HAVE_GETHOST_R_INT)
00646 
00647 #define GETHOSTBYNAME(name) \
00648     (gethostbyname_r(name, &tmphe, tmpbuf, bufsize, &h, &h_err), h)
00649 #define GETHOSTBYNAME2(name, af) \
00650     (gethostbyname2_r(name, af, &tmphe, tmpbuf, bufsize, &h, &h_err), h)
00651 #define GETHOSTBYADDR(addr, addrlen, af) \
00652     (gethostbyaddr_r(addr, addrlen, af, \
00653     &tmphe, tmpbuf, bufsize, &h, &h_err), h)
00654 
00655 #elif defined(_PR_HAVE_GETHOST_R_POINTER)
00656 
00657 #define GETHOSTBYNAME(name) \
00658     gethostbyname_r(name, &tmphe, tmpbuf, bufsize, &h_err)
00659 #define GETHOSTBYNAME2(name, af) \
00660     gethostbyname2_r(name, af, &tmphe, tmpbuf, bufsize, &h_err)
00661 #define GETHOSTBYADDR(addr, addrlen, af) \
00662     gethostbyaddr_r(addr, addrlen, af, &tmphe, tmpbuf, bufsize, &h_err)
00663 
00664 #else
00665 
00666 #define GETHOSTBYNAME(name) gethostbyname(name)
00667 #define GETHOSTBYNAME2(name, af) gethostbyname2(name, af)
00668 #define GETHOSTBYADDR(addr, addrlen, af) gethostbyaddr(addr, addrlen, af)
00669 
00670 #endif  /* definition of GETHOSTBYXXX */
00671 
00672 PR_IMPLEMENT(PRStatus) PR_GetHostByName(
00673     const char *name, char *buf, PRIntn bufsize, PRHostEnt *hp)
00674 {
00675        struct hostent *h;
00676        PRStatus rv = PR_FAILURE;
00677 #if defined(_PR_HAVE_GETHOST_R)
00678     char localbuf[PR_NETDB_BUF_SIZE];
00679     char *tmpbuf;
00680     struct hostent tmphe;
00681     int h_err;
00682 #endif
00683 
00684     if (!_pr_initialized) _PR_ImplicitInitialization();
00685 
00686 #if defined(_PR_HAVE_GETHOST_R)
00687     tmpbuf = localbuf;
00688     if (bufsize > sizeof(localbuf))
00689     {
00690         tmpbuf = (char *)PR_Malloc(bufsize);
00691         if (NULL == tmpbuf)
00692         {
00693             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00694             return rv;
00695         }
00696     }
00697 #endif
00698 
00699        LOCK_DNS();
00700 
00701 #ifdef XP_OS2_VACPP
00702        h = GETHOSTBYNAME((char *)name);
00703 #else
00704        h = GETHOSTBYNAME(name);
00705 #endif
00706     
00707        if (NULL == h)
00708        {
00709            PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
00710        }
00711        else
00712        {
00713               _PRIPAddrConversion conversion = _PRIPAddrNoConversion;
00714               rv = CopyHostent(h, &buf, &bufsize, conversion, hp);
00715               if (PR_SUCCESS != rv)
00716                   PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
00717        }
00718        UNLOCK_DNS();
00719 #if defined(_PR_HAVE_GETHOST_R)
00720     if (tmpbuf != localbuf)
00721         PR_Free(tmpbuf);
00722 #endif
00723        return rv;
00724 }
00725 
00726 #if !defined(_PR_INET6) && \
00727         defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME)
00728 typedef struct hostent  * (*_pr_getipnodebyname_t)(const char *, int,
00729                                                                       int, int *);
00730 typedef struct hostent  * (*_pr_getipnodebyaddr_t)(const void *, size_t,
00731                                                                                            int, int *);
00732 typedef void (*_pr_freehostent_t)(struct hostent *);
00733 static void * _pr_getipnodebyname_fp;
00734 static void * _pr_getipnodebyaddr_fp;
00735 static void * _pr_freehostent_fp;
00736 
00737 /*
00738  * Look up the addresses of getipnodebyname, getipnodebyaddr,
00739  * and freehostent.
00740  */
00741 PRStatus
00742 _pr_find_getipnodebyname(void)
00743 {
00744     PRLibrary *lib;  
00745     PRStatus rv;
00746 #if defined(VMS)
00747 #define GETIPNODEBYNAME getenv("GETIPNODEBYNAME")
00748 #define GETIPNODEBYADDR getenv("GETIPNODEBYADDR")
00749 #define FREEHOSTENT     getenv("FREEHOSTENT")
00750 #else
00751 #define GETIPNODEBYNAME "getipnodebyname"
00752 #define GETIPNODEBYADDR "getipnodebyaddr"
00753 #define FREEHOSTENT     "freehostent"
00754 #endif
00755     _pr_getipnodebyname_fp = PR_FindSymbolAndLibrary(GETIPNODEBYNAME, &lib);
00756     if (NULL != _pr_getipnodebyname_fp) {
00757         _pr_freehostent_fp = PR_FindSymbol(lib, FREEHOSTENT);
00758         if (NULL != _pr_freehostent_fp) {
00759             _pr_getipnodebyaddr_fp = PR_FindSymbol(lib, GETIPNODEBYADDR);
00760             if (NULL != _pr_getipnodebyaddr_fp)
00761                 rv = PR_SUCCESS;
00762             else
00763                 rv = PR_FAILURE;
00764         } else
00765             rv = PR_FAILURE;
00766         (void)PR_UnloadLibrary(lib);
00767     } else
00768         rv = PR_FAILURE;
00769     return rv;
00770 }
00771 #endif
00772 
00773 #if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
00774 /*
00775 ** Append the V4 addresses to the end of the list
00776 */
00777 static PRStatus AppendV4AddrsToHostent(
00778     struct hostent *from,
00779     char **buf,
00780     PRIntn *bufsize,
00781     PRHostEnt *to)
00782 {
00783     PRIntn na, na_old;
00784     char **ap;
00785     char **new_addr_list;
00786                      
00787     /* Count the addresses, then grow storage for the pointers */
00788     for (na_old = 0, ap = to->h_addr_list; *ap != 0; na_old++, ap++)
00789         {;} /* nothing to execute */
00790     for (na = na_old + 1, ap = from->h_addr_list; *ap != 0; na++, ap++)
00791         {;} /* nothing to execute */
00792     new_addr_list = (char**)Alloc(
00793         na * sizeof(char*), buf, bufsize, sizeof(char**));
00794     if (!new_addr_list) return PR_FAILURE;
00795 
00796     /* Copy the V6 addresses, one at a time */
00797     for (na = 0, ap = to->h_addr_list; *ap != 0; na++, ap++) {
00798         new_addr_list[na] = to->h_addr_list[na];
00799     }
00800     to->h_addr_list = new_addr_list;
00801 
00802     /* Copy the V4 addresses, one at a time */
00803     for (ap = from->h_addr_list; *ap != 0; na++, ap++) {
00804         to->h_addr_list[na] = Alloc(to->h_length, buf, bufsize, 0);
00805         if (!to->h_addr_list[na]) return PR_FAILURE;
00806         MakeIPv4MappedAddr(*ap, to->h_addr_list[na]);
00807     }
00808     to->h_addr_list[na] = 0;
00809     return PR_SUCCESS;
00810 }
00811 #endif
00812 
00813 PR_IMPLEMENT(PRStatus) PR_GetIPNodeByName(
00814     const char *name, PRUint16 af, PRIntn flags,
00815     char *buf, PRIntn bufsize, PRHostEnt *hp)
00816 {
00817        struct hostent *h = 0;
00818        PRStatus rv = PR_FAILURE;
00819 #if defined(_PR_HAVE_GETHOST_R)
00820     char localbuf[PR_NETDB_BUF_SIZE];
00821     char *tmpbuf;
00822     struct hostent tmphe;
00823     int h_err;
00824 #endif
00825 #if defined(_PR_HAVE_GETIPNODEBYNAME)
00826        PRUint16 md_af = af;
00827        int error_num;
00828        int tmp_flags = 0;
00829 #endif
00830 #if defined(_PR_HAVE_GETHOSTBYNAME2)
00831     PRBool did_af_inet = PR_FALSE;
00832 #endif
00833 
00834     if (!_pr_initialized) _PR_ImplicitInitialization();
00835 
00836     if (af != PR_AF_INET && af != PR_AF_INET6) {
00837         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
00838         return PR_FAILURE;
00839     }
00840 
00841 #if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
00842     PR_Lock(_pr_query_ifs_lock);
00843     /*
00844      * Keep querying the presence of IPv4 and IPv6 interfaces until
00845      * at least one is up.  This allows us to detect the local
00846      * machine going from offline to online.
00847      */
00848     if (!_pr_have_inet_if && !_pr_have_inet6_if) {
00849        _pr_QueryNetIfs();
00850 #ifdef DEBUG_QUERY_IFS
00851        if (_pr_have_inet_if)
00852               printf("Have IPv4 source address\n");
00853        if (_pr_have_inet6_if)
00854               printf("Have IPv6 source address\n");
00855 #endif
00856     }
00857     PR_Unlock(_pr_query_ifs_lock);
00858 #endif
00859 
00860 #if defined(_PR_HAVE_GETIPNODEBYNAME)
00861        if (flags & PR_AI_V4MAPPED)
00862               tmp_flags |= AI_V4MAPPED;
00863        if (flags & PR_AI_ADDRCONFIG)
00864               tmp_flags |= AI_ADDRCONFIG;
00865        if (flags & PR_AI_ALL)
00866               tmp_flags |= AI_ALL;
00867     if (af == PR_AF_INET6)
00868        md_af = AF_INET6;
00869        else
00870        md_af = af;
00871 #endif
00872 
00873 #if defined(_PR_HAVE_GETHOST_R)
00874     tmpbuf = localbuf;
00875     if (bufsize > sizeof(localbuf))
00876     {
00877         tmpbuf = (char *)PR_Malloc(bufsize);
00878         if (NULL == tmpbuf)
00879         {
00880             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00881             return rv;
00882         }
00883     }
00884 #endif
00885 
00886     /* Do not need to lock the DNS lock if getipnodebyname() is called */
00887 #ifdef _PR_INET6
00888 #ifdef _PR_HAVE_GETHOSTBYNAME2
00889     LOCK_DNS();
00890     if (af == PR_AF_INET6)
00891     {
00892         if ((flags & PR_AI_ADDRCONFIG) == 0 || _pr_have_inet6_if)
00893         {
00894 #ifdef _PR_INET6_PROBE
00895           if (_pr_ipv6_is_present == PR_TRUE)
00896 #endif
00897             h = GETHOSTBYNAME2(name, AF_INET6); 
00898         }
00899         if ((NULL == h) && (flags & PR_AI_V4MAPPED)
00900         && ((flags & PR_AI_ADDRCONFIG) == 0 || _pr_have_inet_if))
00901         {
00902             did_af_inet = PR_TRUE;
00903             h = GETHOSTBYNAME2(name, AF_INET);
00904         }
00905     }
00906     else
00907     {
00908         if ((flags & PR_AI_ADDRCONFIG) == 0 || _pr_have_inet_if)
00909         {
00910             did_af_inet = PR_TRUE;
00911             h = GETHOSTBYNAME2(name, af);
00912         }
00913     }
00914 #elif defined(_PR_HAVE_GETIPNODEBYNAME)
00915     h = getipnodebyname(name, md_af, tmp_flags, &error_num);
00916 #else
00917 #error "Unknown name-to-address translation function"
00918 #endif /* _PR_HAVE_GETHOSTBYNAME2 */
00919 #elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME)
00920     if (_pr_ipv6_is_present == PR_TRUE)
00921     {
00922 #ifdef PR_GETIPNODE_NOT_THREADSAFE
00923         LOCK_DNS();
00924 #endif
00925        h = (*((_pr_getipnodebyname_t)_pr_getipnodebyname_fp))(name, md_af, tmp_flags, &error_num);
00926     }
00927     else
00928     {
00929         LOCK_DNS();
00930        h = GETHOSTBYNAME(name);
00931     }
00932 #else /* _PR_INET6 */
00933     LOCK_DNS();
00934 #ifdef XP_OS2_VACPP
00935     h = GETHOSTBYNAME((char *)name);
00936 #else
00937     h = GETHOSTBYNAME(name);
00938 #endif
00939 #endif /* _PR_INET6 */
00940     
00941        if (NULL == h)
00942        {
00943 #if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
00944            PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num);
00945 #elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME)
00946        if (_pr_ipv6_is_present == PR_TRUE)
00947               PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num);
00948               else
00949               PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
00950 #else
00951            PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
00952 #endif
00953        }
00954        else
00955        {
00956               _PRIPAddrConversion conversion = _PRIPAddrNoConversion;
00957 
00958               if (af == PR_AF_INET6) conversion = _PRIPAddrIPv4Mapped;
00959               rv = CopyHostent(h, &buf, &bufsize, conversion, hp);
00960               if (PR_SUCCESS != rv)
00961                   PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
00962 #if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
00963               freehostent(h);
00964 #elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME)
00965        if (_pr_ipv6_is_present == PR_TRUE)
00966                      (*((_pr_freehostent_t)_pr_freehostent_fp))(h);
00967 #endif
00968 #if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
00969               if ((PR_SUCCESS == rv) && (flags & PR_AI_V4MAPPED)
00970                             && ((flags & PR_AI_ALL)
00971                             || ((flags & PR_AI_ADDRCONFIG) && _pr_have_inet_if))
00972                             && !did_af_inet && (h = GETHOSTBYNAME2(name, AF_INET)) != 0) {
00973                      rv = AppendV4AddrsToHostent(h, &buf, &bufsize, hp);
00974                      if (PR_SUCCESS != rv)
00975                             PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
00976               }
00977 #endif
00978        }
00979 
00980     /* Must match the convoluted logic above for LOCK_DNS() */
00981 #ifdef _PR_INET6
00982 #ifdef _PR_HAVE_GETHOSTBYNAME2
00983     UNLOCK_DNS();
00984 #endif /* _PR_HAVE_GETHOSTBYNAME2 */
00985 #elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME)
00986 #ifdef PR_GETIPNODE_NOT_THREADSAFE
00987     UNLOCK_DNS();
00988 #else
00989     if (_pr_ipv6_is_present == PR_FALSE)
00990         UNLOCK_DNS();
00991 #endif
00992 #else /* _PR_INET6 */
00993     UNLOCK_DNS();
00994 #endif /* _PR_INET6 */
00995 
00996 #if defined(_PR_HAVE_GETHOST_R)
00997     if (tmpbuf != localbuf)
00998         PR_Free(tmpbuf);
00999 #endif
01000 
01001        return rv;
01002 }
01003 
01004 PR_IMPLEMENT(PRStatus) PR_GetHostByAddr(
01005     const PRNetAddr *hostaddr, char *buf, PRIntn bufsize, PRHostEnt *hostentry)
01006 {
01007        struct hostent *h;
01008        PRStatus rv = PR_FAILURE;
01009        const void *addr;
01010        PRUint32 tmp_ip;
01011        int addrlen;
01012        PRInt32 af;
01013 #if defined(_PR_HAVE_GETHOST_R)
01014     char localbuf[PR_NETDB_BUF_SIZE];
01015     char *tmpbuf;
01016     struct hostent tmphe;
01017     int h_err;
01018 #endif
01019 #if defined(_PR_HAVE_GETIPNODEBYADDR)
01020        int error_num;
01021 #endif
01022 
01023     if (!_pr_initialized) _PR_ImplicitInitialization();
01024 
01025        if (hostaddr->raw.family == PR_AF_INET6)
01026        {
01027 #if defined(_PR_INET6_PROBE)
01028               if (_pr_ipv6_is_present == PR_TRUE)
01029                      af = AF_INET6;
01030               else
01031                      af = AF_INET;
01032 #elif defined(_PR_INET6)
01033               af = AF_INET6;
01034 #else
01035               af = AF_INET;
01036 #endif
01037 #if defined(_PR_GHBA_DISALLOW_V4MAPPED)
01038               if (_PR_IN6_IS_ADDR_V4MAPPED(&hostaddr->ipv6.ip))
01039                      af = AF_INET;
01040 #endif
01041        }
01042        else
01043        {
01044               PR_ASSERT(hostaddr->raw.family == AF_INET);
01045               af = AF_INET;
01046        }
01047        if (hostaddr->raw.family == PR_AF_INET6) {
01048 #if defined(_PR_INET6) || defined(_PR_INET6_PROBE)
01049               if (af == AF_INET6) {
01050                      addr = &hostaddr->ipv6.ip;
01051                      addrlen = sizeof(hostaddr->ipv6.ip);
01052               }
01053               else
01054 #endif
01055               {
01056                      PR_ASSERT(af == AF_INET);
01057                      if (!_PR_IN6_IS_ADDR_V4MAPPED(&hostaddr->ipv6.ip)) {
01058                             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
01059                             return rv;
01060                      }
01061                      tmp_ip = _PR_IN6_V4MAPPED_TO_IPADDR((PRIPv6Addr *)
01062                                                                                     &hostaddr->ipv6.ip);
01063                      addr = &tmp_ip;
01064                      addrlen = sizeof(tmp_ip);
01065               }
01066        } else {
01067               PR_ASSERT(hostaddr->raw.family == AF_INET);
01068               PR_ASSERT(af == AF_INET);
01069               addr = &hostaddr->inet.ip;
01070               addrlen = sizeof(hostaddr->inet.ip);
01071        }
01072 
01073 #if defined(_PR_HAVE_GETHOST_R)
01074     tmpbuf = localbuf;
01075     if (bufsize > sizeof(localbuf))
01076     {
01077         tmpbuf = (char *)PR_Malloc(bufsize);
01078         if (NULL == tmpbuf)
01079         {
01080             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
01081             return rv;
01082         }
01083     }
01084 #endif
01085 
01086     /* Do not need to lock the DNS lock if getipnodebyaddr() is called */
01087 #if defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6)
01088        h = getipnodebyaddr(addr, addrlen, af, &error_num);
01089 #elif defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6_PROBE)
01090     if (_pr_ipv6_is_present == PR_TRUE)
01091     {
01092 #ifdef PR_GETIPNODE_NOT_THREADSAFE
01093         LOCK_DNS();
01094 #endif
01095        h = (*((_pr_getipnodebyaddr_t)_pr_getipnodebyaddr_fp))(addr, addrlen,
01096                             af, &error_num);
01097     }
01098        else
01099     {
01100         LOCK_DNS();
01101               h = GETHOSTBYADDR(addr, addrlen, af);
01102     }
01103 #else  /* _PR_HAVE_GETIPNODEBYADDR */
01104     LOCK_DNS();
01105 #ifdef XP_OS2_VACPP
01106        h = GETHOSTBYADDR((char *)addr, addrlen, af);
01107 #else
01108        h = GETHOSTBYADDR(addr, addrlen, af);
01109 #endif
01110 #endif /* _PR_HAVE_GETIPNODEBYADDR */
01111        if (NULL == h)
01112        {
01113 #if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR)
01114               PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num);
01115 #elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYADDR)
01116        if (_pr_ipv6_is_present == PR_TRUE)
01117               PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num);
01118               else
01119               PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
01120 #else
01121               PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
01122 #endif
01123        }
01124        else
01125        {
01126               _PRIPAddrConversion conversion = _PRIPAddrNoConversion;
01127               if (hostaddr->raw.family == PR_AF_INET6) {
01128                      if (af == AF_INET) {
01129                             if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr*)
01130                                                                                     &hostaddr->ipv6.ip)) {
01131                                    conversion = _PRIPAddrIPv4Mapped;
01132                             } else if (_PR_IN6_IS_ADDR_V4COMPAT((PRIPv6Addr *)
01133                                                                                            &hostaddr->ipv6.ip)) {
01134                                    conversion = _PRIPAddrIPv4Compat;
01135                             }
01136                      }
01137               }
01138               rv = CopyHostent(h, &buf, &bufsize, conversion, hostentry);
01139               if (PR_SUCCESS != rv) {
01140                   PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
01141               }
01142 #if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR)
01143               freehostent(h);
01144 #elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYADDR)
01145        if (_pr_ipv6_is_present == PR_TRUE)
01146                      (*((_pr_freehostent_t)_pr_freehostent_fp))(h);
01147 #endif
01148        }
01149 
01150     /* Must match the convoluted logic above for LOCK_DNS() */
01151 #if defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6)
01152 #elif defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6_PROBE)
01153 #ifdef PR_GETIPNODE_NOT_THREADSAFE
01154     UNLOCK_DNS();
01155 #else
01156     if (_pr_ipv6_is_present == PR_FALSE)
01157         UNLOCK_DNS();
01158 #endif
01159 #else  /* _PR_HAVE_GETIPNODEBYADDR */
01160     UNLOCK_DNS();
01161 #endif /* _PR_HAVE_GETIPNODEBYADDR */
01162 
01163 #if defined(_PR_HAVE_GETHOST_R)
01164     if (tmpbuf != localbuf)
01165         PR_Free(tmpbuf);
01166 #endif
01167 
01168        return rv;
01169 }
01170 
01171 /******************************************************************************/
01172 /*
01173  * Some systems define a reentrant version of getprotobyname(). Too bad
01174  * the signature isn't always the same. But hey, they tried. If there
01175  * is such a definition, use it. Otherwise, grab a lock and do it here.
01176  */
01177 /******************************************************************************/
01178 
01179 #if !defined(_PR_HAVE_GETPROTO_R)
01180 /*
01181  * This may seem like a silly thing to do, but the compiler SHOULD
01182  * complain if getprotobyname_r() is implemented on some system and
01183  * we're not using it. For sure these signatures are different than
01184  * any usable implementation.
01185  */
01186 
01187 static struct protoent *getprotobyname_r(const char* name)
01188 {
01189 #ifdef XP_OS2_VACPP
01190        return getprotobyname((char *)name);
01191 #else
01192        return getprotobyname(name);
01193 #endif
01194 } /* getprotobyname_r */
01195 
01196 static struct protoent *getprotobynumber_r(PRInt32 number)
01197 {
01198        return getprotobynumber(number);
01199 } /* getprotobynumber_r */
01200 
01201 #endif /* !defined(_PR_HAVE_GETPROTO_R) */
01202 
01203 PR_IMPLEMENT(PRStatus) PR_GetProtoByName(
01204     const char* name, char* buffer, PRInt32 buflen, PRProtoEnt* result)
01205 {
01206        PRStatus rv = PR_SUCCESS;
01207 #if defined(_PR_HAVE_GETPROTO_R)
01208        struct protoent* res = (struct protoent*)result;
01209 #endif
01210 
01211     if (!_pr_initialized) _PR_ImplicitInitialization();
01212 
01213 #if defined(_PR_HAVE_GETPROTO_R_INT)
01214     {
01215         /*
01216         ** The protoent_data has a pointer as the first field.
01217         ** That implies the buffer better be aligned, and char*
01218         ** doesn't promise much.
01219         */
01220         PRUptrdiff aligned = (PRUptrdiff)buffer;
01221         if (0 != (aligned & (sizeof(struct protoent_data*) - 1)))
01222         {
01223             aligned += sizeof(struct protoent_data*) - 1;
01224             aligned &= ~(sizeof(struct protoent_data*) - 1);
01225             buflen -= (aligned - (PRUptrdiff)buffer);
01226             buffer = (char*)aligned;
01227         }
01228     }
01229 #endif  /* defined(_PR_HAVE_GETPROTO_R_INT) */
01230 
01231     if (PR_NETDB_BUF_SIZE > buflen)
01232     {
01233         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
01234         return PR_FAILURE;
01235     }
01236 
01237 #if defined(_PR_HAVE_GETPROTO_R_POINTER)
01238     if (NULL == getprotobyname_r(name, res, buffer, buflen))
01239     {
01240         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
01241         return PR_FAILURE;
01242     }
01243 #elif defined(_PR_HAVE_GETPROTO_R_INT)
01244     /*
01245     ** The buffer needs to be zero'd, and it should be
01246     ** at least the size of a struct protoent_data.
01247     */
01248     memset(buffer, 0, buflen);
01249        if (-1 == getprotobyname_r(name, res, (struct protoent_data*)buffer))
01250     {
01251         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
01252         return PR_FAILURE;
01253     }
01254 #elif defined(_PR_HAVE_5_ARG_GETPROTO_R)
01255     /* The 5th argument for getprotobyname_r() cannot be NULL */
01256     if (-1 == getprotobyname_r(name, res, buffer, buflen, &res))
01257     {
01258         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
01259         return PR_FAILURE;
01260     }
01261 #else  /* do it the hard way */
01262        {
01263               struct protoent *staticBuf;
01264               PR_Lock(_getproto_lock);
01265               staticBuf = getprotobyname_r(name);
01266               if (NULL == staticBuf)
01267               {
01268                   rv = PR_FAILURE;
01269                   PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
01270         }
01271               else
01272               {
01273                      rv = CopyProtoent(staticBuf, buffer, buflen, result);
01274                      if (PR_FAILURE == rv)
01275                          PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
01276         }
01277               PR_Unlock(_getproto_lock);
01278        }
01279 #endif  /* all that */
01280     return rv;
01281 }
01282 
01283 PR_IMPLEMENT(PRStatus) PR_GetProtoByNumber(
01284     PRInt32 number, char* buffer, PRInt32 buflen, PRProtoEnt* result)
01285 {
01286        PRStatus rv = PR_SUCCESS;
01287 #if defined(_PR_HAVE_GETPROTO_R)
01288        struct protoent* res = (struct protoent*)result;
01289 #endif
01290 
01291     if (!_pr_initialized) _PR_ImplicitInitialization();
01292 
01293 #if defined(_PR_HAVE_GETPROTO_R_INT)
01294     {
01295         /*
01296         ** The protoent_data has a pointer as the first field.
01297         ** That implies the buffer better be aligned, and char*
01298         ** doesn't promise much.
01299         */
01300         PRUptrdiff aligned = (PRUptrdiff)buffer;
01301         if (0 != (aligned & (sizeof(struct protoent_data*) - 1)))
01302         {
01303             aligned += sizeof(struct protoent_data*) - 1;
01304             aligned &= ~(sizeof(struct protoent_data*) - 1);
01305             buflen -= (aligned - (PRUptrdiff)buffer);
01306             buffer = (char*)aligned;
01307         }
01308     }
01309 #endif /* defined(_PR_HAVE_GETPROTO_R_INT) */
01310 
01311     if (PR_NETDB_BUF_SIZE > buflen)
01312     {
01313         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
01314         return PR_FAILURE;
01315     }
01316 
01317 #if defined(_PR_HAVE_GETPROTO_R_POINTER)
01318     if (NULL == getprotobynumber_r(number, res, buffer, buflen))
01319     {
01320         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
01321         return PR_FAILURE;
01322     }
01323 
01324 #elif defined(_PR_HAVE_GETPROTO_R_INT)
01325     /*
01326     ** The buffer needs to be zero'd for these OS's.
01327     */
01328     memset(buffer, 0, buflen);
01329        if (-1 == getprotobynumber_r(number, res, (struct protoent_data*)buffer))
01330     {
01331         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
01332         return PR_FAILURE;
01333     }
01334 #elif defined(_PR_HAVE_5_ARG_GETPROTO_R)
01335     /* The 5th argument for getprotobynumber_r() cannot be NULL */
01336     if (-1 == getprotobynumber_r(number, res, buffer, buflen, &res))
01337     {
01338         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
01339         return PR_FAILURE;
01340     }
01341 #else  /* do it the hard way */
01342        {
01343               struct protoent *staticBuf;
01344               PR_Lock(_getproto_lock);
01345               staticBuf = getprotobynumber_r(number);
01346               if (NULL == staticBuf)
01347               {
01348                   rv = PR_FAILURE;
01349                   PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
01350         }
01351               else
01352               {
01353                      rv = CopyProtoent(staticBuf, buffer, buflen, result);
01354                      if (PR_FAILURE == rv)
01355                          PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
01356         }
01357               PR_Unlock(_getproto_lock);
01358        }
01359 #endif  /* all that crap */
01360     return rv;
01361 
01362 }
01363 
01364 PRUintn _PR_NetAddrSize(const PRNetAddr* addr)
01365 {
01366     PRUintn addrsize;
01367 
01368     /*
01369      * RFC 2553 added a new field (sin6_scope_id) to
01370      * struct sockaddr_in6.  PRNetAddr's ipv6 member has a
01371      * scope_id field to match the new field.  In order to
01372      * work with older implementations supporting RFC 2133,
01373      * we take the size of struct sockaddr_in6 instead of
01374      * addr->ipv6.
01375      */
01376     if (AF_INET == addr->raw.family)
01377         addrsize = sizeof(addr->inet);
01378     else if (PR_AF_INET6 == addr->raw.family)
01379 #if defined(_PR_INET6)
01380         addrsize = sizeof(struct sockaddr_in6);
01381 #else
01382         addrsize = sizeof(addr->ipv6);
01383 #endif
01384 #if defined(XP_UNIX) || defined(XP_OS2_EMX)
01385     else if (AF_UNIX == addr->raw.family)
01386         addrsize = sizeof(addr->local);
01387 #endif
01388     else addrsize = 0;
01389 
01390     return addrsize;
01391 }  /* _PR_NetAddrSize */
01392 
01393 PR_IMPLEMENT(PRIntn) PR_EnumerateHostEnt(
01394     PRIntn enumIndex, const PRHostEnt *hostEnt, PRUint16 port, PRNetAddr *address)
01395 {
01396     void *addr = hostEnt->h_addr_list[enumIndex++];
01397     memset(address, 0, sizeof(PRNetAddr));
01398     if (NULL == addr) enumIndex = 0;
01399     else
01400     {
01401         address->raw.family = hostEnt->h_addrtype;
01402         if (PR_AF_INET6 == hostEnt->h_addrtype)
01403         {
01404             address->ipv6.port = htons(port);
01405               address->ipv6.flowinfo = 0;
01406               address->ipv6.scope_id = 0;
01407             memcpy(&address->ipv6.ip, addr, hostEnt->h_length);
01408         }
01409         else
01410         {
01411             PR_ASSERT(AF_INET == hostEnt->h_addrtype);
01412             address->inet.port = htons(port);
01413             memcpy(&address->inet.ip, addr, hostEnt->h_length);
01414         }
01415     }
01416     return enumIndex;
01417 }  /* PR_EnumerateHostEnt */
01418 
01419 PR_IMPLEMENT(PRStatus) PR_InitializeNetAddr(
01420     PRNetAddrValue val, PRUint16 port, PRNetAddr *addr)
01421 {
01422     PRStatus rv = PR_SUCCESS;
01423     if (!_pr_initialized) _PR_ImplicitInitialization();
01424 
01425        if (val != PR_IpAddrNull) memset(addr, 0, sizeof(addr->inet));
01426        addr->inet.family = AF_INET;
01427        addr->inet.port = htons(port);
01428        switch (val)
01429        {
01430        case PR_IpAddrNull:
01431               break;  /* don't overwrite the address */
01432        case PR_IpAddrAny:
01433               addr->inet.ip = htonl(INADDR_ANY);
01434               break;
01435        case PR_IpAddrLoopback:
01436               addr->inet.ip = htonl(INADDR_LOOPBACK);
01437               break;
01438        default:
01439               PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
01440               rv = PR_FAILURE;
01441        }
01442     return rv;
01443 }  /* PR_InitializeNetAddr */
01444 
01445 PR_IMPLEMENT(PRStatus) PR_SetNetAddr(
01446     PRNetAddrValue val, PRUint16 af, PRUint16 port, PRNetAddr *addr)
01447 {
01448     PRStatus rv = PR_SUCCESS;
01449     if (!_pr_initialized) _PR_ImplicitInitialization();
01450 
01451     if (af == PR_AF_INET6)
01452     {
01453         if (val != PR_IpAddrNull) memset(addr, 0, sizeof(addr->ipv6));
01454         addr->ipv6.family = af;
01455         addr->ipv6.port = htons(port);
01456         addr->ipv6.flowinfo = 0;
01457         addr->ipv6.scope_id = 0;
01458         switch (val)
01459         {
01460         case PR_IpAddrNull:
01461             break;  /* don't overwrite the address */
01462         case PR_IpAddrAny:
01463             addr->ipv6.ip = _pr_in6addr_any;
01464             break;
01465         case PR_IpAddrLoopback:
01466             addr->ipv6.ip = _pr_in6addr_loopback;
01467             break;
01468         default:
01469             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
01470             rv = PR_FAILURE;
01471         }
01472     }
01473     else
01474     {
01475         if (val != PR_IpAddrNull) memset(addr, 0, sizeof(addr->inet));
01476         addr->inet.family = af;
01477         addr->inet.port = htons(port);
01478         switch (val)
01479         {
01480         case PR_IpAddrNull:
01481             break;  /* don't overwrite the address */
01482         case PR_IpAddrAny:
01483             addr->inet.ip = htonl(INADDR_ANY);
01484             break;
01485         case PR_IpAddrLoopback:
01486             addr->inet.ip = htonl(INADDR_LOOPBACK);
01487             break;
01488         default:
01489             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
01490             rv = PR_FAILURE;
01491         }
01492     }
01493     return rv;
01494 }  /* PR_SetNetAddr */
01495 
01496 PR_IMPLEMENT(PRBool)
01497 PR_IsNetAddrType(const PRNetAddr *addr, PRNetAddrValue val)
01498 {
01499     if (addr->raw.family == PR_AF_INET6) {
01500         if (val == PR_IpAddrAny) {
01501                      if (_PR_IN6_IS_ADDR_UNSPECIFIED((PRIPv6Addr *)&addr->ipv6.ip)) {
01502               return PR_TRUE;
01503                      } else if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip)
01504                                    && _PR_IN6_V4MAPPED_TO_IPADDR((PRIPv6Addr *)&addr->ipv6.ip)
01505                                                  == htonl(INADDR_ANY)) {
01506               return PR_TRUE;
01507                      }
01508         } else if (val == PR_IpAddrLoopback) {
01509             if (_PR_IN6_IS_ADDR_LOOPBACK((PRIPv6Addr *)&addr->ipv6.ip)) {
01510               return PR_TRUE;
01511                      } else if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip)
01512                                    && _PR_IN6_V4MAPPED_TO_IPADDR((PRIPv6Addr *)&addr->ipv6.ip)
01513                                                  == htonl(INADDR_LOOPBACK)) {
01514               return PR_TRUE;
01515                      }
01516         } else if (val == PR_IpAddrV4Mapped
01517                 && _PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip)) {
01518             return PR_TRUE;
01519         }
01520     } else {
01521         if (addr->raw.family == AF_INET) {
01522             if (val == PR_IpAddrAny && addr->inet.ip == htonl(INADDR_ANY)) {
01523                 return PR_TRUE;
01524             } else if (val == PR_IpAddrLoopback
01525                     && addr->inet.ip == htonl(INADDR_LOOPBACK)) {
01526                 return PR_TRUE;
01527             }
01528         }
01529     }
01530     return PR_FALSE;
01531 }
01532 
01533 #ifndef _PR_HAVE_INET_NTOP
01534 #define XX 127
01535 static const unsigned char index_hex[256] = {
01536     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
01537     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
01538     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
01539      0, 1, 2, 3,  4, 5, 6, 7,  8, 9,XX,XX, XX,XX,XX,XX,
01540     XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX,
01541     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
01542     XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX,
01543     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
01544     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
01545     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
01546     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
01547     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
01548     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
01549     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
01550     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
01551     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
01552 };
01553 
01554 /*
01555  * StringToV6Addr() returns 1 if the conversion succeeds,
01556  * or 0 if the input is not a valid IPv6 address string.
01557  * (Same as inet_pton(AF_INET6, string, addr).)
01558  */
01559 static int StringToV6Addr(const char *string, PRIPv6Addr *addr)
01560 {
01561     const unsigned char *s = (const unsigned char *)string;
01562     int section = 0;        /* index of the current section (a 16-bit
01563                              * piece of the address */
01564     int double_colon = -1;  /* index of the section after the first
01565                              * 16-bit group of zeros represented by
01566                              * the double colon */
01567     unsigned int val;
01568     int len;
01569 
01570     /* Handle initial (double) colon */
01571     if (*s == ':') {
01572         if (s[1] != ':') return 0;
01573         s += 2;
01574         addr->pr_s6_addr16[0] = 0;
01575         section = double_colon = 1;
01576     }
01577 
01578     while (*s) {
01579         if (section == 8) return 0; /* too long */
01580         if (*s == ':') {
01581             if (double_colon != -1) return 0; /* two double colons */
01582             addr->pr_s6_addr16[section++] = 0;
01583             double_colon = section;
01584             s++;
01585             continue;
01586         }
01587         for (len = val = 0; len < 4 && index_hex[*s] != XX; len++) {
01588             val = (val << 4) + index_hex[*s++];
01589         }
01590         if (*s == '.') {
01591             if (len == 0) return 0; /* nothing between : and . */
01592             break;
01593         }
01594         if (*s == ':') {
01595             s++;
01596             if (!*s) return 0; /* cannot end with single colon */
01597         } else if (*s) {
01598             return 0; /* bad character */
01599         }
01600         addr->pr_s6_addr16[section++] = htons((unsigned short)val);
01601     }
01602     
01603     if (*s == '.') {
01604         /* Have a trailing v4 format address */
01605         if (section > 6) return 0; /* not enough room */
01606 
01607         /*
01608          * The number before the '.' is decimal, but we parsed it
01609          * as hex.  That means it is in BCD.  Check it for validity
01610          * and convert it to binary.
01611          */
01612         if (val > 0x0255 || (val & 0xf0) > 0x90 || (val & 0xf) > 9) return 0;
01613         val = (val >> 8) * 100 + ((val >> 4) & 0xf) * 10 + (val & 0xf);
01614         addr->pr_s6_addr[2 * section] = val;
01615 
01616         s++;
01617         val = index_hex[*s++];
01618         if (val > 9) return 0;
01619         while (*s >= '0' && *s <= '9') {
01620             val = val * 10 + *s++ - '0';
01621             if (val > 255) return 0;
01622         }
01623         if (*s != '.') return 0; /* must have exactly 4 decimal numbers */
01624         addr->pr_s6_addr[2 * section + 1] = val;
01625         section++;
01626 
01627         s++;
01628         val = index_hex[*s++];
01629         if (val > 9) return 0;
01630         while (*s >= '0' && *s <= '9') {
01631             val = val * 10 + *s++ - '0';
01632             if (val > 255) return 0;
01633         }
01634         if (*s != '.') return 0; /* must have exactly 4 decimal numbers */
01635         addr->pr_s6_addr[2 * section] = val;
01636 
01637         s++;
01638         val = index_hex[*s++];
01639         if (val > 9) return 0;
01640         while (*s >= '0' && *s <= '9') {
01641             val = val * 10 + *s++ - '0';
01642             if (val > 255) return 0;
01643         }
01644         if (*s) return 0; /* must have exactly 4 decimal numbers */
01645         addr->pr_s6_addr[2 * section + 1] = val;
01646         section++;
01647     }
01648     
01649     if (double_colon != -1) {
01650         /* Stretch the double colon */
01651         int tosection;
01652         int ncopy = section - double_colon;
01653         for (tosection = 7; ncopy--; tosection--) {
01654             addr->pr_s6_addr16[tosection] = 
01655                 addr->pr_s6_addr16[double_colon + ncopy];
01656         }
01657         while (tosection >= double_colon) {
01658             addr->pr_s6_addr16[tosection--] = 0;
01659         }
01660     } else if (section != 8) {
01661         return 0; /* too short */
01662     }
01663     return 1;
01664 }
01665 #undef XX
01666             
01667 static const char *basis_hex = "0123456789abcdef";
01668 
01669 /*
01670  * V6AddrToString() returns a pointer to the buffer containing
01671  * the text string if the conversion succeeds, and NULL otherwise.
01672  * (Same as inet_ntop(AF_INET6, addr, buf, size), except that errno
01673  * is not set on failure.)
01674  */
01675 static const char *V6AddrToString(
01676     const PRIPv6Addr *addr, char *buf, PRUint32 size)
01677 {
01678 #define STUFF(c) do { \
01679     if (!size--) return NULL; \
01680     *buf++ = (c); \
01681 } while (0)
01682 
01683     int double_colon = -1;          /* index of the first 16-bit
01684                                      * group of zeros represented
01685                                      * by the double colon */
01686     int double_colon_length = 1;    /* use double colon only if
01687                                      * there are two or more 16-bit
01688                                      * groups of zeros */
01689     int zero_length;
01690     int section;
01691     unsigned int val;
01692     const char *bufcopy = buf;
01693 
01694     /* Scan to find the placement of the double colon */
01695     for (section = 0; section < 8; section++) {
01696         if (addr->pr_s6_addr16[section] == 0) {
01697             zero_length = 1;
01698             section++;
01699             while (section < 8 && addr->pr_s6_addr16[section] == 0) {
01700                 zero_length++;
01701                 section++;
01702             }
01703             /* Select the longest sequence of zeros */
01704             if (zero_length > double_colon_length) {
01705                 double_colon = section - zero_length;
01706                 double_colon_length = zero_length;
01707             }
01708         }
01709     }
01710 
01711     /* Now start converting to a string */
01712     section = 0;
01713 
01714     if (double_colon == 0) {
01715         if (double_colon_length == 6 ||
01716             (double_colon_length == 5 && addr->pr_s6_addr16[5] == 0xffff)) {
01717             /* ipv4 format address */
01718             STUFF(':');
01719             STUFF(':');
01720             if (double_colon_length == 5) {
01721                 STUFF('f');
01722                 STUFF('f');
01723                 STUFF('f');
01724                 STUFF('f');
01725                 STUFF(':');
01726             }
01727             if (addr->pr_s6_addr[12] > 99) STUFF(addr->pr_s6_addr[12]/100 + '0');
01728             if (addr->pr_s6_addr[12] > 9) STUFF((addr->pr_s6_addr[12]%100)/10 + '0');
01729             STUFF(addr->pr_s6_addr[12]%10 + '0');
01730             STUFF('.');
01731             if (addr->pr_s6_addr[13] > 99) STUFF(addr->pr_s6_addr[13]/100 + '0');
01732             if (addr->pr_s6_addr[13] > 9) STUFF((addr->pr_s6_addr[13]%100)/10 + '0');
01733             STUFF(addr->pr_s6_addr[13]%10 + '0');
01734             STUFF('.');
01735             if (addr->pr_s6_addr[14] > 99) STUFF(addr->pr_s6_addr[14]/100 + '0');
01736             if (addr->pr_s6_addr[14] > 9) STUFF((addr->pr_s6_addr[14]%100)/10 + '0');
01737             STUFF(addr->pr_s6_addr[14]%10 + '0');
01738             STUFF('.');
01739             if (addr->pr_s6_addr[15] > 99) STUFF(addr->pr_s6_addr[15]/100 + '0');
01740             if (addr->pr_s6_addr[15] > 9) STUFF((addr->pr_s6_addr[15]%100)/10 + '0');
01741             STUFF(addr->pr_s6_addr[15]%10 + '0');
01742             STUFF('\0');
01743             return bufcopy;
01744         }
01745     }
01746 
01747     while (section < 8) {
01748         if (section == double_colon) {
01749             STUFF(':');
01750             STUFF(':');
01751             section += double_colon_length;
01752             continue;
01753         }
01754         val = ntohs(addr->pr_s6_addr16[section]);
01755         if (val > 0xfff) {
01756             STUFF(basis_hex[val >> 12]);
01757         }
01758         if (val > 0xff) {
01759             STUFF(basis_hex[(val >> 8) & 0xf]);
01760         }
01761         if (val > 0xf) {
01762             STUFF(basis_hex[(val >> 4) & 0xf]);
01763         }
01764         STUFF(basis_hex[val & 0xf]);
01765         section++;
01766         if (section < 8 && section != double_colon) STUFF(':');
01767     }
01768     STUFF('\0');
01769     return bufcopy;
01770 #undef STUFF    
01771 }
01772 
01773 #endif /* !_PR_HAVE_INET_NTOP */
01774 
01775 PR_IMPLEMENT(PRStatus) PR_StringToNetAddr(const char *string, PRNetAddr *addr)
01776 {
01777     PRStatus status = PR_SUCCESS;
01778     PRIntn rv;
01779 
01780 #if defined(_PR_HAVE_INET_NTOP)
01781     rv = inet_pton(AF_INET6, string, &addr->ipv6.ip);
01782     if (1 == rv)
01783     {
01784         addr->raw.family = PR_AF_INET6;
01785     }
01786     else
01787     {
01788         PR_ASSERT(0 == rv);
01789         /* clean up after the failed inet_pton() call */
01790         memset(&addr->ipv6.ip, 0, sizeof(addr->ipv6.ip));
01791         rv = inet_pton(AF_INET, string, &addr->inet.ip);
01792         if (1 == rv)
01793         {
01794             addr->raw.family = AF_INET;
01795         }
01796         else
01797         {
01798             PR_ASSERT(0 == rv);
01799             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
01800             status = PR_FAILURE;
01801         }
01802     }
01803 #else /* _PR_HAVE_INET_NTOP */
01804     rv = StringToV6Addr(string, &addr->ipv6.ip);
01805     if (1 == rv) {
01806         addr->raw.family = PR_AF_INET6;
01807         return PR_SUCCESS;
01808     }
01809     PR_ASSERT(0 == rv);
01810     /* clean up after the failed StringToV6Addr() call */
01811     memset(&addr->ipv6.ip, 0, sizeof(addr->ipv6.ip));
01812 
01813     addr->inet.family = AF_INET;
01814 #ifdef XP_OS2_VACPP
01815     addr->inet.ip = inet_addr((char *)string);
01816 #else
01817     addr->inet.ip = inet_addr(string);
01818 #endif
01819     if ((PRUint32) -1 == addr->inet.ip)
01820     {
01821         /*
01822          * The string argument is a malformed address string.
01823          */
01824         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
01825         status = PR_FAILURE;
01826     }
01827 #endif /* _PR_HAVE_INET_NTOP */
01828 
01829     return status;
01830 }
01831 
01832 PR_IMPLEMENT(PRStatus) PR_NetAddrToString(
01833     const PRNetAddr *addr, char *string, PRUint32 size)
01834 {
01835     if (PR_AF_INET6 == addr->raw.family)
01836     {
01837 #if defined(_PR_HAVE_INET_NTOP)
01838         if (NULL == inet_ntop(AF_INET6, &addr->ipv6.ip, string, size))
01839 #else
01840         if (NULL == V6AddrToString(&addr->ipv6.ip, string, size))
01841 #endif
01842         {
01843             /* the size of the result buffer is inadequate */
01844             PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
01845             return PR_FAILURE;
01846         }
01847     }
01848     else
01849     {
01850         if (size < 16) goto failed;
01851         if (AF_INET != addr->raw.family) goto failed;
01852         else
01853         {
01854             unsigned char *byte = (unsigned char*)&addr->inet.ip;
01855             PR_snprintf(string, size, "%u.%u.%u.%u",
01856                 byte[0], byte[1], byte[2], byte[3]);
01857         }
01858     }
01859 
01860     return PR_SUCCESS;
01861 
01862 failed:
01863     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
01864     return PR_FAILURE;
01865 
01866 }  /* PR_NetAddrToString */
01867 
01868 /*
01869  * Convert an IPv4 addr to an (IPv4-mapped) IPv6 addr
01870  */
01871 PR_IMPLEMENT(void) PR_ConvertIPv4AddrToIPv6(PRUint32 v4addr, PRIPv6Addr *v6addr)
01872 {
01873     PRUint8 *dstp;
01874     dstp = v6addr->pr_s6_addr;
01875     memset(dstp, 0, 10);
01876     memset(dstp + 10, 0xff, 2);
01877     memcpy(dstp + 12,(char *) &v4addr, 4);
01878 }
01879 
01880 PR_IMPLEMENT(PRUint16) PR_ntohs(PRUint16 n) { return ntohs(n); }
01881 PR_IMPLEMENT(PRUint32) PR_ntohl(PRUint32 n) { return ntohl(n); }
01882 PR_IMPLEMENT(PRUint16) PR_htons(PRUint16 n) { return htons(n); }
01883 PR_IMPLEMENT(PRUint32) PR_htonl(PRUint32 n) { return htonl(n); }
01884 PR_IMPLEMENT(PRUint64) PR_ntohll(PRUint64 n)
01885 {
01886 #ifdef IS_BIG_ENDIAN
01887     return n;
01888 #else
01889     PRUint64 tmp;
01890     PRUint32 hi, lo;
01891     LL_L2UI(lo, n);
01892     LL_SHR(tmp, n, 32);
01893     LL_L2UI(hi, tmp);
01894     hi = PR_ntohl(hi);
01895     lo = PR_ntohl(lo);
01896     LL_UI2L(n, lo);
01897     LL_SHL(n, n, 32);
01898     LL_UI2L(tmp, hi);
01899     LL_ADD(n, n, tmp);
01900     return n;
01901 #endif
01902 }  /* ntohll */
01903 
01904 PR_IMPLEMENT(PRUint64) PR_htonll(PRUint64 n)
01905 {
01906 #ifdef IS_BIG_ENDIAN
01907     return n;
01908 #else
01909     PRUint64 tmp;
01910     PRUint32 hi, lo;
01911     LL_L2UI(lo, n);
01912     LL_SHR(tmp, n, 32);
01913     LL_L2UI(hi, tmp);
01914     hi = htonl(hi);
01915     lo = htonl(lo);
01916     LL_UI2L(n, lo);
01917     LL_SHL(n, n, 32);
01918     LL_UI2L(tmp, hi);
01919     LL_ADD(n, n, tmp);
01920     return n;
01921 #endif
01922 }  /* htonll */
01923 
01924 
01925 /*
01926  * Implementation of PR_GetAddrInfoByName and friends
01927  *
01928  * Compile-time options:
01929  *
01930  *  _PR_HAVE_GETADDRINFO  Define this macro if the target system provides
01931  *                        getaddrinfo. With this defined, NSPR will require
01932  *                        getaddrinfo at run time. If this if not defined,
01933  *                        then NSPR will attempt to dynamically resolve
01934  *                        getaddrinfo, falling back to PR_GetHostByName if
01935  *                        getaddrinfo does not exist on the target system.
01936  *
01937  * Since getaddrinfo is a relatively new system call on many systems,
01938  * we are forced to dynamically resolve it at run time in most cases.
01939  * The exception includes any system (such as Mac OS X) that is known to
01940  * provide getaddrinfo in all versions that NSPR cares to support.
01941  */
01942 
01943 #if defined(_PR_HAVE_GETADDRINFO)
01944 
01945 #if defined(_PR_INET6)
01946 
01947 typedef struct addrinfo PRADDRINFO;
01948 #define GETADDRINFO getaddrinfo
01949 #define FREEADDRINFO freeaddrinfo
01950 
01951 #elif defined(_PR_INET6_PROBE)
01952 
01953 typedef struct addrinfo PRADDRINFO;
01954 
01955 /* getaddrinfo/freeaddrinfo prototypes */ 
01956 #if defined(WIN32)
01957 #define FUNC_MODIFIER __stdcall
01958 #else
01959 #define FUNC_MODIFIER
01960 #endif
01961 typedef int (FUNC_MODIFIER * FN_GETADDRINFO)
01962     (const char *nodename,
01963      const char *servname,
01964      const PRADDRINFO *hints,
01965      PRADDRINFO **res);
01966 typedef int (FUNC_MODIFIER * FN_FREEADDRINFO)
01967     (PRADDRINFO *ai);
01968 
01969 /* global state */
01970 static FN_GETADDRINFO   _pr_getaddrinfo   = NULL;
01971 static FN_FREEADDRINFO  _pr_freeaddrinfo  = NULL;
01972 
01973 #if defined(VMS)
01974 #define GETADDRINFO_SYMBOL getenv("GETADDRINFO")
01975 #define FREEADDRINFO_SYMBOL getenv("FREEADDRINFO")
01976 #else
01977 #define GETADDRINFO_SYMBOL "getaddrinfo"
01978 #define FREEADDRINFO_SYMBOL "freeaddrinfo"
01979 #endif
01980 
01981 PRStatus
01982 _pr_find_getaddrinfo(void)
01983 {
01984     PRLibrary *lib;
01985 #ifdef WIN32
01986     /*
01987      * On windows, we need to search ws2_32.dll or wship6.dll
01988      * (Microsoft IPv6 Technology Preview for Windows 2000) for
01989      * getaddrinfo and freeaddrinfo.  These libraries might not
01990      * be loaded yet.
01991      */
01992     const char *libname[] = { "ws2_32.dll", "wship6.dll" };
01993     int i;
01994 
01995     for (i = 0; i < sizeof(libname)/sizeof(libname[0]); i++) {
01996         lib = PR_LoadLibrary(libname[i]);
01997         if (!lib) {
01998             continue;
01999         }
02000         _pr_getaddrinfo = (FN_GETADDRINFO)
02001             PR_FindFunctionSymbol(lib, GETADDRINFO_SYMBOL);
02002         if (!_pr_getaddrinfo) {
02003             PR_UnloadLibrary(lib);
02004             continue;
02005         }
02006         _pr_freeaddrinfo = (FN_FREEADDRINFO)
02007             PR_FindFunctionSymbol(lib, FREEADDRINFO_SYMBOL);
02008         PR_ASSERT(_pr_freeaddrinfo);
02009         /* Keep the library loaded. */
02010         return PR_SUCCESS;
02011     }
02012     return PR_FAILURE;
02013 #else
02014     /*
02015      * Resolve getaddrinfo by searching all loaded libraries.  Then
02016      * search library containing getaddrinfo for freeaddrinfo.
02017      */
02018     _pr_getaddrinfo = (FN_GETADDRINFO)
02019         PR_FindFunctionSymbolAndLibrary(GETADDRINFO_SYMBOL, &lib);
02020     if (!_pr_getaddrinfo) {
02021         return PR_FAILURE;
02022     }
02023     _pr_freeaddrinfo = (FN_FREEADDRINFO)
02024         PR_FindFunctionSymbol(lib, FREEADDRINFO_SYMBOL);
02025     PR_UnloadLibrary(lib);
02026     if (!_pr_freeaddrinfo) {
02027         return PR_FAILURE;
02028     }
02029     return PR_SUCCESS;
02030 #endif
02031 }
02032 
02033 #define GETADDRINFO (*_pr_getaddrinfo)
02034 #define FREEADDRINFO (*_pr_freeaddrinfo)
02035 
02036 #endif /* _PR_INET6 */
02037 
02038 #endif /* _PR_HAVE_GETADDRINFO */
02039 
02040 /*
02041  * If getaddrinfo does not exist, then we will fall back on
02042  * PR_GetHostByName, which requires that we allocate a buffer for the 
02043  * PRHostEnt data structure and its members.
02044  */
02045 typedef struct PRAddrInfoFB {
02046     char      buf[PR_NETDB_BUF_SIZE];
02047     PRHostEnt hostent;
02048     PRBool    has_cname;
02049 } PRAddrInfoFB;
02050 
02051 static PRAddrInfo *
02052 pr_GetAddrInfoByNameFB(const char  *hostname,
02053                        PRUint16     af,
02054                        PRIntn       flags)
02055 {
02056     PRStatus rv;
02057     PRAddrInfoFB *ai;
02058     /* fallback on PR_GetHostByName */
02059     ai = PR_NEW(PRAddrInfoFB);
02060     if (!ai) {
02061         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
02062         return NULL;
02063     }
02064     rv = PR_GetHostByName(hostname, ai->buf, sizeof ai->buf, &ai->hostent);
02065     if (rv == PR_FAILURE) {
02066         PR_Free(ai);
02067         return NULL;
02068     }
02069     ai->has_cname = !(flags & PR_AI_NOCANONNAME);
02070 
02071     return (PRAddrInfo *) ai;
02072 }
02073 
02074 PR_IMPLEMENT(PRAddrInfo *) PR_GetAddrInfoByName(const char  *hostname,
02075                                                 PRUint16     af,
02076                                                 PRIntn       flags)
02077 {
02078     /* restrict input to supported values */
02079     if ((af != PR_AF_INET && af != PR_AF_UNSPEC) ||
02080         (flags & ~ PR_AI_NOCANONNAME) != PR_AI_ADDRCONFIG) {
02081         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
02082         return NULL;
02083     }
02084 
02085     if (!_pr_initialized) _PR_ImplicitInitialization();
02086 
02087 #if !defined(_PR_HAVE_GETADDRINFO)
02088     return pr_GetAddrInfoByNameFB(hostname, af, flags);
02089 #else
02090 #if defined(_PR_INET6_PROBE)
02091     if (!_pr_ipv6_is_present) {
02092         return pr_GetAddrInfoByNameFB(hostname, af, flags);
02093     }
02094 #endif
02095     {
02096         PRADDRINFO *res, hints;
02097         PRStatus rv;
02098 
02099         /*
02100          * we assume a RFC 2553 compliant getaddrinfo.  this may at some
02101          * point need to be customized as platforms begin to adopt the
02102          * RFC 3493.
02103          */
02104 
02105         memset(&hints, 0, sizeof(hints));
02106         hints.ai_flags = (flags & PR_AI_NOCANONNAME) ? 0: AI_CANONNAME;
02107         hints.ai_family = (af == PR_AF_INET) ? AF_INET : AF_UNSPEC;
02108 
02109         /*
02110          * it is important to select a socket type in the hints, otherwise we
02111          * will get back repetitive entries: one for each socket type.  since
02112          * we do not expose ai_socktype through our API, it is okay to do this
02113          * here.  the application may still choose to create a socket of some
02114          * other type.
02115          */
02116         hints.ai_socktype = SOCK_STREAM;
02117 
02118         rv = GETADDRINFO(hostname, NULL, &hints, &res);
02119         if (rv == 0)
02120             return (PRAddrInfo *) res;
02121 
02122         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, rv);
02123     }
02124     return NULL;
02125 #endif
02126 }
02127 
02128 PR_IMPLEMENT(void) PR_FreeAddrInfo(PRAddrInfo *ai)
02129 {
02130 #if defined(_PR_HAVE_GETADDRINFO)
02131 #if defined(_PR_INET6_PROBE)
02132     if (!_pr_ipv6_is_present)
02133         PR_Free((PRAddrInfoFB *) ai);
02134     else
02135 #endif
02136         FREEADDRINFO((PRADDRINFO *) ai);
02137 #else
02138     PR_Free((PRAddrInfoFB *) ai);
02139 #endif
02140 }
02141 
02142 PR_IMPLEMENT(void *) PR_EnumerateAddrInfo(void             *iterPtr,
02143                                           const PRAddrInfo *base,
02144                                           PRUint16          port,
02145                                           PRNetAddr        *result)
02146 {
02147 #if defined(_PR_HAVE_GETADDRINFO)
02148     PRADDRINFO *ai;
02149 #if defined(_PR_INET6_PROBE)
02150     if (!_pr_ipv6_is_present) {
02151         /* using PRAddrInfoFB */
02152         PRIntn iter = (PRIntn)(PRPtrdiff) iterPtr;
02153         iter = PR_EnumerateHostEnt(iter, &((PRAddrInfoFB *) base)->hostent, port, result);
02154         if (iter < 0)
02155             iter = 0;
02156         return (void *)(PRPtrdiff) iter;
02157     }
02158 #endif
02159 
02160     if (iterPtr)
02161         ai = ((PRADDRINFO *) iterPtr)->ai_next;
02162     else
02163         ai = (PRADDRINFO *) base;
02164 
02165     if (ai) {
02166         /* copy sockaddr to PRNetAddr */
02167         memcpy(result, ai->ai_addr, ai->ai_addrlen);
02168         result->raw.family = ai->ai_addr->sa_family;
02169         if (ai->ai_addrlen < sizeof(PRNetAddr))
02170             memset(((char*)result)+ai->ai_addrlen, 0, sizeof(PRNetAddr) - ai->ai_addrlen);
02171 
02172         if (result->raw.family == PR_AF_INET)
02173             result->inet.port = htons(port);
02174         else
02175             result->ipv6.port = htons(port);
02176     }
02177 
02178     return ai;
02179 #else
02180     /* using PRAddrInfoFB */
02181     PRIntn iter = (PRIntn) iterPtr;
02182     iter = PR_EnumerateHostEnt(iter, &((PRAddrInfoFB *) base)->hostent, port, result);
02183     if (iter < 0)
02184         iter = 0;
02185     return (void *) iter;
02186 #endif
02187 }
02188 
02189 PR_IMPLEMENT(const char *) PR_GetCanonNameFromAddrInfo(const PRAddrInfo *ai)
02190 {
02191 #if defined(_PR_HAVE_GETADDRINFO)
02192 #if defined(_PR_INET6_PROBE)
02193     if (!_pr_ipv6_is_present) {
02194         const PRAddrInfoFB *fb = (const PRAddrInfoFB *) ai;
02195         return fb->has_cname ? fb->hostent.h_name : NULL;
02196     } 
02197 #endif
02198     return ((const PRADDRINFO *) ai)->ai_canonname;
02199 #else
02200     const PRAddrInfoFB *fb = (const PRAddrInfoFB *) ai;
02201     return fb->has_cname ? fb->hostent.h_name : NULL;
02202 #endif
02203 }