home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / misc / prnetdb.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  23.3 KB  |  831 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "primpl.h"
  20.  
  21. #include <string.h>
  22.  
  23. /*
  24.  * On Unix, the error code for gethostbyname() and gethostbyaddr()
  25.  * is returned in the global variable h_errno, instead of the usual
  26.  * errno.
  27.  */
  28. #if defined(XP_UNIX)
  29. #if defined(_PR_NEED_H_ERRNO)
  30. extern int h_errno;
  31. #endif
  32. #define _MD_GETHOST_ERRNO() h_errno
  33. #else
  34. #define _MD_GETHOST_ERRNO() _MD_ERRNO()
  35. #endif
  36.  
  37. #if defined(_PR_NO_PREEMPT)
  38. #define LOCK_DNS()
  39. #define UNLOCK_DNS()
  40. #else
  41. PRLock *_pr_dnsLock = NULL;
  42. #define LOCK_DNS() PR_Lock(_pr_dnsLock)
  43. #define UNLOCK_DNS() PR_Unlock(_pr_dnsLock)
  44. #endif  /* defined(_PR_NO_PREEMPT) */
  45.  
  46. #if defined(XP_UNIX)
  47. #include <signal.h>
  48.  
  49. /*
  50. ** Unix's, as a rule, have a bug in their select code: if a timer
  51. ** interrupt occurs and you have SA_RESTART set on your signal, select
  52. ** forgets how much time has elapsed and restarts the system call from
  53. ** the beginning. This can cause a call to select to *never* time out.
  54. **
  55. ** Because we aren't certain that select is wrapped properly in this code
  56. ** we disable the clock while a dns operation is occuring. This sucks and
  57. ** can be tossed when implement our own dns code that calls our own
  58. ** PR_Poll.
  59. */
  60.  
  61. static sigset_t timer_set;
  62. #define DISABLECLOCK(_set)    sigprocmask(SIG_BLOCK, &timer_set, _set)
  63. #define ENABLECLOCK(_set)    sigprocmask(SIG_SETMASK, _set, 0)
  64.  
  65. #endif /* XP_UNIX */
  66.  
  67. /*
  68.  * Some platforms have the reentrant getprotobyname_r() and
  69.  * getprotobynumber_r().  However, they come in two flavors.
  70.  * Some return a pointer to struct protoent, others return
  71.  * an int.
  72.  */
  73.  
  74. #if defined(SOLARIS) \
  75.     || (defined(LINUX2_0) && defined(_REENTRANT) \
  76.         && !(defined(__GLIBC__) && __GLIBC__ >= 2))
  77. #define _PR_HAVE_GETPROTO_R
  78. #define _PR_HAVE_GETPROTO_R_POINTER
  79. #endif
  80.  
  81. #if defined(OSF1) || (defined(AIX) && defined(_THREAD_SAFE)) \
  82.     || (defined(HPUX10_10) && defined(_REENTRANT)) \
  83.         || (defined(HPUX10_20) && defined(_REENTRANT))
  84. #define _PR_HAVE_GETPROTO_R
  85. #define _PR_HAVE_GETPROTO_R_INT
  86. #endif
  87.  
  88. #if (defined(LINUX2_0) && defined(__GLIBC__) && __GLIBC__ >= 2)
  89. #define _PR_HAVE_GETPROTO_R
  90. #define _PR_HAVE_5_ARG_GETPROTO_R
  91. #endif
  92.  
  93. #if !defined(_PR_HAVE_GETPROTO_R)
  94. PRLock* _getproto_lock = NULL;
  95. #endif
  96.  
  97. #if defined(_PR_INET6)
  98. PRBool _pr_ipv6_enabled = PR_FALSE;
  99. #if defined(AIX)
  100. const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
  101. const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
  102. #else
  103. extern const struct in6_addr in6addr_any;
  104. extern const struct in6_addr in6addr_loopback;
  105. #endif /* AIX */
  106. #endif /* _PR_INET6 */
  107.  
  108. void _PR_InitNet(void)
  109. {
  110. #if defined(XP_UNIX)
  111. #ifdef HAVE_NETCONFIG
  112.     /*
  113.      * This one-liner prevents the endless re-open's and re-read's of
  114.      * /etc/netconfig on EACH and EVERY call to accept(), connect(), etc.
  115.      */
  116.      (void)setnetconfig();
  117. #endif
  118.     sigemptyset(&timer_set);
  119.     sigaddset(&timer_set, SIGALRM);
  120. #endif
  121. #if !defined(_PR_NO_PREEMPT)
  122.     _pr_dnsLock = PR_NewLock();
  123. #endif
  124. #if !defined(_PR_HAVE_GETPROTO_R)
  125.     _getproto_lock = PR_NewLock();
  126. #endif
  127.  
  128. }
  129.  
  130. PR_IMPLEMENT(PRStatus) PR_SetIPv6Enable(PRBool itIs)
  131. {
  132. #if defined(XP_MAC)
  133. #pragma unused (itIs)
  134. #endif
  135.  
  136. #if defined(_PR_INET6)
  137.     _pr_ipv6_enabled = itIs;
  138.     return PR_SUCCESS;
  139. #else /* defined(_PR_INET6) */
  140.     PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, 0);
  141.     return PR_FAILURE;
  142. #endif /* defined(_PR_INET6) */
  143. }  /* PR_SetIPv6Enable */
  144.  
  145. PR_IMPLEMENT(PRStatus) PR_GetHostName(char *name, PRUint32 namelen)
  146. {
  147. #if defined(DEBUG)
  148.     static PRBool warn = PR_TRUE;
  149.     if (warn) warn = _PR_Obsolete("PR_GetHostName()", "PR_GetSystemInfo()");
  150. #endif
  151.     return PR_GetSystemInfo(PR_SI_HOSTNAME, name, namelen);
  152. }
  153.  
  154. /*
  155. ** Allocate space from the buffer, aligning it to "align" before doing
  156. ** the allocation. "align" must be a power of 2.
  157. */
  158. static char *Alloc(PRIntn amount, char **bufp, PRIntn *buflenp, PRIntn align)
  159. {
  160.     char *buf = *bufp;
  161.     PRIntn buflen = *buflenp;
  162.  
  163.     if (align && ((long)buf & (align - 1))) {
  164.         PRIntn skip = align - ((ptrdiff_t)buf & (align - 1));
  165.         if (buflen < skip) {
  166.             return 0;
  167.         }
  168.         buf += skip;
  169.         buflen -= skip;
  170.     }
  171.     if (buflen < amount) {
  172.         return 0;
  173.     }
  174.     *bufp = buf + amount;
  175.     *buflenp = buflen - amount;
  176.     return buf;
  177. }
  178.  
  179. /*
  180. ** Copy a hostent, and all of the memory that it refers to into
  181. ** (hopefully) stacked buffers.
  182. */
  183. static PRStatus CopyHostent(
  184.     struct hostent *from, char *buf, PRIntn bufsize, PRHostEnt *to)
  185. {
  186.     PRIntn len, na;
  187.     char **ap;
  188.  
  189.     /* Do the easy stuff */
  190.     to->h_addrtype = from->h_addrtype;
  191.     to->h_length = from->h_length;
  192.  
  193.     /* Copy the official name */
  194.     if (!from->h_name) return PR_FAILURE;
  195.     len = strlen(from->h_name) + 1;
  196.     to->h_name = Alloc(len, &buf, &bufsize, 0);
  197.     if (!to->h_name) return PR_FAILURE;
  198.     memcpy(to->h_name, from->h_name, len);
  199.  
  200.     /* Count the aliases, then allocate storage for the pointers */
  201.     for (na = 1, ap = from->h_aliases; *ap != 0; na++, ap++){;} /* nothing to execute */
  202.     to->h_aliases = (char**)Alloc(
  203.         na * sizeof(char*), &buf, &bufsize, sizeof(char**));
  204.     if (!to->h_aliases) return PR_FAILURE;
  205.  
  206.     /* Copy the aliases, one at a time */
  207.     for (na = 0, ap = from->h_aliases; *ap != 0; na++, ap++) {
  208.         len = strlen(*ap) + 1;
  209.         to->h_aliases[na] = Alloc(len, &buf, &bufsize, 0);
  210.         if (!to->h_aliases[na]) return PR_FAILURE;
  211.         memcpy(to->h_aliases[na], *ap, len);
  212.     }
  213.     to->h_aliases[na] = 0;
  214.  
  215.     /* Count the addresses, then allocate storage for the pointers */
  216.     for (na = 1, ap = from->h_addr_list; *ap != 0; na++, ap++){;} /* nothing to execute */
  217.     to->h_addr_list = (char**)Alloc(
  218.         na * sizeof(char*), &buf, &bufsize, sizeof(char**));
  219.     if (!to->h_addr_list) return PR_FAILURE;
  220.  
  221.     /* Copy the addresses, one at a time */
  222.     for (na = 0, ap = from->h_addr_list; *ap != 0; na++, ap++) {
  223.         to->h_addr_list[na] = Alloc(to->h_length, &buf, &bufsize, 0);
  224.         if (!to->h_addr_list[na]) return PR_FAILURE;
  225.         memcpy(to->h_addr_list[na], *ap, to->h_length);
  226.     }
  227.     to->h_addr_list[na] = 0;
  228.     return PR_SUCCESS;
  229. }
  230.  
  231. #if !defined(_PR_HAVE_GETPROTO_R)
  232. /*
  233. ** Copy a protoent, and all of the memory that it refers to into
  234. ** (hopefully) stacked buffers.
  235. */
  236. static PRStatus CopyProtoent(
  237.     struct protoent *from, char *buf, PRIntn bufsize, PRProtoEnt *to)
  238. {
  239.     PRIntn len, na;
  240.     char **ap;
  241.  
  242.     /* Do the easy stuff */
  243.     to->p_num = from->p_proto;
  244.  
  245.     /* Copy the official name */
  246.     if (!from->p_name) return PR_FAILURE;
  247.     len = strlen(from->p_name) + 1;
  248.     to->p_name = Alloc(len, &buf, &bufsize, 0);
  249.     if (!to->p_name) return PR_FAILURE;
  250.     memcpy(to->p_name, from->p_name, len);
  251.  
  252.     /* Count the aliases, then allocate storage for the pointers */
  253.     for (na = 1, ap = from->p_aliases; *ap != 0; na++, ap++){;} /* nothing to execute */
  254.     to->p_aliases = (char**)Alloc(
  255.         na * sizeof(char*), &buf, &bufsize, sizeof(char**));
  256.     if (!to->p_aliases) return PR_FAILURE;
  257.  
  258.     /* Copy the aliases, one at a time */
  259.     for (na = 0, ap = from->p_aliases; *ap != 0; na++, ap++) {
  260.         len = strlen(*ap) + 1;
  261.         to->p_aliases[na] = Alloc(len, &buf, &bufsize, 0);
  262.         if (!to->p_aliases[na]) return PR_FAILURE;
  263.         memcpy(to->p_aliases[na], *ap, len);
  264.     }
  265.     to->p_aliases[na] = 0;
  266.  
  267.     return PR_SUCCESS;
  268. }
  269. #endif /* !defined(_PR_HAVE_GETPROTO_R) */
  270.  
  271. PR_IMPLEMENT(PRStatus) PR_GetHostByName(
  272.     const char *name, char *buf, PRIntn bufsize, PRHostEnt *hp)
  273. {
  274.     struct hostent *h;
  275.     PRStatus rv = PR_FAILURE;
  276. #ifdef XP_UNIX
  277.     sigset_t oldset;
  278. #endif
  279.  
  280.     if (!_pr_initialized) _PR_ImplicitInitialization();
  281.  
  282. #ifdef XP_UNIX
  283.     DISABLECLOCK(&oldset);
  284. #endif
  285.     LOCK_DNS();
  286.  
  287. #ifdef _PR_INET6
  288.     if (_pr_ipv6_enabled)
  289.     {
  290.         h = gethostbyname2(name, AF_INET6);
  291.         if (NULL == h)
  292.         {
  293.             h = gethostbyname2(name, AF_INET);
  294.         }
  295.     }
  296.     else
  297.     {
  298.         h = gethostbyname(name);
  299.     }
  300. #else
  301.     h = gethostbyname(name);
  302. #endif /* _PR_INET6 */
  303.     
  304.     if (NULL == h)
  305.         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
  306.     else
  307.     {
  308.         rv = CopyHostent(h, buf, bufsize, hp);
  309.         if (PR_SUCCESS != rv)
  310.             PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
  311.     }
  312.     UNLOCK_DNS();
  313. #ifdef XP_UNIX
  314.     ENABLECLOCK(&oldset);
  315. #endif
  316.     return rv;
  317. }
  318.  
  319. PR_IMPLEMENT(PRStatus) PR_GetHostByAddr(
  320.     const PRNetAddr *hostaddr, char *buf, PRIntn bufsize, PRHostEnt *hostentry)
  321. {
  322.     struct hostent *h;
  323.     PRStatus rv = PR_FAILURE;
  324.     const void *addr;
  325.     int addrlen;
  326. #ifdef XP_UNIX
  327.     sigset_t oldset;
  328. #endif
  329.  
  330.     if (!_pr_initialized) _PR_ImplicitInitialization();
  331.  
  332. #ifdef XP_UNIX
  333.     DISABLECLOCK(&oldset);
  334. #endif
  335.     LOCK_DNS();
  336. #if defined(_PR_INET6)
  337.     if (hostaddr->raw.family == AF_INET6)
  338.     {
  339.         addr = &hostaddr->ipv6.ip;
  340.         addrlen = sizeof(hostaddr->ipv6.ip);
  341.     }
  342.     else
  343. #endif /* defined(_PR_INET6) */
  344.     {
  345.         PR_ASSERT(hostaddr->raw.family == AF_INET);
  346.         addr = &hostaddr->inet.ip;
  347.         addrlen = sizeof(hostaddr->inet.ip);
  348.     }
  349.  
  350.     h = gethostbyaddr(addr, addrlen, hostaddr->raw.family);
  351.     if (NULL == h) PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
  352.     else
  353.     {
  354.         rv = CopyHostent(h, buf, bufsize, hostentry);
  355.         if (PR_SUCCESS != rv) {
  356.             PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
  357.         }
  358.     }
  359.     UNLOCK_DNS();
  360. #ifdef XP_UNIX
  361.     ENABLECLOCK(&oldset);
  362. #endif
  363.     return rv;
  364. }
  365.  
  366. /******************************************************************************/
  367. /*
  368.  * Some systems define a reentrant version of getprotobyname(). Too bad
  369.  * the signature isn't always the same. But hey, they tried. If there
  370.  * is such a definition, use it. Otherwise, grab a lock and do it here.
  371.  */
  372. /******************************************************************************/
  373.  
  374. #if !defined(_PR_HAVE_GETPROTO_R)
  375. /*
  376.  * This may seem like a silly thing to do, but the compiler SHOULD
  377.  * complain if getprotobyname_r() is implemented on some system and
  378.  * we're not using it. For sure these signatures are different than
  379.  * any usable implementation.
  380.  */
  381.  
  382. static struct protoent *getprotobyname_r(const char* name)
  383. {
  384.     return getprotobyname(name);
  385. } /* getprotobyname_r */
  386.  
  387. static struct protoent *getprotobynumber_r(PRInt32 number)
  388. {
  389.     return getprotobynumber(number);
  390. } /* getprotobynumber_r */
  391.  
  392. #endif /* !defined(_PR_HAVE_GETPROTO_R) */
  393.  
  394. PR_IMPLEMENT(PRStatus) PR_GetProtoByName(
  395.     const char* name, char* buffer, PRInt32 buflen, PRProtoEnt* result)
  396. {
  397.     PRStatus rv = PR_SUCCESS;
  398.     struct protoent* res = (struct protoent*)result;
  399.  
  400.     if (!_pr_initialized) _PR_ImplicitInitialization();
  401.  
  402. #if defined(_PR_HAVE_GETPROTO_R_INT)
  403.     {
  404.         /*
  405.         ** The protoent_data has a pointer as the first field.
  406.         ** That implies the buffer better be aligned, and char*
  407.         ** doesn't promise much.
  408.         */
  409.         PRUptrdiff aligned = (PRUptrdiff)buffer;
  410.         if (0 != (aligned & (sizeof(struct protoent_data*) - 1)))
  411.         {
  412.             aligned += sizeof(struct protoent_data*) - 1;
  413.             aligned &= ~(sizeof(struct protoent_data*) - 1);
  414.             buflen -= (aligned - (PRUptrdiff)buffer);
  415.             buffer = (char*)aligned;
  416.         }
  417.     }
  418. #endif  /* defined(_PR_HAVE_GETPROTO_R_INT) */
  419.  
  420.     PR_ASSERT(PR_NETDB_BUF_SIZE <= buflen);
  421.     if (PR_NETDB_BUF_SIZE > buflen)
  422.     {
  423.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  424.         return PR_FAILURE;
  425.     }
  426.  
  427. #if defined(_PR_HAVE_GETPROTO_R_POINTER)
  428.     if (NULL == getprotobyname_r(name, res, buffer, buflen))
  429.     {
  430.         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
  431.         return PR_FAILURE;
  432.     }
  433. #elif defined(_PR_HAVE_GETPROTO_R_INT)
  434.     /*
  435.     ** The buffer needs to be zero'd, and it should be
  436.     ** at least the size of a struct protoent_data.
  437.     */
  438.     memset(buffer, 0, buflen);
  439.     if (-1 == getprotobyname_r(name, res, (struct protoent_data*)buffer))
  440.     {
  441.         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
  442.         return PR_FAILURE;
  443.     }
  444. #elif defined(_PR_HAVE_5_ARG_GETPROTO_R)
  445.     /* The 5th argument for getprotobyname_r() cannot be NULL */
  446.     if (-1 == getprotobyname_r(name, res, buffer, buflen, &res))
  447.     {
  448.         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
  449.         return PR_FAILURE;
  450.     }
  451. #else  /* do it the hard way */
  452.     {
  453.         struct protoent *staticBuf;
  454.         PR_Lock(_getproto_lock);
  455.         staticBuf = getprotobyname_r(name);
  456.         if (NULL == staticBuf)
  457.         {
  458.             rv = PR_FAILURE;
  459.             PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
  460.         }
  461.         else
  462.         {
  463.             rv = CopyProtoent(staticBuf, buffer, buflen, result);
  464.             if (PR_FAILURE == rv)
  465.                 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
  466.         }
  467.         PR_Unlock(_getproto_lock);
  468.     }
  469. #endif  /* all that */
  470.     return rv;
  471. }
  472.  
  473. PR_IMPLEMENT(PRStatus) PR_GetProtoByNumber(
  474.     PRInt32 number, char* buffer, PRInt32 buflen, PRProtoEnt* result)
  475. {
  476.     PRStatus rv = PR_SUCCESS;
  477.     struct protoent* res = (struct protoent*)result;
  478.  
  479.     if (!_pr_initialized) _PR_ImplicitInitialization();
  480.  
  481. #if defined(_PR_HAVE_GETPROTO_R_INT)
  482.     {
  483.         /*
  484.         ** The protoent_data has a pointer as the first field.
  485.         ** That implies the buffer better be aligned, and char*
  486.         ** doesn't promise much.
  487.         */
  488.         PRUptrdiff aligned = (PRUptrdiff)buffer;
  489.         if (0 != (aligned & (sizeof(struct protoent_data*) - 1)))
  490.         {
  491.             aligned += sizeof(struct protoent_data*) - 1;
  492.             aligned &= ~(sizeof(struct protoent_data*) - 1);
  493.             buflen -= (aligned - (PRUptrdiff)buffer);
  494.             buffer = (char*)aligned;
  495.         }
  496.     }
  497. #endif /* defined(_PR_HAVE_GETPROTO_R_INT) */
  498.  
  499.     PR_ASSERT(PR_NETDB_BUF_SIZE <= buflen);
  500.     if (PR_NETDB_BUF_SIZE > buflen)
  501.     {
  502.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  503.         return PR_FAILURE;
  504.     }
  505.  
  506. #if defined(_PR_HAVE_GETPROTO_R_POINTER)
  507.     if (NULL == getprotobynumber_r(number, res, buffer, buflen))
  508.     {
  509.         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
  510.         return PR_FAILURE;
  511.     }
  512.  
  513. #elif defined(_PR_HAVE_GETPROTO_R_INT)
  514.     /*
  515.     ** The buffer needs to be zero'd for these OS's.
  516.     */
  517.     memset(buffer, 0, buflen);
  518.     if (-1 == getprotobynumber_r(number, res, (struct protoent_data*)buffer))
  519.     {
  520.         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
  521.         return PR_FAILURE;
  522.     }
  523. #elif defined(_PR_HAVE_5_ARG_GETPROTO_R)
  524.     /* The 5th argument for getprotobynumber_r() cannot be NULL */
  525.     if (-1 == getprotobynumber_r(number, res, buffer, buflen, &res))
  526.     {
  527.         PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
  528.         return PR_FAILURE;
  529.     }
  530. #else  /* do it the hard way */
  531.     {
  532.         struct protoent *staticBuf;
  533.         PR_Lock(_getproto_lock);
  534.         staticBuf = getprotobynumber_r(number);
  535.         if (NULL == staticBuf)
  536.         {
  537.             rv = PR_FAILURE;
  538.             PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO());
  539.         }
  540.         else
  541.         {
  542.             rv = CopyProtoent(staticBuf, buffer, buflen, result);
  543.             if (PR_FAILURE == rv)
  544.                 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
  545.         }
  546.         PR_Unlock(_getproto_lock);
  547.     }
  548. #endif  /* all that crap */
  549.     return rv;
  550.  
  551. }
  552.  
  553. PR_IMPLEMENT(PRUintn) PR_NetAddrSize(const PRNetAddr* addr)
  554. {
  555.     PRUintn addrsize;
  556.  
  557. #if defined(_PR_INET6)
  558.  
  559.     if ((AF_INET == (0x00ff & addr->raw.family))
  560.     || (AF_INET == (0x00ff & ntohs(addr->raw.family))))
  561.         addrsize = sizeof(struct sockaddr_in);
  562.     else if ((AF_INET6 == (0x00ff & addr->raw.family))
  563.     || (AF_INET6 == (0x00ff & ntohs(addr->raw.family))))
  564.         addrsize = sizeof(struct sockaddr_in6);
  565.     else addrsize = 0;
  566.  
  567. #else /* defined(_PR_INET6) */
  568.     
  569. #if defined(XP_MAC)
  570. #pragma unused (addr)
  571. #endif
  572.  
  573.     addrsize = sizeof(struct sockaddr_in);
  574.  
  575. #endif  /* defined(_PR_INET6) */
  576.  
  577.     return addrsize;
  578. }  /* PR_NetAddrSize */
  579.  
  580. PR_IMPLEMENT(PRIntn) PR_EnumerateHostEnt(
  581.     PRIntn enumIndex, const PRHostEnt *hostEnt, PRUint16 port, PRNetAddr *address)
  582. {
  583.     void *addr = hostEnt->h_addr_list[enumIndex++];
  584.     memset(address, 0, sizeof(PRNetAddr));
  585.     if (NULL == addr) enumIndex = 0;
  586.     else
  587.     {
  588. #if defined(_PR_INET6)
  589.         if (_pr_ipv6_enabled)
  590.         {
  591.             address->ipv6.family = AF_INET6;
  592.             address->ipv6.port = htons(port);
  593.             if (AF_INET6 == hostEnt->h_addrtype)
  594.                 memcpy(&address->ipv6.ip, addr, hostEnt->h_length);
  595.             else
  596.             {
  597.                 unsigned char *start = (unsigned char *) &address->ipv6.ip;
  598.                 PR_ASSERT(AF_INET == hostEnt->h_addrtype);
  599.                 memset(start, 0, 10);
  600.                 memset(start + 10, 0xff, 2);
  601.                 memcpy(start + 12, addr, hostEnt->h_length);
  602.                 PR_ASSERT(IN6_IS_ADDR_V4MAPPED(&address->ipv6.ip));
  603.             }
  604.         }
  605.         else
  606. #endif /* defined(_PR_INET6) */
  607.         {
  608.             PR_ASSERT(AF_INET == hostEnt->h_addrtype);
  609.             address->inet.family = hostEnt->h_addrtype;
  610.             address->inet.port = htons(port);
  611.             memcpy(&address->inet.ip, addr, hostEnt->h_length);
  612.         }
  613.     }
  614.     return enumIndex;
  615. }  /* PR_EnumerateHostEnt */
  616.  
  617. PR_IMPLEMENT(PRStatus) PR_InitializeNetAddr(
  618.     PRNetAddrValue val, PRUint16 port, PRNetAddr *addr)
  619. {
  620.     PRStatus rv = PR_SUCCESS;
  621.     if (!_pr_initialized) _PR_ImplicitInitialization();
  622.  
  623. #if defined(_PR_INET6)
  624.     if (_pr_ipv6_enabled)
  625.     {
  626.         addr->ipv6.family = AF_INET6;
  627.         addr->ipv6.port = htons(port);
  628.         switch (val)
  629.         {
  630.         case PR_IpAddrNull:
  631.             break;  /* don't overwrite the address */
  632.         case PR_IpAddrAny:
  633.             addr->ipv6.ip = in6addr_any;
  634.             break;
  635.         case PR_IpAddrLoopback:
  636.             addr->ipv6.ip = in6addr_loopback;
  637.             break;
  638.         default:
  639.             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  640.             rv = PR_FAILURE;
  641.         }
  642.     }
  643.     else
  644. #endif  /* defined(_PR_INET6) */
  645.     {
  646.         addr->inet.family = AF_INET;
  647.         addr->inet.port = htons(port);
  648.         switch (val)
  649.         {
  650.         case PR_IpAddrNull:
  651.             break;  /* don't overwrite the address */
  652.         case PR_IpAddrAny:
  653.             addr->inet.ip = htonl(INADDR_ANY);
  654.             break;
  655.         case PR_IpAddrLoopback:
  656.             addr->inet.ip = htonl(INADDR_LOOPBACK);
  657.             break;
  658.         default:
  659.             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  660.             rv = PR_FAILURE;
  661.         }
  662.     }
  663.     return rv;
  664. }  /* PR_InitializeNetAddr */
  665.  
  666. PR_IMPLEMENT(PRNetAddr*) PR_CreateNetAddr(PRNetAddrValue val, PRUint16 port)
  667. {
  668.     PRNetAddr *addr = NULL;
  669.     if ((PR_IpAddrAny == val) || (PR_IpAddrLoopback == val))
  670.     {
  671.         addr = PR_NEWZAP(PRNetAddr);
  672.         if (NULL == addr)
  673.             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  674.         else
  675.             if (PR_FAILURE == PR_InitializeNetAddr(val, port, addr))
  676.                 PR_DELETE(addr);  /* and that will make 'addr' == NULL */
  677.     }
  678.     else
  679.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  680.     return addr;
  681. }  /* PR_CreateNetAddr */
  682.  
  683. PR_IMPLEMENT(PRStatus) PR_DestroyNetAddr(PRNetAddr *addr)
  684. {
  685.     PR_Free(addr);
  686.     return PR_SUCCESS;
  687. }  /* PR_DestroyNetAddr */
  688.  
  689. PR_IMPLEMENT(PRStatus) PR_StringToNetAddr(const char *string, PRNetAddr *addr)
  690. {
  691.     /*
  692.     ** If we're built to support IPv6 addressing AND it's currently enabled,
  693.     ** then all addresses are of the IPv6 addressing family. Both are required
  694.     ** before anything overt happens.
  695.     */
  696.     PRStatus status = PR_InitializeNetAddr(PR_IpAddrNull, 0, addr);
  697.  
  698.     PR_ASSERT(PR_SUCCESS == status);
  699.     if (PR_SUCCESS != status) return status;
  700.  
  701. #if defined(_PR_INET6)
  702.  
  703.     if (_pr_ipv6_enabled)
  704.     {
  705.         /*
  706.         ** Okay, we're doing it.
  707.         */
  708.         PRIntn rv = inet_pton(AF_INET6, string, &addr->ipv6.ip);
  709.         if (1 != rv)
  710.         {
  711.             /*
  712.              * rv is 0 if the string argument is not a valid IPv4 or IPv6
  713.              * address string.
  714.              * rv is -1 with errno set to EADNOSUPPORT if the af argument is
  715.              * not a known address family.
  716.              */
  717.             PRIntn syserrno = (-1 == rv) ? errno : 0;
  718.             PR_SetError(PR_INVALID_ARGUMENT_ERROR, syserrno);
  719.             status = PR_FAILURE;
  720.         }
  721.     }
  722.     else
  723. #endif
  724.     {
  725.         PRUint32 *ip = (PRUint32*)&addr->inet.ip;
  726.  
  727.         *ip = inet_addr(string);
  728.         if ((PRUint32) -1 == *ip)
  729.         {
  730.             /*
  731.              * Either the af argument is not AF_INET, or the string argument
  732.              * is a malformed address string.
  733.              */
  734.             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  735.             status = PR_FAILURE;
  736.         }
  737.     }
  738.  
  739.     return status;
  740. }
  741.  
  742. PR_IMPLEMENT(PRStatus) PR_NetAddrToString(
  743.     const PRNetAddr *addr, char *string, PRUint32 size)
  744. {
  745.     PR_ASSERT(size >= 16);
  746.     if (size < 16) goto failed;
  747.  
  748. #if defined(_PR_INET6)
  749.     if (_pr_ipv6_enabled)
  750.     {
  751.         PR_ASSERT(AF_INET6 == addr->ipv6.family);
  752.         if ((AF_INET6 != addr->ipv6.family)
  753.         || (NULL == inet_ntop(AF_INET6, &addr->ipv6.ip, string, size)))
  754.             goto failed;
  755.     }
  756.     else
  757. #endif  /* defined(_PR_INET6) */
  758.     {
  759.         PR_ASSERT(AF_INET == addr->inet.family);
  760.         if (AF_INET != addr->inet.family) goto failed;
  761.         else
  762.         {
  763.             unsigned char *byte = (unsigned char*)&addr->inet.ip;
  764.             PR_snprintf(string, size, "%u.%u.%u.%u",
  765.                 byte[0], byte[1], byte[2], byte[3]);
  766.         }
  767.     }
  768.  
  769.     return PR_SUCCESS;
  770.  
  771. failed:
  772.     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  773.     return PR_FAILURE;
  774.  
  775. }  /* PR_NetAddrToString */
  776.  
  777. PR_IMPLEMENT(PRUint16) PR_ntohs(PRUint16 n) { return ntohs(n); }
  778. PR_IMPLEMENT(PRUint32) PR_ntohl(PRUint32 n) { return ntohl(n); }
  779. PR_IMPLEMENT(PRUint16) PR_htons(PRUint16 n) { return htons(n); }
  780. PR_IMPLEMENT(PRUint32) PR_htonl(PRUint32 n) { return htonl(n); }
  781. PR_IMPLEMENT(PRUint64) PR_ntohll(PRUint64 n)
  782. {
  783.     /*
  784.     ** There is currently no attempt to optomize out depending
  785.     ** on the host' byte order. That would be easy enough to
  786.     ** do.
  787.     */
  788.     PRUint64 tmp;
  789.     PRUint32 hi, lo;
  790.     LL_L2UI(lo, n);
  791.     LL_SHR(tmp, n, 32);
  792.     LL_L2UI(hi, tmp);
  793.     hi = PR_ntohl(hi);
  794.     lo = PR_ntohl(lo);
  795.     LL_UI2L(n, hi);
  796.     LL_SHL(n, n, 32);
  797.     LL_UI2L(tmp, lo);
  798.     LL_ADD(n, n, tmp);
  799.     return n;
  800. }  /* ntohll */
  801.  
  802. PR_IMPLEMENT(PRUint64) PR_htonll(PRUint64 n)
  803. {
  804.     /*
  805.     ** There is currently no attempt to optomize out depending
  806.     ** on the host' byte order. That would be easy enough to
  807.     ** do.
  808.     */
  809.     PRUint64 tmp;
  810.     PRUint32 hi, lo;
  811.     LL_L2UI(lo, n);
  812.     LL_SHR(tmp, n, 32);
  813.     LL_L2UI(hi, tmp);
  814.     hi = htonl(hi);
  815.     lo = htonl(lo);
  816.     LL_UI2L(n, hi);
  817.     LL_SHL(n, n, 32);
  818.     LL_UI2L(tmp, lo);
  819.     LL_ADD(n, n, tmp);
  820.     return n;
  821. }  /* htonll */
  822.  
  823. PR_IMPLEMENT(PRUint16) PR_FamilyInet(void)
  824. {
  825. #ifdef _PR_INET6
  826.     return (_pr_ipv6_enabled ? AF_INET6 : AF_INET);
  827. #else
  828.     return AF_INET;
  829. #endif
  830. }
  831.