net_util_md.c
来自「This is a resource based on j2me embedde」· C语言 代码 · 共 1,305 行 · 第 1/3 页
C
1,305 行
/* * @(#)net_util_md.c 1.14 06/10/13 * * Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. * */#include <errno.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/tcp.h> /* Defines TCP_NODELAY, needed for 2.6 */#include <netinet/in.h>#include <net/if.h>#include <netdb.h>#include <stdlib.h>#include <dlfcn.h>#ifdef __linux__#include <arpa/inet.h>#include <net/route.h>#include <sys/utsname.h>#ifndef IPV6_FLOWINFO_SEND#define IPV6_FLOWINFO_SEND 33#endif#endif#include "jni_util.h"#include "jvm.h"#include "net_util.h"#include "java_net_InetAddress.h"#include "java_net_Inet4Address.h"#include "java_net_Inet6Address.h"#include "java_net_SocketOptions.h"/* needed from libsocket on Solaris 8 */getaddrinfo_f getaddrinfo_ptr = NULL;freeaddrinfo_f freeaddrinfo_ptr = NULL;getnameinfo_f getnameinfo_ptr = NULL;/* * EXCLBIND socket options only on Solaris 8 & 9. */#if defined(__solaris__) && !defined(TCP_EXCLBIND)#define TCP_EXCLBIND 0x21#endif#if defined(__solaris__) && !defined(UDP_EXCLBIND)#define UDP_EXCLBIND 0x0101#endif#ifdef __solaris__static int init_max_buf;static int tcp_max_buf;static int udp_max_buf;/* * Get the specified parameter from the specified driver. The value * of the parameter is assumed to be an 'int'. If the parameter * cannot be obtained return the specified default value. */static int getParam(char *driver, char *param, int dflt){ struct strioctl stri; char buf [64]; int s; int value; s = open (driver, O_RDWR); if (s < 0) { return dflt; } strncpy (buf, param, sizeof(buf)); stri.ic_cmd = ND_GET; stri.ic_timout = 0; stri.ic_dp = buf; stri.ic_len = sizeof(buf); if (ioctl (s, I_STR, &stri) < 0) { value = dflt; } else { value = atoi(buf); } close (s); return value;}#endif#ifdef __linux__static int kernelV22 = 0;static int vinit = 0;int kernelIsV22 () { if (!vinit) { struct utsname sysinfo; if (uname(&sysinfo) == 0) { sysinfo.release[3] = '\0'; if (strcmp(sysinfo.release, "2.2") == 0) { kernelV22 = JNI_TRUE; } } vinit = 1; } return kernelV22;}static int kernelV24 = 0;static int vinit24 = 0;int kernelIsV24 () { if (!vinit24) { struct utsname sysinfo; if (uname(&sysinfo) == 0) { sysinfo.release[3] = '\0'; if (strcmp(sysinfo.release, "2.4") == 0) { kernelV24 = JNI_TRUE; } } vinit24 = 1; } return kernelV24;}#endif#include "jni_statics.h"int initialized = 0;void init(JNIEnv *env) { if (!initialized) { Java_java_net_InetAddress_init(env, 0); Java_java_net_Inet4Address_init(env, 0); Java_java_net_Inet6Address_init(env, 0); initialized = 1; }}voidNET_ThrowByNameWithLastError(JNIEnv *env, const char *name, const char *defaultDetail) { char errmsg[255]; sprintf(errmsg, "errno: %d, error: %s\n", errno, defaultDetail); JNU_ThrowByNameWithLastError(env, name, errmsg); }void NET_ThrowCurrent(JNIEnv *env, char *msg) { NET_ThrowNew(env, errno, msg);}voidNET_ThrowNew(JNIEnv *env, int errorNumber, char *msg) { char fullMsg[512]; if (!msg) { msg = "no further information"; } switch(errorNumber) { case EBADF: jio_snprintf(fullMsg, sizeof(fullMsg), "socket closed: %s", msg); JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", fullMsg); break; case EINTR: JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", msg); break; default: errno = errorNumber; JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", msg); break; }}jfieldIDNET_GetFileDescriptorID(JNIEnv *env){ jclass cls = (*env)->FindClass(env, "java/io/FileDescriptor"); CHECK_NULL_RETURN(cls, NULL); return (*env)->GetFieldID(env, cls, "fd", "I");}jint IPv6_supported(){#ifndef AF_INET6 return JNI_FALSE;#endif#ifdef AF_INET6 int fd; void *ipv6_fn; fd = JVM_Socket(AF_INET6, SOCK_STREAM, 0) ; if (fd < 0) { /* * TODO: We really cant tell since it may be an unrelated error * for now we will assume that AF_INET6 is not available */ return JNI_FALSE; } /** * Linux - check if any interface has an IPv6 address. * Don't need to parse the line - we just need an indication. */ { FILE *fP = fopen("/proc/net/if_inet6", "r"); char buf[255]; char *bufP; if (fP == NULL) { close(fd); return JNI_FALSE; } bufP = fgets(buf, sizeof(buf), fP); fclose(fP); if (bufP == NULL) { close(fd); return JNI_FALSE; } } /** * On Solaris 8 it's possible to create INET6 sockets even * though IPv6 is not enabled on all interfaces. Thus we * query the number of IPv6 addresses to verify that IPv6 * has been configured on at least one interface. * * On Linux it doesn't matter - if IPv6 is built-in the * kernel then IPv6 addresses will be bound automatically * to all interfaces. */#endif /* AF_INET6 */ /* * OK we may have the stack available in the kernel, * we should also check if the APIs are available. */ ipv6_fn = dlsym(RTLD_DEFAULT, "inet_pton"); if (ipv6_fn == NULL ) { close(fd); return JNI_FALSE; } /* * We've got the library, let's get the pointers to some * IPV6 specific functions. We have to do that because, at least * on Solaris we may build on a system without IPV6 networking * libraries, therefore we can't have a hard link to these * functions. */ getaddrinfo_ptr = (getaddrinfo_f) dlsym(RTLD_DEFAULT, "getaddrinfo"); freeaddrinfo_ptr = (freeaddrinfo_f) dlsym(RTLD_DEFAULT, "freeaddrinfo"); getnameinfo_ptr = (getnameinfo_f) dlsym(RTLD_DEFAULT, "getnameinfo"); if (freeaddrinfo_ptr == NULL || getnameinfo_ptr == NULL) { /* We need all 3 of them */ getaddrinfo_ptr = NULL; } close(fd); return JNI_TRUE; }void NET_AllocSockaddr(struct sockaddr **him, int *len) {#ifdef AF_INET6 if (ipv6_available()) { struct sockaddr_in6 *him6 = (struct sockaddr_in6*)malloc(sizeof(struct sockaddr_in6)); *him = (struct sockaddr*)him6; *len = sizeof(struct sockaddr_in6); } else#endif /* AF_INET6 */ { struct sockaddr_in *him4 = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in)); *him = (struct sockaddr*)him4; *len = sizeof(struct sockaddr_in); }}#if defined(__linux__) && defined(AF_INET6)/* following code creates a list of addresses from the kernel * routing table that are routed via the loopback address. * We check all destination addresses against this table * and override the scope_id field to use the relevant value for "lo" * in order to work-around the Linux bug that prevents packets destined * for certain local addresses from being sent via a physical interface. */struct loopback_route { struct in6_addr addr; /* destination address */ int plen; /* prefix length */};static struct loopback_route *loRoutes = 0;static int nRoutes = 0; /* number of routes */static int loRoutes_size = 16; /* initial size */static int lo_scope_id = 0;static void initLoopbackRoutes();void printAddr (struct in6_addr *addr) { int i; for (i=0; i<16; i++) { printf ("%02x", addr->s6_addr[i]); } printf ("\n");} static void initLoopbackRoutes() { FILE *f; char srcp[8][5]; char hopp[8][5]; int dest_plen, src_plen, use, refcnt, metric; unsigned long flags; char dest_str[40]; struct in6_addr dest_addr; char device[16]; if (loRoutes != 0) { free (loRoutes); } loRoutes = calloc (loRoutes_size, sizeof(struct loopback_route)); if (loRoutes == 0) { return; } /* * Scan /proc/net/ipv6_route looking for a matching * route. */ if ((f = fopen("/proc/net/ipv6_route", "r")) == NULL) { return ; } while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x " "%4s%4s%4s%4s%4s%4s%4s%4s %02x " "%4s%4s%4s%4s%4s%4s%4s%4s " "%08x %08x %08x %08lx %8s", dest_str, &dest_str[5], &dest_str[10], &dest_str[15], &dest_str[20], &dest_str[25], &dest_str[30], &dest_str[35], &dest_plen, srcp[0], srcp[1], srcp[2], srcp[3], srcp[4], srcp[5], srcp[6], srcp[7], &src_plen, hopp[0], hopp[1], hopp[2], hopp[3], hopp[4], hopp[5], hopp[6], hopp[7], &metric, &use, &refcnt, &flags, device) == 31) { /* * Some routes should be ignored */ if ( (dest_plen < 0 || dest_plen > 128) || (src_plen != 0) || (flags & (RTF_POLICY | RTF_FLOW)) || ((flags & RTF_REJECT) && dest_plen == 0) ) { continue; } /* * Convert the destination address */ dest_str[4] = ':'; dest_str[9] = ':'; dest_str[14] = ':'; dest_str[19] = ':'; dest_str[24] = ':'; dest_str[29] = ':'; dest_str[34] = ':'; dest_str[39] = '\0'; if (inet_pton(AF_INET6, dest_str, &dest_addr) < 0) { /* not an Ipv6 address */ continue; } if (strcmp(device, "lo") != 0) { /* Not a loopback route */ continue; } else { if (nRoutes == loRoutes_size) { loRoutes = realloc (loRoutes, loRoutes_size * sizeof (struct loopback_route) * 2); if (loRoutes == 0) { return ; } loRoutes_size *= 2; } memcpy (&loRoutes[nRoutes].addr,&dest_addr,sizeof(struct in6_addr)); loRoutes[nRoutes].plen = dest_plen; nRoutes ++; } } fclose (f); { /* now find the scope_id for "lo" */ char devname[20]; char addr6p[8][5]; int plen, scope, dad_status, if_idx; if ((f = fopen("/proc/net/if_inet6", "r")) != NULL) { while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n", addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope, &dad_status, devname) == 13) { if (strcmp(devname, "lo") == 0) { /* * Found - so just return the index
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?