8029607: Type of Service (TOS) cannot be set in IPv6 header

Reviewed-by: alanb
This commit is contained in:
Michael McMahon 2014-06-25 15:55:42 +01:00
parent ea1882be4f
commit fd148509ce
8 changed files with 40 additions and 34 deletions

View File

@ -110,6 +110,7 @@ int main(int argc, const char* argv[]) {
emit_inet("StandardSocketOptions.IP_MULTICAST_LOOP", IPPROTO_IP, IP_MULTICAST_LOOP); emit_inet("StandardSocketOptions.IP_MULTICAST_LOOP", IPPROTO_IP, IP_MULTICAST_LOOP);
#ifdef AF_INET6 #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_IF", IPPROTO_IPV6, IPV6_MULTICAST_IF);
emit_inet6("StandardSocketOptions.IP_MULTICAST_TTL", IPPROTO_IPV6, IPV6_MULTICAST_HOPS); emit_inet6("StandardSocketOptions.IP_MULTICAST_TTL", IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
emit_inet6("StandardSocketOptions.IP_MULTICAST_LOOP", IPPROTO_IPV6, IPV6_MULTICAST_LOOP); emit_inet6("StandardSocketOptions.IP_MULTICAST_LOOP", IPPROTO_IPV6, IPV6_MULTICAST_LOOP);

View File

@ -195,15 +195,8 @@ class DatagramChannelImpl
synchronized (stateLock) { synchronized (stateLock) {
ensureOpen(); ensureOpen();
if (name == StandardSocketOptions.IP_TOS) { if (name == StandardSocketOptions.IP_TOS ||
// IPv4 only; no-op for IPv6 name == StandardSocketOptions.IP_MULTICAST_TTL ||
if (family == StandardProtocolFamily.INET) {
Net.setSocketOption(fd, family, name, value);
}
return this;
}
if (name == StandardSocketOptions.IP_MULTICAST_TTL ||
name == StandardSocketOptions.IP_MULTICAST_LOOP) name == StandardSocketOptions.IP_MULTICAST_LOOP)
{ {
// options are protocol dependent // options are protocol dependent
@ -256,16 +249,8 @@ class DatagramChannelImpl
synchronized (stateLock) { synchronized (stateLock) {
ensureOpen(); ensureOpen();
if (name == StandardSocketOptions.IP_TOS) { if (name == StandardSocketOptions.IP_TOS ||
// IPv4 only; always return 0 on IPv6 name == StandardSocketOptions.IP_MULTICAST_TTL ||
if (family == StandardProtocolFamily.INET) {
return (T) Net.getSocketOption(fd, family, name);
} else {
return (T) Integer.valueOf(0);
}
}
if (name == StandardSocketOptions.IP_MULTICAST_TTL ||
name == StandardSocketOptions.IP_MULTICAST_LOOP) name == StandardSocketOptions.IP_MULTICAST_LOOP)
{ {
return (T) Net.getSocketOption(fd, family, name); return (T) Net.getSocketOption(fd, family, name);

View File

@ -352,7 +352,8 @@ public class Net {
} }
boolean mayNeedConversion = (family == UNSPEC); 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, static Object getSocketOption(FileDescriptor fd, ProtocolFamily family,
@ -499,7 +500,7 @@ public class Net {
throws IOException; throws IOException;
private static native void setIntOption0(FileDescriptor fd, boolean mayNeedConversion, 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; throws IOException;
static native int poll(FileDescriptor fd, int events, long timeout) static native int poll(FileDescriptor fd, int events, long timeout)

View File

@ -133,6 +133,14 @@ class ServerSocketChannelImpl
synchronized (stateLock) { synchronized (stateLock) {
if (!isOpen()) if (!isOpen())
throw new ClosedChannelException(); 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 && if (name == StandardSocketOptions.SO_REUSEADDR &&
Net.useExclusiveBind()) Net.useExclusiveBind())
{ {
@ -177,6 +185,7 @@ class ServerSocketChannelImpl
HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(2); HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(2);
set.add(StandardSocketOptions.SO_RCVBUF); set.add(StandardSocketOptions.SO_RCVBUF);
set.add(StandardSocketOptions.SO_REUSEADDR); set.add(StandardSocketOptions.SO_REUSEADDR);
set.add(StandardSocketOptions.IP_TOS);
return Collections.unmodifiableSet(set); return Collections.unmodifiableSet(set);
} }
} }

View File

@ -173,14 +173,14 @@ class SocketChannelImpl
if (!isOpen()) if (!isOpen())
throw new ClosedChannelException(); throw new ClosedChannelException();
// special handling for IP_TOS: no-op when IPv6
if (name == StandardSocketOptions.IP_TOS) { if (name == StandardSocketOptions.IP_TOS) {
if (!Net.isIPv6Available()) ProtocolFamily family = Net.isIPv6Available() ?
Net.setSocketOption(fd, StandardProtocolFamily.INET, name, value); StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
Net.setSocketOption(fd, family, name, value);
return this; return this;
} else if (name == StandardSocketOptions.SO_REUSEADDR && }
Net.useExclusiveBind())
{ if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
// SO_REUSEADDR emulated when using exclusive bind // SO_REUSEADDR emulated when using exclusive bind
isReuseAddress = (Boolean)value; isReuseAddress = (Boolean)value;
return this; return this;
@ -215,8 +215,9 @@ class SocketChannelImpl
// special handling for IP_TOS: always return 0 when IPv6 // special handling for IP_TOS: always return 0 when IPv6
if (name == StandardSocketOptions.IP_TOS) { if (name == StandardSocketOptions.IP_TOS) {
return (Net.isIPv6Available()) ? (T) Integer.valueOf(0) : ProtocolFamily family = Net.isIPv6Available() ?
(T) Net.getSocketOption(fd, StandardProtocolFamily.INET, name); StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
return (T) Net.getSocketOption(fd, family, name);
} }
// no options that require special handling // no options that require special handling

View File

@ -1317,7 +1317,7 @@ NET_SetSockOpt(int fd, int level, int opt, const void *arg,
* or sending UDP packet. * or sending UDP packet.
* 2. IPv6 on Linux: By default Linux ignores flowinfo * 2. IPv6 on Linux: By default Linux ignores flowinfo
* field so enable IPV6_FLOWINFO_SEND so that 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 * 3. IPv4: set socket option based on ToS and Precedence
* fields (otherwise get invalid argument) * 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 defined(AF_INET6) && defined(__linux__)
if (ipv6_available()) { if (ipv6_available()) {
int optval = 1; int optval = 1;
return setsockopt(fd, IPPROTO_IPV6, IPV6_FLOWINFO_SEND, if (setsockopt(fd, IPPROTO_IPV6, IPV6_FLOWINFO_SEND,
(void *)&optval, sizeof(optval)); (void *)&optval, sizeof(optval)) < 0) {
return -1;
}
} }
#endif #endif

View File

@ -435,7 +435,8 @@ Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 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; int result;
struct linger linger; struct linger linger;
@ -478,6 +479,12 @@ Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
JNU_JAVANETPKG "SocketException", JNU_JAVANETPKG "SocketException",
"sun.nio.ch.Net.setIntOption"); "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 JNIEXPORT jint JNICALL

View File

@ -319,7 +319,7 @@ Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 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; struct linger linger;
char *parg; char *parg;