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