Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/config/external/nspr/pr/./../../../../../nsprpub/pr/src/misc/prnetdb.c
Warning:line 2612, column 14
Value stored to 'md_af' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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