8029607: Type of Service (TOS) cannot be set in IPv6 header
Reviewed-by: alanb
diff --git a/src/share/classes/sun/nio/ch/DatagramChannelImpl.java b/src/share/classes/sun/nio/ch/DatagramChannelImpl.java
index fe32f63..a34286b 100644
--- a/src/share/classes/sun/nio/ch/DatagramChannelImpl.java
+++ b/src/share/classes/sun/nio/ch/DatagramChannelImpl.java
@@ -195,15 +195,8 @@
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 @@
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/src/share/classes/sun/nio/ch/Net.java b/src/share/classes/sun/nio/ch/Net.java
index 753e541..37823e9 100644
--- a/src/share/classes/sun/nio/ch/Net.java
+++ b/src/share/classes/sun/nio/ch/Net.java
@@ -352,7 +352,8 @@
}
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 @@
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/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java b/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java
index 6b7d51b..db73c72 100644
--- a/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java
+++ b/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java
@@ -133,6 +133,14 @@
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 @@
HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(2);
set.add(StandardSocketOptions.SO_RCVBUF);
set.add(StandardSocketOptions.SO_REUSEADDR);
+ set.add(StandardSocketOptions.IP_TOS);
return Collections.unmodifiableSet(set);
}
}
diff --git a/src/share/classes/sun/nio/ch/SocketChannelImpl.java b/src/share/classes/sun/nio/ch/SocketChannelImpl.java
index 1e36aed..7b694ef 100644
--- a/src/share/classes/sun/nio/ch/SocketChannelImpl.java
+++ b/src/share/classes/sun/nio/ch/SocketChannelImpl.java
@@ -173,14 +173,14 @@
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 @@
// 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/src/share/native/sun/nio/ch/genSocketOptionRegistry.c b/src/share/native/sun/nio/ch/genSocketOptionRegistry.c
index d5ed5d7..41bd548 100644
--- a/src/share/native/sun/nio/ch/genSocketOptionRegistry.c
+++ b/src/share/native/sun/nio/ch/genSocketOptionRegistry.c
@@ -110,6 +110,7 @@
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/src/solaris/native/java/net/net_util_md.c b/src/solaris/native/java/net/net_util_md.c
index 8ba8732..769e540 100644
--- a/src/solaris/native/java/net/net_util_md.c
+++ b/src/solaris/native/java/net/net_util_md.c
@@ -1310,7 +1310,7 @@
* 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)
*/
@@ -1326,8 +1326,10 @@
#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/src/solaris/native/sun/nio/ch/Net.c b/src/solaris/native/sun/nio/ch/Net.c
index 2846217..ae7f579 100644
--- a/src/solaris/native/sun/nio/ch/Net.c
+++ b/src/solaris/native/sun/nio/ch/Net.c
@@ -478,7 +478,8 @@
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;
@@ -521,6 +522,12 @@
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/src/windows/native/sun/nio/ch/Net.c b/src/windows/native/sun/nio/ch/Net.c
index 9720d80..fc96ea2 100644
--- a/src/windows/native/sun/nio/ch/Net.c
+++ b/src/windows/native/sun/nio/ch/Net.c
@@ -319,7 +319,7 @@
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;