/* * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 in the LICENSE file that * accompanied this code). * * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions.
*/ #include <dlfcn.h> #include <errno.h> #include <net/if.h> #include <netinet/tcp.h> // defines TCP_NODELAY #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> #include <sys/time.h>
fd = socket(AF_INET6, SOCK_STREAM, 0) ; if (fd < 0) { /* * TODO: We really can't tell since it may be an unrelated error * for now we will assume that AF_INET6 is not available
*/ return JNI_FALSE;
}
/* * If fd 0 is a socket it means we may have been launched from inetd or * xinetd. If it's a socket then check the family - if it's an * IPv4 socket then we need to disable IPv6.
*/ if (getsockname(0, &sa.sa, &sa_len) == 0) { if (sa.sa.sa_family == AF_INET) {
close(fd); return JNI_FALSE;
}
}
/** * Linux - check if any interface has an IPv6 address. * Don't need to parse the line - we just need an indication.
*/ #ifdef __linux__
{
FILE *fP = fopen("/proc/net/if_inet6", "r"); char buf[255]; char *bufP;
/* * OK we may have the stack available in the kernel, * we should also check if the APIs are available.
*/
ipv6_fn = JVM_FindLibraryEntry(RTLD_DEFAULT, "inet_pton");
close(fd); if (ipv6_fn == NULL ) { return JNI_FALSE;
} else { return JNI_TRUE;
}
} #endif/* DONT_ENABLE_IPV6 */
jint reuseport_supported(int ipv6_available)
{ /* Do a simple dummy call, and try to figure out from that */ int one = 1; int rv, s; if (ipv6_available) {
s = socket(PF_INET6, SOCK_STREAM, 0);
} else {
s = socket(PF_INET, SOCK_STREAM, 0);
} if (s < 0) { return JNI_FALSE;
}
rv = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (void *)&one, sizeof(one)); if (rv != 0) {
rv = JNI_FALSE;
} else {
rv = JNI_TRUE;
}
close(s); return rv;
}
void NET_ThrowUnknownHostExceptionWithGaiError(JNIEnv *env, constchar* hostname, int gai_error)
{ int size; char *buf; constchar *format = "%s: %s"; constchar *error_string = gai_strerror(gai_error); if (error_string == NULL)
error_string = "unknown error";
size = strlen(format) + strlen(hostname) + strlen(error_string) + 2;
buf = (char *) malloc(size); if (buf) {
jstring s;
sprintf(buf, format, hostname, error_string);
s = JNU_NewStringPlatform(env, buf); if (s != NULL) {
jobject x = JNU_NewObjectByName(env, "java/net/UnknownHostException", "(Ljava/lang/String;)V", s); if (x != NULL)
(*env)->Throw(env, x);
}
free(buf);
}
}
if (ipv6_available()) { switch (cmd) { // Different multicast options if IPv6 is enabled case java_net_SocketOptions_IP_MULTICAST_IF: case java_net_SocketOptions_IP_MULTICAST_IF2:
*level = IPPROTO_IPV6;
*optname = IPV6_MULTICAST_IF; return 0;
case java_net_SocketOptions_IP_MULTICAST_LOOP:
*level = IPPROTO_IPV6;
*optname = IPV6_MULTICAST_LOOP; return 0; #ifdefined(MACOSX) // Map IP_TOS request to IPV6_TCLASS case java_net_SocketOptions_IP_TOS:
*level = IPPROTO_IPV6;
*optname = IPV6_TCLASS; return 0; #endif
}
}
/* * Map the Java level option to the native level
*/ for (i=0; i<(int)(sizeof(opts) / sizeof(opts[0])); i++) { if (cmd == opts[i].cmd) {
*level = opts[i].level;
*optname = opts[i].optname; return 0;
}
}
/* not found */ return -1;
}
/* * Wrapper for getsockopt system routine - does any necessary * pre/post processing to deal with OS specific oddities :- * * On Linux the SO_SNDBUF/SO_RCVBUF values must be post-processed * to compensate for an incorrect value returned by the kernel.
*/ int
NET_GetSockOpt(int fd, int level, int opt, void *result, int *len)
{ int rv;
socklen_t socklen = *len;
#ifdef __linux__ /* * On Linux SO_SNDBUF/SO_RCVBUF aren't symmetric. This * stems from additional socket structures in the send * and receive buffers.
*/ if ((level == SOL_SOCKET) && ((opt == SO_SNDBUF)
|| (opt == SO_RCVBUF))) { int n = *((int *)result);
n /= 2;
*((int *)result) = n;
} #endif
/* Workaround for Mac OS treating linger value as * signed integer
*/ #ifdef MACOSX if (level == SOL_SOCKET && opt == SO_LINGER) { struct linger* to_cast = (struct linger*)result;
to_cast->l_linger = (unsignedshort)to_cast->l_linger;
} #endif return rv;
}
/* * Wrapper for setsockopt system routine - performs any * necessary pre/post processing to deal with OS specific * issue :- * * On Solaris need to limit the suggested value for SO_SNDBUF * and SO_RCVBUF to the kernel configured limit * * For IP_TOS socket option need to mask off bits as this * aren't automatically masked by the kernel and results in * an error.
*/ int
NET_SetSockOpt(int fd, int level, int opt, constvoid *arg, int len)
{
/* * IPPROTO/IP_TOS :- * 1. IPv6 on Solaris/Mac OS: * Set the TOS OR Traffic Class value to cater for * IPv6 and IPv4 scenarios. * 2. IPv6 on Linux: By default Linux ignores flowinfo * field so enable IPV6_FLOWINFO_SEND so that flowinfo * will be examined. We also set the IPv4 TOS option in this case. * 3. IPv4: set socket option based on ToS and Precedence * fields (otherwise get invalid argument)
*/ if (level == IPPROTO_IP && opt == IP_TOS) { int *iptos;
#ifdefined(__linux__) if (ipv6_available()) { int optval = 1; if (setsockopt(fd, IPPROTO_IPV6, IPV6_FLOWINFO_SEND,
(void *)&optval, sizeof(optval)) < 0) { return -1;
} /* * Let's also set the IPV6_TCLASS flag. * Linux appears to allow both IP_TOS and IPV6_TCLASS to be set * This helps in mixed environments where IPv4 and IPv6 sockets * are connecting.
*/ if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS,
arg, len) < 0) { return -1;
}
} #endif
#ifdef _AIX if (level == SOL_SOCKET) { if (opt == SO_SNDBUF || opt == SO_RCVBUF) { /* * Just try to set the requested size. If it fails we will leave the * socket option as is. Setting the buffer size means only a hint in * the jse2/java software layer, see javadoc. In the previous * solution the buffer has always been truncated to a length of * 0x100000 Byte, even if the technical limit has not been reached. * This kind of absolute truncation was unexpected in the jck tests.
*/ int ret = setsockopt(fd, level, opt, arg, len); if ((ret == 0) || (ret == -1 && errno == ENOBUFS)) { // Accept failure because of insufficient buffer memory resources. return 0;
} else { // Deliver all other kinds of errors. return ret;
}
}
} #endif
/* * On Linux the receive buffer is used for both socket * structures and the packet payload. The implication * is that if SO_RCVBUF is too small then small packets * must be discarded.
*/ #ifdef __linux__ if (level == SOL_SOCKET && opt == SO_RCVBUF) { int *bufsize = (int *)arg; if (*bufsize < 1024) {
*bufsize = 1024;
}
} #endif
#ifdefined(_ALLBSD_SOURCE) /* * SOL_SOCKET/{SO_SNDBUF,SO_RCVBUF} - On FreeBSD need to * ensure that value is <= kern.ipc.maxsockbuf as otherwise we get * an ENOBUFS error.
*/ if (level == SOL_SOCKET) { if (opt == SO_SNDBUF || opt == SO_RCVBUF) { #ifdef KIPC_MAXSOCKBUF if (maxsockbuf == -1) {
mib[0] = CTL_KERN;
mib[1] = KERN_IPC;
mib[2] = KIPC_MAXSOCKBUF;
rlen = sizeof(maxsockbuf); if (sysctl(mib, 3, &maxsockbuf, &rlen, NULL, 0) == -1)
maxsockbuf = 1024;
#if 1 /* XXXBSD: This is a hack to workaround mb_max/mb_max_adj problem. It should be removed when kern.ipc.maxsockbuf
will be real value. */
maxsockbuf = (maxsockbuf/5)*4; #endif
} #elifdefined(__OpenBSD__)
maxsockbuf = SB_MAX; #else
maxsockbuf = 64 * 1024; /* XXX: NetBSD */ #endif
#ifdefined(_ALLBSD_SOURCE) || defined(_AIX) /* * On Solaris, SO_REUSEADDR will allow multiple datagram * sockets to bind to the same port. The network jck tests check * for this "feature", so we need to emulate it by turning on * SO_REUSEPORT as well for that combination.
*/ if (level == SOL_SOCKET && opt == SO_REUSEADDR) { int sotype;
socklen_t arglen;
/* * Wrapper for bind system call - performs any necessary pre/post * processing to deal with OS specific issues :- * * Linux allows a socket to bind to 127.0.0.255 which must be * caught.
*/ int
NET_Bind(int fd, SOCKETADDRESS *sa, int len)
{ int rv;
#ifdef __linux__ /* * ## get bugId for this issue - goes back to 1.2.2 port ## * ## When IPv6 is enabled this will be an IPv4-mapped * ## with family set to AF_INET6
*/ if (sa->sa.sa_family == AF_INET) { if ((ntohl(sa->sa4.sin_addr.s_addr) & 0x7f0000ff) == 0x7f0000ff) {
errno = EADDRNOTAVAIL; return -1;
}
} #endif
rv = bind(fd, &sa->sa, len);
return rv;
}
/** * Wrapper for poll with timeout on a single file descriptor. * * flags (defined in net_util_md.h can be any combination of * NET_WAIT_READ, NET_WAIT_WRITE & NET_WAIT_CONNECT. * * The function will return when either the socket is ready for one * of the specified operations or the timeout expired. * * It returns the time left from the timeout (possibly 0), or -1 if it expired.
*/
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.