📄 prnetdb.c
字号:
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Netscape Portable Runtime (NSPR). * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */#include "primpl.h"#include <string.h>/* * On Unix, the error code for gethostbyname() and gethostbyaddr() * is returned in the global variable h_errno, instead of the usual * errno. */#if defined(XP_UNIX)#if defined(_PR_NEED_H_ERRNO)extern int h_errno;#endif#define _MD_GETHOST_ERRNO() h_errno#else#define _MD_GETHOST_ERRNO() _MD_ERRNO()#endif/* * The meaning of the macros related to gethostbyname, gethostbyaddr, * and gethostbyname2 is defined below. * - _PR_HAVE_THREADSAFE_GETHOST: the gethostbyXXX functions return * the result in thread specific storage. For example, AIX, HP-UX, * and OSF1. * - _PR_HAVE_GETHOST_R: have the gethostbyXXX_r functions. See next * two macros. * - _PR_HAVE_GETHOST_R_INT: the gethostbyXXX_r functions return an * int. For example, Linux glibc. * - _PR_HAVE_GETHOST_R_POINTER: the gethostbyXXX_r functions return * a struct hostent* pointer. For example, Solaris and IRIX. */#if defined(_PR_NO_PREEMPT) || defined(_PR_HAVE_GETHOST_R) \ || defined(_PR_HAVE_THREADSAFE_GETHOST)#define _PR_NO_DNS_LOCK#endif#if defined(_PR_NO_DNS_LOCK)#define LOCK_DNS()#define UNLOCK_DNS()#elsePRLock *_pr_dnsLock = NULL;#define LOCK_DNS() PR_Lock(_pr_dnsLock)#define UNLOCK_DNS() PR_Unlock(_pr_dnsLock)#endif /* defined(_PR_NO_DNS_LOCK) *//* * Some platforms have the reentrant getprotobyname_r() and * getprotobynumber_r(). However, they come in two flavors. * Some return a pointer to struct protoent, others return * an int. */#if defined(XP_BEOS) && defined(BONE_VERSION)#include <arpa/inet.h> /* pick up define for inet_addr */#include <sys/socket.h>#define _PR_HAVE_GETPROTO_R#define _PR_HAVE_GETPROTO_R_POINTER#endif#if defined(SOLARIS) || (defined(BSDI) && defined(_REENTRANT)) \ || (defined(LINUX) && defined(_REENTRANT) \ && !(defined(__GLIBC__) && __GLIBC__ >= 2))#define _PR_HAVE_GETPROTO_R#define _PR_HAVE_GETPROTO_R_POINTER#endif#if defined(OSF1) \ || defined(AIX4_3) || (defined(AIX) && defined(_THREAD_SAFE)) \ || (defined(HPUX10_10) && defined(_REENTRANT)) \ || (defined(HPUX10_20) && defined(_REENTRANT))#define _PR_HAVE_GETPROTO_R#define _PR_HAVE_GETPROTO_R_INT#endif#if (defined(LINUX) && defined(__GLIBC__) && __GLIBC__ >= 2)#define _PR_HAVE_GETPROTO_R#define _PR_HAVE_5_ARG_GETPROTO_R#endif#if !defined(_PR_HAVE_GETPROTO_R)PRLock* _getproto_lock = NULL;#endif#if defined(_PR_INET6_PROBE)PR_EXTERN(PRBool) _pr_ipv6_is_present;#endif#define _PR_IN6_IS_ADDR_UNSPECIFIED(a) \ (((a)->pr_s6_addr32[0] == 0) && \ ((a)->pr_s6_addr32[1] == 0) && \ ((a)->pr_s6_addr32[2] == 0) && \ ((a)->pr_s6_addr32[3] == 0)) #define _PR_IN6_IS_ADDR_LOOPBACK(a) \ (((a)->pr_s6_addr32[0] == 0) && \ ((a)->pr_s6_addr32[1] == 0) && \ ((a)->pr_s6_addr32[2] == 0) && \ ((a)->pr_s6_addr[12] == 0) && \ ((a)->pr_s6_addr[13] == 0) && \ ((a)->pr_s6_addr[14] == 0) && \ ((a)->pr_s6_addr[15] == 0x1U)) const PRIPv6Addr _pr_in6addr_any = {{{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}};const PRIPv6Addr _pr_in6addr_loopback = {{{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1U }}};/* * The values at bytes 10 and 11 are compared using pointers to * 8-bit fields, and not 32-bit fields, to make the comparison work on * both big-endian and little-endian systems */#define _PR_IN6_IS_ADDR_V4MAPPED(a) \ (((a)->pr_s6_addr32[0] == 0) && \ ((a)->pr_s6_addr32[1] == 0) && \ ((a)->pr_s6_addr[8] == 0) && \ ((a)->pr_s6_addr[9] == 0) && \ ((a)->pr_s6_addr[10] == 0xff) && \ ((a)->pr_s6_addr[11] == 0xff))#define _PR_IN6_IS_ADDR_V4COMPAT(a) \ (((a)->pr_s6_addr32[0] == 0) && \ ((a)->pr_s6_addr32[1] == 0) && \ ((a)->pr_s6_addr32[2] == 0))#define _PR_IN6_V4MAPPED_TO_IPADDR(a) ((a)->pr_s6_addr32[3])#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)/* * The _pr_QueryNetIfs() function finds out if the system has * IPv4 or IPv6 source addresses configured and sets _pr_have_inet_if * and _pr_have_inet6_if accordingly. * * We have an implementation using SIOCGIFCONF ioctl and a * default implementation that simply sets _pr_have_inet_if * and _pr_have_inet6_if to true. A better implementation * would be to use the routing sockets (see Chapter 17 of * W. Richard Stevens' Unix Network Programming, Vol. 1, 2nd. Ed.) */static PRBool _pr_have_inet_if = PR_FALSE;static PRBool _pr_have_inet6_if = PR_FALSE;#undef DEBUG_QUERY_IFS#if defined(AIX)/* * Use SIOCGIFCONF ioctl on platforms that don't have routing * sockets. Warning: whether SIOCGIFCONF ioctl returns AF_INET6 * network interfaces is not portable. * * The _pr_QueryNetIfs() function is derived from the code in * src/lib/libc/net/getifaddrs.c in BSD Unix and the code in * Section 16.6 of W. Richard Stevens' Unix Network Programming, * Vol. 1, 2nd. Ed. */#include <sys/ioctl.h>#include <sys/socket.h>#include <netinet/in.h>#include <net/if.h>#ifdef DEBUG_QUERY_IFSstatic void_pr_PrintIfreq(struct ifreq *ifr){ PRNetAddr addr; struct sockaddr *sa; const char* family; char addrstr[64]; sa = &ifr->ifr_addr; if (sa->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *)sa; family = "inet"; memcpy(&addr.inet.ip, &sin->sin_addr, sizeof(sin->sin_addr)); } else if (sa->sa_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; family = "inet6"; memcpy(&addr.ipv6.ip, &sin6->sin6_addr, sizeof(sin6->sin6_addr)); } else { return; /* skip if not AF_INET or AF_INET6 */ } addr.raw.family = sa->sa_family; PR_NetAddrToString(&addr, addrstr, sizeof(addrstr)); printf("%s: %s %s\n", ifr->ifr_name, family, addrstr);}#endifstatic void_pr_QueryNetIfs(void){ int sock; int rv; struct ifconf ifc; struct ifreq *ifr; struct ifreq *lifr; PRUint32 len, lastlen; char *buf; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { return; } /* Issue SIOCGIFCONF request in a loop. */ lastlen = 0; len = 100 * sizeof(struct ifreq); /* initial buffer size guess */ for (;;) { buf = (char *)PR_Malloc(len); if (NULL == buf) { close(sock); return; } ifc.ifc_buf = buf; ifc.ifc_len = len; rv = ioctl(sock, SIOCGIFCONF, &ifc); if (rv < 0) { if (errno != EINVAL || lastlen != 0) { close(sock); PR_Free(buf); return; } } else { if (ifc.ifc_len == lastlen) break; /* success, len has not changed */ lastlen = ifc.ifc_len; } len += 10 * sizeof(struct ifreq); /* increment */ PR_Free(buf); } close(sock); ifr = ifc.ifc_req; lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len]; while (ifr < lifr) { struct sockaddr *sa; int sa_len;#ifdef DEBUG_QUERY_IFS _pr_PrintIfreq(ifr);#endif sa = &ifr->ifr_addr; if (sa->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *) sa; if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) { _pr_have_inet_if = PR_TRUE; } } else if (sa->sa_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; if (!IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) { _pr_have_inet6_if = PR_TRUE; } }#ifdef _PR_HAVE_SOCKADDR_LEN sa_len = PR_MAX(sa->sa_len, sizeof(struct sockaddr));#else switch (sa->sa_family) {#ifdef AF_LINK case AF_LINK: sa_len = sizeof(struct sockaddr_dl); break;#endif case AF_INET6: sa_len = sizeof(struct sockaddr_in6); break; default: sa_len = sizeof(struct sockaddr); break; }#endif ifr = (struct ifreq *)(((char *)sa) + sa_len); } PR_Free(buf);}#else /* default *//* * Emulate the code in NSPR 4.2 or older. PR_GetIPNodeByName behaves * as if the system had both IPv4 and IPv6 source addresses configured. */static void_pr_QueryNetIfs(void){ _pr_have_inet_if = PR_TRUE; _pr_have_inet6_if = PR_TRUE;}#endif#endif /* _PR_INET6 && _PR_HAVE_GETHOSTBYNAME2 */void _PR_InitNet(void){#if defined(XP_UNIX)#ifdef HAVE_NETCONFIG /* * This one-liner prevents the endless re-open's and re-read's of * /etc/netconfig on EACH and EVERY call to accept(), connect(), etc. */ (void)setnetconfig();#endif#endif#if !defined(_PR_NO_DNS_LOCK) _pr_dnsLock = PR_NewLock();#endif#if !defined(_PR_HAVE_GETPROTO_R) _getproto_lock = PR_NewLock();#endif#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) _pr_QueryNetIfs();#ifdef DEBUG_QUERY_IFS if (_pr_have_inet_if) printf("Have IPv4 source address\n"); if (_pr_have_inet6_if) printf("Have IPv6 source address\n");#endif#endif}void _PR_CleanupNet(void){#if !defined(_PR_NO_DNS_LOCK) if (_pr_dnsLock) { PR_DestroyLock(_pr_dnsLock); _pr_dnsLock = NULL; }#endif#if !defined(_PR_HAVE_GETPROTO_R) if (_getproto_lock) { PR_DestroyLock(_getproto_lock); _getproto_lock = NULL; }#endif}/*** Allocate space from the buffer, aligning it to "align" before doing** the allocation. "align" must be a power of 2.*/static char *Alloc(PRIntn amount, char **bufp, PRIntn *buflenp, PRIntn align){ char *buf = *bufp; PRIntn buflen = *buflenp; if (align && ((long)buf & (align - 1))) { PRIntn skip = align - ((ptrdiff_t)buf & (align - 1)); if (buflen < skip) { return 0; } buf += skip; buflen -= skip; } if (buflen < amount) { return 0; } *bufp = buf + amount; *buflenp = buflen - amount; return buf;}typedef enum _PRIPAddrConversion { _PRIPAddrNoConversion, _PRIPAddrIPv4Mapped, _PRIPAddrIPv4Compat} _PRIPAddrConversion;/*** Convert an IPv4 address (v4) to an IPv4-mapped IPv6 address (v6).*/static void MakeIPv4MappedAddr(const char *v4, char *v6){ memset(v6, 0, 10); memset(v6 + 10, 0xff, 2); memcpy(v6 + 12, v4, 4);}/*** Convert an IPv4 address (v4) to an IPv4-compatible IPv6 address (v6).*/static void MakeIPv4CompatAddr(const char *v4, char *v6){ memset(v6, 0, 12); memcpy(v6 + 12, v4, 4);}/*** Copy a hostent, and all of the memory that it refers to into** (hopefully) stacked buffers.*/static PRStatus CopyHostent( struct hostent *from, char **buf, PRIntn *bufsize, _PRIPAddrConversion conversion, PRHostEnt *to){ PRIntn len, na; char **ap;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -