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
public void testTrafficClass() throws IOException {
final int value = 0x1;
// IPTOS_THROUGHPUT
final int value = 0x08;
socket.setTrafficClass(value);
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) {
/* Try to set the ipv6 equivalent, but don't throw if this is an ipv4 only socket. */
int rc = netty_unix_socket_setOption0(fd, IPPROTO_IPV6, IPV6_TCLASS, &optval, sizeof(optval));
if (rc < 0 && errno != ENOPROTOOPT) {
netty_unix_socket_setOptionHandleError(env, errno);
}
if (socketType == AF_INET6) {
// This call will put an exception on the stack to be processed once the JNI calls completes if
// setsockopt failed and return a negative value.
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 */
#ifdef __linux__
else {
netty_unix_socket_setOption(env, fd, IPPROTO_IP, IP_TOS, &optval, sizeof(optval));
// Previous call successful now try to set also for ipv4
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
}
} 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) {
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) {
/* macOS may throw an error if IPv6 is supported and it is not consulted first */
int optval;
if (socketType == AF_INET6) {
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);
return -1;
}
}
} else {
if (netty_unix_socket_getOption(env, fd, IPPROTO_IP, IP_TOS, &optval, sizeof(optval)) == -1) {
return -1;
}
}
return optval;
}