mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-01 19:50:05 +00:00
8072384: Setting IP_TOS on java.net sockets not working on unix
Reviewed-by: michaelm
This commit is contained in:
parent
46b53cd5cf
commit
4ae5f74173
@ -42,7 +42,7 @@ SUNWprivate_1.1 {
|
||||
Java_java_net_Inet4Address_init;
|
||||
Java_java_net_Inet6Address_init;
|
||||
Java_java_net_PlainDatagramSocketImpl_setTTL;
|
||||
Java_java_net_PlainDatagramSocketImpl_socketSetOption;
|
||||
Java_java_net_PlainDatagramSocketImpl_socketSetOption0;
|
||||
Java_java_net_PlainDatagramSocketImpl_bind0;
|
||||
Java_java_net_PlainSocketImpl_socketAccept;
|
||||
Java_java_net_DatagramPacket_init;
|
||||
@ -73,7 +73,7 @@ SUNWprivate_1.1 {
|
||||
Java_java_net_SocketOutputStream_init;
|
||||
Java_java_net_PlainDatagramSocketImpl_peek;
|
||||
Java_java_net_PlainDatagramSocketImpl_peekData;
|
||||
Java_java_net_PlainSocketImpl_socketSetOption;
|
||||
Java_java_net_PlainSocketImpl_socketSetOption0;
|
||||
Java_java_net_PlainSocketImpl_socketSendUrgentData;
|
||||
Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate;
|
||||
Java_java_net_PlainSocketImpl_socketGetOption;
|
||||
|
||||
@ -312,11 +312,16 @@ abstract class AbstractPlainSocketImpl extends SocketImpl
|
||||
ret = socketGetOption(opt, null);
|
||||
return ret;
|
||||
case IP_TOS:
|
||||
ret = socketGetOption(opt, null);
|
||||
if (ret == -1) { // ipv6 tos
|
||||
return trafficClass;
|
||||
} else {
|
||||
return ret;
|
||||
try {
|
||||
ret = socketGetOption(opt, null);
|
||||
if (ret == -1) { // ipv6 tos
|
||||
return trafficClass;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
} catch (SocketException se) {
|
||||
// TODO - should make better effort to read TOS or TCLASS
|
||||
return trafficClass; // ipv6 tos
|
||||
}
|
||||
case SO_KEEPALIVE:
|
||||
ret = socketGetOption(opt, null);
|
||||
|
||||
@ -1184,7 +1184,14 @@ class DatagramSocket implements java.io.Closeable {
|
||||
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
getImpl().setOption(SocketOptions.IP_TOS, tc);
|
||||
try {
|
||||
getImpl().setOption(SocketOptions.IP_TOS, tc);
|
||||
} catch (SocketException se) {
|
||||
// not supported if socket already connected
|
||||
// Solaris returns error in such cases
|
||||
if(!isConnected())
|
||||
throw se;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1380,7 +1380,14 @@ class Socket implements java.io.Closeable {
|
||||
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
getImpl().setOption(SocketOptions.IP_TOS, tc);
|
||||
try {
|
||||
getImpl().setOption(SocketOptions.IP_TOS, tc);
|
||||
} catch (SocketException se) {
|
||||
// not supported if socket already connected
|
||||
// Solaris returns error in such cases
|
||||
if(!isConnected())
|
||||
throw se;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -80,6 +80,15 @@ class PlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
|
||||
return options;
|
||||
}
|
||||
|
||||
protected void socketSetOption(int opt, Object val) throws SocketException {
|
||||
try {
|
||||
socketSetOption0(opt, val);
|
||||
} catch (SocketException se) {
|
||||
if (!connected)
|
||||
throw se;
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized native void bind0(int lport, InetAddress laddr)
|
||||
throws SocketException;
|
||||
|
||||
@ -112,7 +121,7 @@ class PlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
|
||||
|
||||
protected native void datagramSocketClose();
|
||||
|
||||
protected native void socketSetOption(int opt, Object val)
|
||||
protected native void socketSetOption0(int opt, Object val)
|
||||
throws SocketException;
|
||||
|
||||
protected native Object socketGetOption(int opt) throws SocketException;
|
||||
|
||||
@ -94,6 +94,15 @@ class PlainSocketImpl extends AbstractPlainSocketImpl
|
||||
return options;
|
||||
}
|
||||
|
||||
protected void socketSetOption(int opt, boolean b, Object val) throws SocketException {
|
||||
try {
|
||||
socketSetOption0(opt, b, val);
|
||||
} catch (SocketException se) {
|
||||
if (socket == null || !socket.isConnected())
|
||||
throw se;
|
||||
}
|
||||
}
|
||||
|
||||
native void socketCreate(boolean isServer) throws IOException;
|
||||
|
||||
native void socketConnect(InetAddress address, int port, int timeout)
|
||||
@ -114,7 +123,7 @@ class PlainSocketImpl extends AbstractPlainSocketImpl
|
||||
|
||||
static native void initProto();
|
||||
|
||||
native void socketSetOption(int cmd, boolean on, Object value)
|
||||
native void socketSetOption0(int cmd, boolean on, Object value)
|
||||
throws SocketException;
|
||||
|
||||
native int socketGetOption(int opt, Object iaContainerObj) throws SocketException;
|
||||
|
||||
@ -1294,11 +1294,11 @@ static void setMulticastLoopbackMode(JNIEnv *env, jobject this, int fd,
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainDatagramSocketImpl
|
||||
* Method: socketSetOption
|
||||
* Method: socketSetOption0
|
||||
* Signature: (ILjava/lang/Object;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_net_PlainDatagramSocketImpl_socketSetOption(JNIEnv *env,
|
||||
Java_java_net_PlainDatagramSocketImpl_socketSetOption0(JNIEnv *env,
|
||||
jobject this,
|
||||
jint opt,
|
||||
jobject value) {
|
||||
|
||||
@ -847,11 +847,11 @@ Java_java_net_PlainSocketImpl_socketShutdown(JNIEnv *env, jobject this,
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: socketSetOption
|
||||
* Method: socketSetOption0
|
||||
* Signature: (IZLjava/lang/Object;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_net_PlainSocketImpl_socketSetOption(JNIEnv *env, jobject this,
|
||||
Java_java_net_PlainSocketImpl_socketSetOption0(JNIEnv *env, jobject this,
|
||||
jint cmd, jboolean on,
|
||||
jobject value) {
|
||||
int fd;
|
||||
|
||||
@ -1023,12 +1023,10 @@ NET_MapSocketOption(jint cmd, int *level, int *optname) {
|
||||
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Different multicast options if IPv6 is enabled
|
||||
*/
|
||||
#ifdef AF_INET6
|
||||
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;
|
||||
@ -1039,6 +1037,13 @@ NET_MapSocketOption(jint cmd, int *level, int *optname) {
|
||||
*level = IPPROTO_IPV6;
|
||||
*optname = IPV6_MULTICAST_LOOP;
|
||||
return 0;
|
||||
#if (defined(__solaris__) || defined(MACOSX))
|
||||
// Map IP_TOS request to IPV6_TCLASS
|
||||
case java_net_SocketOptions_IP_TOS:
|
||||
*level = IPPROTO_IPV6;
|
||||
*optname = IPV6_TCLASS;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -1214,9 +1219,6 @@ int getDefaultIPv6Interface(struct in6_addr *target_addr) {
|
||||
* Wrapper for getsockopt system routine - does any necessary
|
||||
* pre/post processing to deal with OS specific oddities :-
|
||||
*
|
||||
* IP_TOS is a no-op with IPv6 sockets as it's setup when
|
||||
* the connection is established.
|
||||
*
|
||||
* On Linux the SO_SNDBUF/SO_RCVBUF values must be post-processed
|
||||
* to compensate for an incorrect value returned by the kernel.
|
||||
*/
|
||||
@ -1227,21 +1229,6 @@ NET_GetSockOpt(int fd, int level, int opt, void *result,
|
||||
int rv;
|
||||
socklen_t socklen = *len;
|
||||
|
||||
#ifdef AF_INET6
|
||||
if ((level == IPPROTO_IP) && (opt == IP_TOS)) {
|
||||
if (ipv6_available()) {
|
||||
|
||||
/*
|
||||
* For IPv6 socket option implemented at Java-level
|
||||
* so return -1.
|
||||
*/
|
||||
int *tc = (int *)result;
|
||||
*tc = -1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
rv = getsockopt(fd, level, opt, result, &socklen);
|
||||
*len = socklen;
|
||||
|
||||
@ -1285,8 +1272,7 @@ NET_GetSockOpt(int fd, int level, int opt, void *result,
|
||||
*
|
||||
* For IP_TOS socket option need to mask off bits as this
|
||||
* aren't automatically masked by the kernel and results in
|
||||
* an error. In addition IP_TOS is a NOOP with IPv6 as it
|
||||
* should be setup as connection time.
|
||||
* an error.
|
||||
*/
|
||||
int
|
||||
NET_SetSockOpt(int fd, int level, int opt, const void *arg,
|
||||
@ -1317,9 +1303,9 @@ NET_SetSockOpt(int fd, int level, int opt, const void *arg,
|
||||
|
||||
/*
|
||||
* IPPROTO/IP_TOS :-
|
||||
* 1. IPv6 on Solaris/Mac OS: NOOP and will be set
|
||||
* in flowinfo field when connecting TCP socket,
|
||||
* or sending UDP packet.
|
||||
* 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.
|
||||
@ -1329,12 +1315,6 @@ NET_SetSockOpt(int fd, int level, int opt, const void *arg,
|
||||
if (level == IPPROTO_IP && opt == IP_TOS) {
|
||||
int *iptos;
|
||||
|
||||
#if defined(AF_INET6) && (defined(__solaris__) || defined(MACOSX))
|
||||
if (ipv6_available()) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(AF_INET6) && defined(__linux__)
|
||||
if (ipv6_available()) {
|
||||
int optval = 1;
|
||||
@ -1342,6 +1322,16 @@ NET_SetSockOpt(int fd, int level, int opt, const void *arg,
|
||||
(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
|
||||
|
||||
@ -1435,7 +1425,7 @@ NET_SetSockOpt(int fd, int level, int opt, const void *arg,
|
||||
* 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 discard.
|
||||
* must be discarded.
|
||||
*/
|
||||
#ifdef __linux__
|
||||
if (level == SOL_SOCKET && opt == SO_RCVBUF) {
|
||||
@ -1619,7 +1609,7 @@ NET_Bind(int fd, struct sockaddr *him, int len)
|
||||
* NET_WAIT_READ, NET_WAIT_WRITE & NET_WAIT_CONNECT.
|
||||
*
|
||||
* The function will return when either the socket is ready for one
|
||||
* of the specified operation or the timeout expired.
|
||||
* of the specified operations or the timeout expired.
|
||||
*
|
||||
* It returns the time left from the timeout (possibly 0), or -1 if it expired.
|
||||
*/
|
||||
|
||||
@ -23,8 +23,9 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8036979
|
||||
* @bug 8036979 8072384
|
||||
* @run main/othervm -Xcheck:jni OptionsTest
|
||||
* @run main/othervm -Xcheck:jni -Djava.net.preferIPv4Stack=true OptionsTest
|
||||
*/
|
||||
|
||||
import java.net.*;
|
||||
@ -59,7 +60,8 @@ public class OptionsTest {
|
||||
|
||||
static Test[] serverSocketTests = new Test[] {
|
||||
Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)),
|
||||
Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE)
|
||||
Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE),
|
||||
Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100))
|
||||
};
|
||||
|
||||
static Test[] dgSocketTests = new Test[] {
|
||||
@ -193,6 +195,9 @@ public class OptionsTest {
|
||||
return Integer.valueOf(socket.getReceiveBufferSize());
|
||||
} else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) {
|
||||
return Boolean.valueOf(socket.getReuseAddress());
|
||||
} else if (option.equals(StandardSocketOptions.IP_TOS)) {
|
||||
return Integer.valueOf(jdk.net.Sockets.getOption(
|
||||
socket, StandardSocketOptions.IP_TOS));
|
||||
} else {
|
||||
throw new RuntimeException("unexecpted socket option");
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user