8284890: Support for Do not fragment IP socket options
Reviewed-by: erikj, ihse, dfuchs
This commit is contained in:
parent
a7b5157375
commit
67755edd6f
make/modules/jdk.net
src
java.base/share/classes/sun/net/ext
jdk.net
linux
macosx
share/classes/jdk/net
windows
test/jdk
@ -27,7 +27,7 @@ include LibCommon.gmk
|
||||
|
||||
################################################################################
|
||||
|
||||
ifeq ($(call isTargetOs, linux macosx), true)
|
||||
ifeq ($(call isTargetOs, linux macosx windows), true)
|
||||
|
||||
$(eval $(call SetupJdkLibrary, BUILD_LIBEXTNET, \
|
||||
NAME := extnet, \
|
||||
@ -35,8 +35,9 @@ ifeq ($(call isTargetOs, linux macosx), true)
|
||||
CFLAGS := $(CFLAGS_JDKLIB), \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||
LIBS := -ljava, \
|
||||
LIBS_unix := -ljava, \
|
||||
LIBS_linux := -ljvm, \
|
||||
LIBS_windows := jvm.lib ws2_32.lib $(WIN_JAVA_LIB), \
|
||||
))
|
||||
|
||||
$(BUILD_LIBEXTNET): $(call FindLib, java.base, java)
|
||||
|
@ -108,7 +108,8 @@ public abstract class ExtendedSocketOptions {
|
||||
}
|
||||
|
||||
private static boolean isStreamOption(SocketOption<?> option, boolean server) {
|
||||
if (option.name().startsWith("UDP_") || isUnixDomainOption(option)) {
|
||||
if (option.name().startsWith("UDP_") || isUnixDomainOption(option)
|
||||
|| option.name().equals("IP_DONTFRAGMENT")) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
|
@ -102,6 +102,16 @@ class LinuxSocketOptions extends PlatformSocketOptions {
|
||||
return getIncomingNapiId0(fd);
|
||||
}
|
||||
|
||||
@Override
|
||||
void setIpDontFragment(int fd, final boolean value) throws SocketException {
|
||||
setIpDontFragment0(fd, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean getIpDontFragment(int fd) throws SocketException {
|
||||
return getIpDontFragment0(fd);
|
||||
}
|
||||
|
||||
@Override
|
||||
UnixDomainPrincipal getSoPeerCred(int fd) throws SocketException {
|
||||
long l = getSoPeerCred0(fd);
|
||||
@ -115,9 +125,11 @@ class LinuxSocketOptions extends PlatformSocketOptions {
|
||||
private static native void setTcpkeepAliveProbes0(int fd, int value) throws SocketException;
|
||||
private static native void setTcpKeepAliveTime0(int fd, int value) throws SocketException;
|
||||
private static native void setTcpKeepAliveIntvl0(int fd, int value) throws SocketException;
|
||||
private static native void setIpDontFragment0(int fd, boolean value) throws SocketException;
|
||||
private static native int getTcpkeepAliveProbes0(int fd) throws SocketException;
|
||||
private static native int getTcpKeepAliveTime0(int fd) throws SocketException;
|
||||
private static native int getTcpKeepAliveIntvl0(int fd) throws SocketException;
|
||||
private static native boolean getIpDontFragment0(int fd) throws SocketException;
|
||||
private static native void setQuickAck0(int fd, boolean on) throws SocketException;
|
||||
private static native boolean getQuickAck0(int fd) throws SocketException;
|
||||
private static native long getSoPeerCred0(int fd) throws SocketException;
|
||||
|
@ -243,3 +243,65 @@ JNIEXPORT jint JNICALL Java_jdk_net_LinuxSocketOptions_getIncomingNapiId0
|
||||
handleError(env, rv, "get option SO_INCOMING_NAPI_ID failed");
|
||||
return optval;
|
||||
}
|
||||
|
||||
static int socketFamily(jint fd) {
|
||||
struct sockaddr_storage st;
|
||||
struct sockaddr *sa = (struct sockaddr *)&st;
|
||||
socklen_t sa_len = sizeof(st);
|
||||
|
||||
if (getsockname(fd, sa, &sa_len) == 0) {
|
||||
return sa->sa_family;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: jdk_net_LinuxSocketOptions
|
||||
* Method: setIpDontFragment0
|
||||
* Signature: (IZ)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_jdk_net_LinuxSocketOptions_setIpDontFragment0
|
||||
(JNIEnv *env, jobject unused, jint fd, jboolean optval) {
|
||||
jint rv, optsetting;
|
||||
jint family = socketFamily(fd);
|
||||
if (family == -1) {
|
||||
handleError(env, family, "get socket family failed");
|
||||
return;
|
||||
}
|
||||
|
||||
optsetting = optval ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
|
||||
|
||||
if (family == AF_INET) {
|
||||
rv = setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &optsetting, sizeof (optsetting));
|
||||
} else {
|
||||
rv = setsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &optsetting, sizeof (optsetting));
|
||||
}
|
||||
handleError(env, rv, "set option IP_DONTFRAGMENT failed");
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: jdk_net_LinuxSocketOptions
|
||||
* Method: getIpDontFragment0
|
||||
* Signature: (I)Z;
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_jdk_net_LinuxSocketOptions_getIpDontFragment0
|
||||
(JNIEnv *env, jobject unused, jint fd) {
|
||||
jint optlevel, optname, optval, rv;
|
||||
jint family = socketFamily(fd);
|
||||
if (family == -1) {
|
||||
handleError(env, family, "get socket family failed");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (family == AF_INET) {
|
||||
optlevel = IPPROTO_IP;
|
||||
optname = IP_MTU_DISCOVER;
|
||||
} else {
|
||||
optlevel = IPPROTO_IPV6;
|
||||
optname = IPV6_MTU_DISCOVER;
|
||||
}
|
||||
socklen_t sz = sizeof(optval);
|
||||
rv = getsockopt(fd, optlevel, optname, &optval, &sz);
|
||||
handleError(env, rv, "get option IP_DONTFRAGMENT failed");
|
||||
return optval == IP_PMTUDISC_DO ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
|
@ -78,6 +78,16 @@ class MacOSXSocketOptions extends PlatformSocketOptions {
|
||||
return getTcpKeepAliveIntvl0(fd);
|
||||
}
|
||||
|
||||
@Override
|
||||
void setIpDontFragment(int fd, final boolean value) throws SocketException {
|
||||
setIpDontFragment0(fd, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean getIpDontFragment(int fd) throws SocketException {
|
||||
return getIpDontFragment0(fd);
|
||||
}
|
||||
|
||||
@Override
|
||||
UnixDomainPrincipal getSoPeerCred(int fd) throws SocketException {
|
||||
long l = getSoPeerCred0(fd);
|
||||
@ -91,9 +101,11 @@ class MacOSXSocketOptions extends PlatformSocketOptions {
|
||||
private static native void setTcpkeepAliveProbes0(int fd, int value) throws SocketException;
|
||||
private static native void setTcpKeepAliveTime0(int fd, int value) throws SocketException;
|
||||
private static native void setTcpKeepAliveIntvl0(int fd, int value) throws SocketException;
|
||||
private static native void setIpDontFragment0(int fd, boolean value) throws SocketException;
|
||||
private static native int getTcpkeepAliveProbes0(int fd) throws SocketException;
|
||||
private static native int getTcpKeepAliveTime0(int fd) throws SocketException;
|
||||
private static native int getTcpKeepAliveIntvl0(int fd) throws SocketException;
|
||||
private static native boolean getIpDontFragment0(int fd) throws SocketException;
|
||||
private static native long getSoPeerCred0(int fd) throws SocketException;
|
||||
private static native boolean keepAliveOptionsSupported0();
|
||||
static {
|
||||
|
@ -30,7 +30,14 @@
|
||||
|
||||
#include <jni.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
#define __APPLE_USE_RFC_3542
|
||||
#include <netinet/in.h>
|
||||
|
||||
#ifndef IP_DONTFRAG
|
||||
#define IP_DONTFRAG 28
|
||||
#endif
|
||||
|
||||
#include "jni_util.h"
|
||||
|
||||
/*
|
||||
@ -170,3 +177,60 @@ JNIEXPORT jint JNICALL Java_jdk_net_MacOSXSocketOptions_getTcpKeepAliveIntvl0
|
||||
handleError(env, rv, "get option TCP_KEEPINTVL failed");
|
||||
return optval;
|
||||
}
|
||||
|
||||
static int socketFamily(jint fd) {
|
||||
struct sockaddr_storage st;
|
||||
struct sockaddr* sa = (struct sockaddr *)&st;
|
||||
socklen_t sa_len = sizeof(st);
|
||||
|
||||
if (getsockname(fd, sa, &sa_len) == 0) {
|
||||
return sa->sa_family;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: jdk_net_MacOSXSocketOptions
|
||||
* Method: setIpDontFragment0
|
||||
* Signature: (IZ)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_jdk_net_MacOSXSocketOptions_setIpDontFragment0
|
||||
(JNIEnv *env, jobject unused, jint fd, jboolean optval) {
|
||||
jint rv;
|
||||
jint family = socketFamily(fd);
|
||||
jint value = optval ? 1 : 0;
|
||||
|
||||
if (family == -1) {
|
||||
handleError(env, family, "get socket family failed");
|
||||
return;
|
||||
}
|
||||
if (family == AF_INET) {
|
||||
rv = setsockopt(fd, IPPROTO_IP, IP_DONTFRAG, &value, sizeof(value));
|
||||
} else {
|
||||
rv = setsockopt(fd, IPPROTO_IPV6, IPV6_DONTFRAG, &value, sizeof(value));
|
||||
}
|
||||
handleError(env, rv, "set option IP_DONTFRAGMENT failed");
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: jdk_net_MacOSXSocketOptions
|
||||
* Method: getIpDontFragment0
|
||||
* Signature: (I)Z;
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_jdk_net_MacOSXSocketOptions_getIpDontFragment0
|
||||
(JNIEnv *env, jobject unused, jint fd) {
|
||||
jint optval, rv;
|
||||
socklen_t sz = sizeof (optval);
|
||||
jint family = socketFamily(fd);
|
||||
if (family == -1) {
|
||||
handleError(env, family, "get socket family failed");
|
||||
return 0;
|
||||
}
|
||||
if (family == AF_INET) {
|
||||
rv = getsockopt(fd, IPPROTO_IP, IP_DONTFRAG, &optval, &sz);
|
||||
} else {
|
||||
rv = getsockopt(fd, IPPROTO_IPV6, IPV6_DONTFRAG, &optval, &sz);
|
||||
}
|
||||
handleError(env, rv, "get option IP_DONTFRAGMENT failed");
|
||||
return optval;
|
||||
}
|
||||
|
@ -199,6 +199,28 @@ public final class ExtendedSocketOptions {
|
||||
= new ExtSocketOption<UnixDomainPrincipal>
|
||||
("SO_PEERCRED", UnixDomainPrincipal.class);
|
||||
|
||||
/**
|
||||
* Disable IP packet fragmentation.
|
||||
*
|
||||
* <p> The value of this socket option is a {@code Boolean} that represents
|
||||
* whether the option is enabled or disabled. When {@code true} fragmentation
|
||||
* of outgoing IPv4 and IPv6 packets does not occur. This option can only be used
|
||||
* with datagram sockets. When set, care must be taken to limit outgoing packet
|
||||
* sizes to the {@link java.net.NetworkInterface#getMTU() local MTU}. Depending
|
||||
* on the implementation and the network interface, packets larger than the MTU
|
||||
* may be sent or dropped silently or dropped with an exception thrown.
|
||||
*
|
||||
* @apiNote
|
||||
* For IPv4 this option sets the DF (Do not Fragment) flag in the IP packet
|
||||
* header. This instructs intermediate routers to not fragment the packet.
|
||||
* IPv6 routers never fragment packets. Instead, fragmentation is handled
|
||||
* by the sending and receiving nodes exclusively. Setting this option for
|
||||
* an IPv6 socket ensures that packets to be sent are never fragmented, in
|
||||
* which case, the local network MTU must be observed.
|
||||
*/
|
||||
public static final SocketOption<Boolean> IP_DONTFRAGMENT =
|
||||
new ExtSocketOption<Boolean>("IP_DONTFRAGMENT", Boolean.class);
|
||||
|
||||
private static final PlatformSocketOptions platformSocketOptions =
|
||||
PlatformSocketOptions.get();
|
||||
|
||||
@ -210,6 +232,7 @@ public final class ExtendedSocketOptions {
|
||||
platformSocketOptions.peerCredentialsSupported();
|
||||
private static final boolean incomingNapiIdOptSupported =
|
||||
platformSocketOptions.incomingNapiIdSupported();
|
||||
|
||||
private static final Set<SocketOption<?>> extendedOptions = options();
|
||||
|
||||
static Set<SocketOption<?>> options() {
|
||||
@ -226,6 +249,7 @@ public final class ExtendedSocketOptions {
|
||||
if (peerCredentialsSupported) {
|
||||
options.add(SO_PEERCRED);
|
||||
}
|
||||
options.add(IP_DONTFRAGMENT);
|
||||
return Collections.unmodifiableSet(options);
|
||||
}
|
||||
|
||||
@ -248,6 +272,8 @@ public final class ExtendedSocketOptions {
|
||||
setQuickAckOption(fd, (boolean) value);
|
||||
} else if (option == TCP_KEEPCOUNT) {
|
||||
setTcpkeepAliveProbes(fd, (Integer) value);
|
||||
} else if (option == IP_DONTFRAGMENT) {
|
||||
setIpDontFragment(fd, (Boolean) value);
|
||||
} else if (option == TCP_KEEPIDLE) {
|
||||
setTcpKeepAliveTime(fd, (Integer) value);
|
||||
} else if (option == TCP_KEEPINTERVAL) {
|
||||
@ -277,6 +303,8 @@ public final class ExtendedSocketOptions {
|
||||
return getQuickAckOption(fd);
|
||||
} else if (option == TCP_KEEPCOUNT) {
|
||||
return getTcpkeepAliveProbes(fd);
|
||||
} else if (option == IP_DONTFRAGMENT) {
|
||||
return getIpDontFragment(fd);
|
||||
} else if (option == TCP_KEEPIDLE) {
|
||||
return getTcpKeepAliveTime(fd);
|
||||
} else if (option == TCP_KEEPINTERVAL) {
|
||||
@ -320,6 +348,11 @@ public final class ExtendedSocketOptions {
|
||||
platformSocketOptions.setTcpKeepAliveTime(fdAccess.get(fd), value);
|
||||
}
|
||||
|
||||
private static void setIpDontFragment(FileDescriptor fd, boolean value)
|
||||
throws SocketException {
|
||||
platformSocketOptions.setIpDontFragment(fdAccess.get(fd), value);
|
||||
}
|
||||
|
||||
private static void setTcpKeepAliveIntvl(FileDescriptor fd, int value)
|
||||
throws SocketException {
|
||||
platformSocketOptions.setTcpKeepAliveIntvl(fdAccess.get(fd), value);
|
||||
@ -329,6 +362,10 @@ public final class ExtendedSocketOptions {
|
||||
return platformSocketOptions.getTcpkeepAliveProbes(fdAccess.get(fd));
|
||||
}
|
||||
|
||||
private static boolean getIpDontFragment(FileDescriptor fd) throws SocketException {
|
||||
return platformSocketOptions.getIpDontFragment(fdAccess.get(fd));
|
||||
}
|
||||
|
||||
private static int getTcpKeepAliveTime(FileDescriptor fd) throws SocketException {
|
||||
return platformSocketOptions.getTcpKeepAliveTime(fdAccess.get(fd));
|
||||
}
|
||||
@ -368,6 +405,8 @@ public final class ExtendedSocketOptions {
|
||||
return newInstance("jdk.net.LinuxSocketOptions");
|
||||
} else if (osname.startsWith("Mac")) {
|
||||
return newInstance("jdk.net.MacOSXSocketOptions");
|
||||
} else if (osname.startsWith("Windows")) {
|
||||
return newInstance("jdk.net.WindowsSocketOptions");
|
||||
} else {
|
||||
return new PlatformSocketOptions();
|
||||
}
|
||||
@ -415,6 +454,14 @@ public final class ExtendedSocketOptions {
|
||||
throw new UnsupportedOperationException("unsupported TCP_KEEPINTVL option");
|
||||
}
|
||||
|
||||
void setIpDontFragment(int fd, final boolean value) throws SocketException {
|
||||
throw new UnsupportedOperationException("unsupported IP_DONTFRAGMENT option");
|
||||
}
|
||||
|
||||
boolean getIpDontFragment(int fd) throws SocketException {
|
||||
throw new UnsupportedOperationException("unsupported IP_DONTFRAGMENT option");
|
||||
}
|
||||
|
||||
int getTcpkeepAliveProbes(int fd) throws SocketException {
|
||||
throw new UnsupportedOperationException("unsupported TCP_KEEPCNT option");
|
||||
}
|
||||
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
package jdk.net;
|
||||
|
||||
import java.net.SocketException;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import jdk.net.ExtendedSocketOptions.PlatformSocketOptions;
|
||||
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
class WindowsSocketOptions extends PlatformSocketOptions {
|
||||
|
||||
public WindowsSocketOptions() {
|
||||
}
|
||||
|
||||
@Override
|
||||
void setIpDontFragment(int fd, final boolean value) throws SocketException {
|
||||
setIpDontFragment0(fd, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean getIpDontFragment(int fd) throws SocketException {
|
||||
return getIpDontFragment0(fd);
|
||||
}
|
||||
|
||||
private static native void setIpDontFragment0(int fd, boolean value) throws SocketException;
|
||||
private static native boolean getIpDontFragment0(int fd) throws SocketException;
|
||||
|
||||
static {
|
||||
if (System.getSecurityManager() == null) {
|
||||
System.loadLibrary("extnet");
|
||||
} else {
|
||||
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
|
||||
System.loadLibrary("extnet");
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
126
src/jdk.net/windows/native/libextnet/WindowsSocketOptions.c
Normal file
126
src/jdk.net/windows/native/libextnet/WindowsSocketOptions.c
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 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 <windows.h>
|
||||
#include <winsock2.h>
|
||||
|
||||
#include <WS2tcpip.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
|
||||
static void handleError(JNIEnv *env, jint rv, const char *errmsg) {
|
||||
if (rv < 0) {
|
||||
if (errno == ENOPROTOOPT) {
|
||||
JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
|
||||
"unsupported socket option");
|
||||
} else {
|
||||
JNU_ThrowByNameWithLastError(env, "java/net/SocketException", errmsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int socketFamily(jint fd) {
|
||||
WSAPROTOCOL_INFO info;
|
||||
socklen_t sa_len = sizeof(info);
|
||||
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL_INFO, (char *)&info, &sa_len) == 0) {
|
||||
return info.iAddressFamily;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: jdk_net_WindowsSocketOptions
|
||||
* Method: setIpDontFragment0
|
||||
* Signature: (IZ)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_jdk_net_WindowsSocketOptions_setIpDontFragment0
|
||||
(JNIEnv *env, jobject unused, jint fd, jboolean optval) {
|
||||
int rv, opt;
|
||||
jint family = socketFamily(fd);
|
||||
if (family == -1) {
|
||||
handleError(env, family, "get socket family failed");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (family == AF_INET) {
|
||||
opt = optval ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
|
||||
rv = setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, (char *)&opt, sizeof(int));
|
||||
if (rv == SOCKET_ERROR && WSAGetLastError() == WSAENOPROTOOPT) {
|
||||
opt = optval;
|
||||
rv = setsockopt(fd, IPPROTO_IP, IP_DONTFRAGMENT, (char *)&opt, sizeof(int));
|
||||
}
|
||||
} else {
|
||||
opt = optval ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
|
||||
rv = setsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, (char *)&opt, sizeof(int));
|
||||
if (rv == SOCKET_ERROR && WSAGetLastError() == WSAENOPROTOOPT) {
|
||||
/* IPV6_MTU_DISCOVER not supported on W 2016 and older, can use old option */
|
||||
opt = optval;
|
||||
rv = setsockopt(fd, IPPROTO_IP, IP_DONTFRAGMENT, (char *)&opt, sizeof(int));
|
||||
}
|
||||
}
|
||||
handleError(env, rv, "set option IP_DONTFRAGMENT failed");
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: jdk_net_WindowsSocketOptions
|
||||
* Method: getIpDontFragment0
|
||||
* Signature: (I)Z;
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_jdk_net_WindowsSocketOptions_getIpDontFragment0
|
||||
(JNIEnv *env, jobject unused, jint fd) {
|
||||
int optval, rv, sz = sizeof(optval);
|
||||
jint family = socketFamily(fd);
|
||||
if (family == -1) {
|
||||
handleError(env, family, "get socket family failed");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (family == AF_INET) {
|
||||
rv = getsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, (char *)&optval, &sz);
|
||||
if (rv == SOCKET_ERROR && WSAGetLastError() == WSAENOPROTOOPT) {
|
||||
sz = sizeof(optval);
|
||||
rv = getsockopt(fd, IPPROTO_IP, IP_DONTFRAGMENT, (char *)&optval, &sz);
|
||||
handleError(env, rv, "get option IP_DONTFRAGMENT failed");
|
||||
return optval;
|
||||
}
|
||||
handleError(env, rv, "get option IP_DONTFRAGMENT failed");
|
||||
return optval == IP_PMTUDISC_DO ? JNI_TRUE : JNI_FALSE;
|
||||
} else {
|
||||
rv = getsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, (char *)&optval, &sz);
|
||||
if (rv == SOCKET_ERROR && WSAGetLastError() == WSAENOPROTOOPT) {
|
||||
sz = sizeof(optval);
|
||||
rv = getsockopt(fd, IPPROTO_IP, IP_DONTFRAGMENT, (char *)&optval, &sz);
|
||||
handleError(env, rv, "get option IP_DONTFRAGMENT failed");
|
||||
return optval;
|
||||
}
|
||||
handleError(env, rv, "get option IP_DONTFRAGMENT failed");
|
||||
return optval == IP_PMTUDISC_DO ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
}
|
||||
|
@ -105,6 +105,8 @@ public class AfterClose {
|
||||
map.put((SocketOption<?>)field.get(null), listOf(10, 100));
|
||||
field = c.getField("SO_INCOMING_NAPI_ID");
|
||||
map.put((SocketOption<?>)field.get(null), listOf(RO));
|
||||
field = c.getField("IP_DONTFRAGMENT");
|
||||
map.put((SocketOption<?>)field.get(null), listOf(TRUE, FALSE));
|
||||
} catch (ClassNotFoundException e) {
|
||||
// ignore, jdk.net module not present
|
||||
} catch (ReflectiveOperationException e) {
|
||||
|
106
test/jdk/jdk/net/ExtendedSocketOption/DontFragmentTest.java
Normal file
106
test/jdk/jdk/net/ExtendedSocketOption/DontFragmentTest.java
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8243099
|
||||
* @modules jdk.net
|
||||
* @run main/othervm DontFragmentTest ipv4
|
||||
* @run main/othervm DontFragmentTest ipv6
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
import java.nio.channels.*;
|
||||
import static java.net.StandardProtocolFamily.INET;
|
||||
import static java.net.StandardProtocolFamily.INET6;
|
||||
import static jdk.net.ExtendedSocketOptions.IP_DONTFRAGMENT;
|
||||
|
||||
public class DontFragmentTest {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
testDatagramChannel();
|
||||
StandardProtocolFamily fam = args[0].equals("ipv4") ? INET : INET6;
|
||||
System.out.println("Family = " + fam);
|
||||
testDatagramChannel(args, fam);
|
||||
try (DatagramSocket c = new DatagramSocket()) {
|
||||
testDatagramSocket(c);
|
||||
}
|
||||
try (DatagramChannel dc = DatagramChannel.open(fam)) {
|
||||
var c = dc.socket();
|
||||
testDatagramSocket(c);
|
||||
}
|
||||
try (MulticastSocket mc = new MulticastSocket()) {
|
||||
testDatagramSocket(mc);
|
||||
}
|
||||
}
|
||||
|
||||
public static void testDatagramChannel() throws IOException {
|
||||
try (DatagramChannel c1 = DatagramChannel.open()) {
|
||||
|
||||
if (c1.getOption(IP_DONTFRAGMENT)) {
|
||||
throw new RuntimeException("IP_DONTFRAGMENT should not be set");
|
||||
}
|
||||
c1.setOption(IP_DONTFRAGMENT, true);
|
||||
if (!c1.getOption(IP_DONTFRAGMENT)) {
|
||||
throw new RuntimeException("IP_DONTFRAGMENT should be set");
|
||||
}
|
||||
c1.setOption(IP_DONTFRAGMENT, false);
|
||||
if (c1.getOption(IP_DONTFRAGMENT)) {
|
||||
throw new RuntimeException("IP_DONTFRAGMENT should not be set");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void testDatagramChannel(String[] args, ProtocolFamily fam) throws IOException {
|
||||
try (DatagramChannel c1 = DatagramChannel.open(fam)) {
|
||||
|
||||
if (c1.getOption(IP_DONTFRAGMENT)) {
|
||||
throw new RuntimeException("IP_DONTFRAGMENT should not be set");
|
||||
}
|
||||
c1.setOption(IP_DONTFRAGMENT, true);
|
||||
if (!c1.getOption(IP_DONTFRAGMENT)) {
|
||||
throw new RuntimeException("IP_DONTFRAGMENT should be set");
|
||||
}
|
||||
c1.setOption(IP_DONTFRAGMENT, false);
|
||||
if (c1.getOption(IP_DONTFRAGMENT)) {
|
||||
throw new RuntimeException("IP_DONTFRAGMENT should not be set");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void testDatagramSocket(DatagramSocket c1) throws IOException {
|
||||
if (c1.getOption(IP_DONTFRAGMENT)) {
|
||||
throw new RuntimeException("IP_DONTFRAGMENT should not be set");
|
||||
}
|
||||
c1.setOption(IP_DONTFRAGMENT, true);
|
||||
if (!c1.getOption(IP_DONTFRAGMENT)) {
|
||||
throw new RuntimeException("IP_DONTFRAGMENT should be set");
|
||||
}
|
||||
c1.setOption(IP_DONTFRAGMENT, false);
|
||||
if (c1.getOption(IP_DONTFRAGMENT)) {
|
||||
throw new RuntimeException("IP_DONTFRAGMENT should not be set");
|
||||
}
|
||||
c1.close();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user