提交 dad04c58 编写于 作者: C coffeys

8072384: Setting IP_TOS on java.net sockets not working on unix

Reviewed-by: michaelm
上级 dc6cc3d9
......@@ -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 new Integer(ret);
case IP_TOS:
ret = socketGetOption(opt, null);
if (ret == -1) { // ipv6 tos
return new Integer(trafficClass);
} else {
return new Integer(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);
......
......@@ -1182,7 +1182,14 @@ class DatagramSocket implements java.io.Closeable {
if (isClosed())
throw new SocketException("Socket is closed");
getImpl().setOption(SocketOptions.IP_TOS, new Integer(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;
}
}
/**
......
......@@ -1378,7 +1378,14 @@ class Socket implements java.io.Closeable {
if (isClosed())
throw new SocketException("Socket is closed");
getImpl().setOption(SocketOptions.IP_TOS, new Integer(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;
}
}
/**
......
......@@ -69,6 +69,15 @@ class PlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
return (T)flow;
}
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;
......@@ -101,7 +110,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;
......
......@@ -83,6 +83,15 @@ class PlainSocketImpl extends AbstractPlainSocketImpl
return (T)flow;
}
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)
......@@ -103,7 +112,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;
......
......@@ -1321,11 +1321,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) {
......
......@@ -885,11 +885,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;
......
......@@ -1012,12 +1012,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;
......@@ -1028,6 +1026,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
......@@ -1203,9 +1208,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.
*/
......@@ -1215,21 +1217,6 @@ NET_GetSockOpt(int fd, int level, int opt, void *result,
{
int rv;
#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
#ifdef __solaris__
rv = getsockopt(fd, level, opt, result, len);
#else
......@@ -1280,8 +1267,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,
......@@ -1312,9 +1298,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.
......@@ -1324,12 +1310,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;
......@@ -1337,6 +1317,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
......@@ -1429,7 +1419,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 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) {
......@@ -1612,7 +1602,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 8032808
* @bug 8032808 8072384
* @run main/othervm -Xcheck:jni Test
* @run main/othervm -Xcheck:jni -Djava.net.preferIPv4Stack=true Test
* @run main/othervm/policy=policy.fail -Xcheck:jni Test fail
* @run main/othervm/policy=policy.success -Xcheck:jni Test success
*/
......@@ -100,6 +101,10 @@ public class Test {
System.out.println ("Set SO_RCVBUF to 5000\ngetting returns: ");
System.out.println (Sockets.getOption(s, StandardSocketOptions.SO_RCVBUF));
Sockets.setOption(ss, StandardSocketOptions.IP_TOS, 128);
System.out.println ("Setting TOS to 128\ngetting returns: ");
System.out.println (Sockets.getOption(ss, StandardSocketOptions.IP_TOS));
try {
Sockets.setOption(ss, StandardSocketOptions.TCP_NODELAY, true);
throw new RuntimeException("TCP_NODELAY should not be supported for ServerSocket");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册