comparison nspr/pr/src/misc/prnetdb.c @ 0:1e5118fa0cb1

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