nsprpub/pr/src/misc/prnetdb.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial