Ensure setting / getting the traffic class on an ipv4 only system works when using the native transport.

Motivation:

We tried to set IPV6 opts on an ipv4 only system and so failed to set / get the traffic opts. This resulted in a test-error when trying to compile netty on ipv4 only systems.

Modifications:

Use the correct opts depending on if the system is ipv4 only or not.

Result:

Be able to build and use on ipv4 only systems.
This commit is contained in:
Norman Maurer 2017-10-05 15:08:00 +02:00
parent dcc39e5b21
commit d8e187ff2c
2 changed files with 32 additions and 15 deletions

View File

@ -91,7 +91,8 @@ public abstract class SocketTest<T extends Socket> {
@Test @Test
public void testTrafficClass() throws IOException { public void testTrafficClass() throws IOException {
final int value = 0x1; // IPTOS_THROUGHPUT
final int value = 0x08;
socket.setTrafficClass(value); socket.setTrafficClass(value);
assertEquals(value, socket.getTrafficClass()); assertEquals(value, socket.getTrafficClass());
} }

View File

@ -755,19 +755,27 @@ static void netty_unix_socket_setSoLinger(JNIEnv* env, jclass clazz, jint fd, ji
} }
static void netty_unix_socket_setTrafficClass(JNIEnv* env, jclass clazz, jint fd, jint optval) { static void netty_unix_socket_setTrafficClass(JNIEnv* env, jclass clazz, jint fd, jint optval) {
/* Try to set the ipv6 equivalent, but don't throw if this is an ipv4 only socket. */ if (socketType == AF_INET6) {
int rc = netty_unix_socket_setOption0(fd, IPPROTO_IPV6, IPV6_TCLASS, &optval, sizeof(optval)); // This call will put an exception on the stack to be processed once the JNI calls completes if
if (rc < 0 && errno != ENOPROTOOPT) { // setsockopt failed and return a negative value.
netty_unix_socket_setOptionHandleError(env, errno); int rc = netty_unix_socket_setOption(env, fd, IPPROTO_IPV6, IPV6_TCLASS, &optval, sizeof(optval));
}
if (rc >= 0) {
/* Linux allows both ipv4 and ipv6 families to be set */ /* Linux allows both ipv4 and ipv6 families to be set */
#ifdef __linux__ #ifdef __linux__
else { // Previous call successful now try to set also for ipv4
netty_unix_socket_setOption(env, fd, IPPROTO_IP, IP_TOS, &optval, sizeof(optval)); if (netty_unix_socket_setOption0(fd, IPPROTO_IP, IP_TOS, &optval, sizeof(optval)) == -1) {
if (errno != ENOPROTOOPT) {
// throw exception
netty_unix_socket_setOptionHandleError(env, errno);
}
} }
#endif #endif
} }
} else {
netty_unix_socket_setOption(env, fd, IPPROTO_IP, IP_TOS, &optval, sizeof(optval));
}
}
static jint netty_unix_socket_isKeepAlive(JNIEnv* env, jclass clazz, jint fd) { static jint netty_unix_socket_isKeepAlive(JNIEnv* env, jclass clazz, jint fd) {
int optval; int optval;
@ -814,15 +822,23 @@ static jint netty_unix_socket_getSoLinger(JNIEnv* env, jclass clazz, jint fd) {
} }
static jint netty_unix_socket_getTrafficClass(JNIEnv* env, jclass clazz, jint fd) { static jint netty_unix_socket_getTrafficClass(JNIEnv* env, jclass clazz, jint fd) {
/* macOS may throw an error if IPv6 is supported and it is not consulted first */
int optval; int optval;
if (socketType == AF_INET6) {
if (netty_unix_socket_getOption0(fd, IPPROTO_IPV6, IPV6_TCLASS, &optval, sizeof(optval)) == -1) { if (netty_unix_socket_getOption0(fd, IPPROTO_IPV6, IPV6_TCLASS, &optval, sizeof(optval)) == -1) {
if (errno != ENOPROTOOPT || netty_unix_socket_getOption0(fd, IPPROTO_IP, IP_TOS, &optval, sizeof(optval)) == -1) { if (errno == ENOPROTOOPT) {
if (netty_unix_socket_getOption(env, fd, IPPROTO_IP, IP_TOS, &optval, sizeof(optval)) == -1) {
return -1;
}
} else {
netty_unix_socket_getOptionHandleError(env, errno); netty_unix_socket_getOptionHandleError(env, errno);
return -1; return -1;
} }
} }
} else {
if (netty_unix_socket_getOption(env, fd, IPPROTO_IP, IP_TOS, &optval, sizeof(optval)) == -1) {
return -1;
}
}
return optval; return optval;
} }