From fd148509ce5d52f3161e22be6877f3768eed908e Mon Sep 17 00:00:00 2001 From: Michael McMahon Date: Wed, 25 Jun 2014 15:55:42 +0100 Subject: [PATCH] 8029607: Type of Service (TOS) cannot be set in IPv6 header Reviewed-by: alanb --- .../genconstants/ch/genSocketOptionRegistry.c | 1 + .../sun/nio/ch/DatagramChannelImpl.java | 23 ++++--------------- jdk/src/share/classes/sun/nio/ch/Net.java | 5 ++-- .../sun/nio/ch/ServerSocketChannelImpl.java | 9 ++++++++ .../classes/sun/nio/ch/SocketChannelImpl.java | 17 +++++++------- jdk/src/solaris/native/java/net/net_util_md.c | 8 ++++--- jdk/src/solaris/native/sun/nio/ch/Net.c | 9 +++++++- jdk/src/windows/native/sun/nio/ch/Net.c | 2 +- 8 files changed, 40 insertions(+), 34 deletions(-) diff --git a/jdk/make/src/native/genconstants/ch/genSocketOptionRegistry.c b/jdk/make/src/native/genconstants/ch/genSocketOptionRegistry.c index d5ed5d7a87e..41bd5484ab7 100644 --- a/jdk/make/src/native/genconstants/ch/genSocketOptionRegistry.c +++ b/jdk/make/src/native/genconstants/ch/genSocketOptionRegistry.c @@ -110,6 +110,7 @@ int main(int argc, const char* argv[]) { emit_inet("StandardSocketOptions.IP_MULTICAST_LOOP", IPPROTO_IP, IP_MULTICAST_LOOP); #ifdef AF_INET6 + emit_inet6("StandardSocketOptions.IP_TOS", IPPROTO_IPV6, IPV6_TCLASS); emit_inet6("StandardSocketOptions.IP_MULTICAST_IF", IPPROTO_IPV6, IPV6_MULTICAST_IF); emit_inet6("StandardSocketOptions.IP_MULTICAST_TTL", IPPROTO_IPV6, IPV6_MULTICAST_HOPS); emit_inet6("StandardSocketOptions.IP_MULTICAST_LOOP", IPPROTO_IPV6, IPV6_MULTICAST_LOOP); diff --git a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java index fe32f63880b..a34286bddb4 100644 --- a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -195,15 +195,8 @@ class DatagramChannelImpl synchronized (stateLock) { ensureOpen(); - if (name == StandardSocketOptions.IP_TOS) { - // IPv4 only; no-op for IPv6 - if (family == StandardProtocolFamily.INET) { - Net.setSocketOption(fd, family, name, value); - } - return this; - } - - if (name == StandardSocketOptions.IP_MULTICAST_TTL || + if (name == StandardSocketOptions.IP_TOS || + name == StandardSocketOptions.IP_MULTICAST_TTL || name == StandardSocketOptions.IP_MULTICAST_LOOP) { // options are protocol dependent @@ -256,16 +249,8 @@ class DatagramChannelImpl synchronized (stateLock) { ensureOpen(); - if (name == StandardSocketOptions.IP_TOS) { - // IPv4 only; always return 0 on IPv6 - if (family == StandardProtocolFamily.INET) { - return (T) Net.getSocketOption(fd, family, name); - } else { - return (T) Integer.valueOf(0); - } - } - - if (name == StandardSocketOptions.IP_MULTICAST_TTL || + if (name == StandardSocketOptions.IP_TOS || + name == StandardSocketOptions.IP_MULTICAST_TTL || name == StandardSocketOptions.IP_MULTICAST_LOOP) { return (T) Net.getSocketOption(fd, family, name); diff --git a/jdk/src/share/classes/sun/nio/ch/Net.java b/jdk/src/share/classes/sun/nio/ch/Net.java index 753e5417310..37823e98c55 100644 --- a/jdk/src/share/classes/sun/nio/ch/Net.java +++ b/jdk/src/share/classes/sun/nio/ch/Net.java @@ -352,7 +352,8 @@ public class Net { } boolean mayNeedConversion = (family == UNSPEC); - setIntOption0(fd, mayNeedConversion, key.level(), key.name(), arg); + boolean isIPv6 = (family == StandardProtocolFamily.INET6); + setIntOption0(fd, mayNeedConversion, key.level(), key.name(), arg, isIPv6); } static Object getSocketOption(FileDescriptor fd, ProtocolFamily family, @@ -499,7 +500,7 @@ public class Net { throws IOException; private static native void setIntOption0(FileDescriptor fd, boolean mayNeedConversion, - int level, int opt, int arg) + int level, int opt, int arg, boolean isIPv6) throws IOException; static native int poll(FileDescriptor fd, int events, long timeout) diff --git a/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java index b35cf815272..a7cc1946904 100644 --- a/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java @@ -133,6 +133,14 @@ class ServerSocketChannelImpl synchronized (stateLock) { if (!isOpen()) throw new ClosedChannelException(); + + if (name == StandardSocketOptions.IP_TOS) { + ProtocolFamily family = Net.isIPv6Available() ? + StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; + Net.setSocketOption(fd, family, name, value); + return this; + } + if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { @@ -177,6 +185,7 @@ class ServerSocketChannelImpl HashSet> set = new HashSet>(2); set.add(StandardSocketOptions.SO_RCVBUF); set.add(StandardSocketOptions.SO_REUSEADDR); + set.add(StandardSocketOptions.IP_TOS); return Collections.unmodifiableSet(set); } } diff --git a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java index 3277de9f6a3..a72fe07e4a1 100644 --- a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java @@ -173,14 +173,14 @@ class SocketChannelImpl if (!isOpen()) throw new ClosedChannelException(); - // special handling for IP_TOS: no-op when IPv6 if (name == StandardSocketOptions.IP_TOS) { - if (!Net.isIPv6Available()) - Net.setSocketOption(fd, StandardProtocolFamily.INET, name, value); + ProtocolFamily family = Net.isIPv6Available() ? + StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; + Net.setSocketOption(fd, family, name, value); return this; - } else if (name == StandardSocketOptions.SO_REUSEADDR && - Net.useExclusiveBind()) - { + } + + if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { // SO_REUSEADDR emulated when using exclusive bind isReuseAddress = (Boolean)value; return this; @@ -215,8 +215,9 @@ class SocketChannelImpl // special handling for IP_TOS: always return 0 when IPv6 if (name == StandardSocketOptions.IP_TOS) { - return (Net.isIPv6Available()) ? (T) Integer.valueOf(0) : - (T) Net.getSocketOption(fd, StandardProtocolFamily.INET, name); + ProtocolFamily family = Net.isIPv6Available() ? + StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; + return (T) Net.getSocketOption(fd, family, name); } // no options that require special handling diff --git a/jdk/src/solaris/native/java/net/net_util_md.c b/jdk/src/solaris/native/java/net/net_util_md.c index e463d46276f..dedeedb669f 100644 --- a/jdk/src/solaris/native/java/net/net_util_md.c +++ b/jdk/src/solaris/native/java/net/net_util_md.c @@ -1317,7 +1317,7 @@ NET_SetSockOpt(int fd, int level, int opt, const void *arg, * or sending UDP packet. * 2. IPv6 on Linux: By default Linux ignores flowinfo * field so enable IPV6_FLOWINFO_SEND so that flowinfo - * will be examined. + * 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) */ @@ -1333,8 +1333,10 @@ NET_SetSockOpt(int fd, int level, int opt, const void *arg, #if defined(AF_INET6) && defined(__linux__) if (ipv6_available()) { int optval = 1; - return setsockopt(fd, IPPROTO_IPV6, IPV6_FLOWINFO_SEND, - (void *)&optval, sizeof(optval)); + if (setsockopt(fd, IPPROTO_IPV6, IPV6_FLOWINFO_SEND, + (void *)&optval, sizeof(optval)) < 0) { + return -1; + } } #endif diff --git a/jdk/src/solaris/native/sun/nio/ch/Net.c b/jdk/src/solaris/native/sun/nio/ch/Net.c index 92f6f19a43e..8887f59109c 100644 --- a/jdk/src/solaris/native/sun/nio/ch/Net.c +++ b/jdk/src/solaris/native/sun/nio/ch/Net.c @@ -435,7 +435,8 @@ Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo, JNIEXPORT void JNICALL Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, - jboolean mayNeedConversion, jint level, jint opt, jint arg) + jboolean mayNeedConversion, jint level, + jint opt, jint arg, jboolean isIPv6) { int result; struct linger linger; @@ -478,6 +479,12 @@ Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, JNU_JAVANETPKG "SocketException", "sun.nio.ch.Net.setIntOption"); } +#ifdef __linux__ + if (level == IPPROTO_IPV6 && opt == IPV6_TCLASS && isIPv6) { + // set the V4 option also + setsockopt(fdval(env, fdo), IPPROTO_IP, IP_TOS, parg, arglen); + } +#endif } JNIEXPORT jint JNICALL diff --git a/jdk/src/windows/native/sun/nio/ch/Net.c b/jdk/src/windows/native/sun/nio/ch/Net.c index 9720d80ef62..fc96ea206ae 100644 --- a/jdk/src/windows/native/sun/nio/ch/Net.c +++ b/jdk/src/windows/native/sun/nio/ch/Net.c @@ -319,7 +319,7 @@ Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo, JNIEXPORT void JNICALL Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, - jboolean mayNeedConversion, jint level, jint opt, jint arg) + jboolean mayNeedConversion, jint level, jint opt, jint arg, jboolean ipv6) { struct linger linger; char *parg;