From 9e7a5693f3fa0f8f7bedcb68026c057d3072e5b5 Mon Sep 17 00:00:00 2001 From: Tomas Olvecky Date: Mon, 31 Aug 2015 00:11:39 +0200 Subject: [PATCH] Add TCP_USER_TIMEOUT Motivation: See #4174. Modifications: Modify transport-native-epoll to allow setting TCP_USER_TIMEOUT. Result: Hanging connections that are written into will get timeouted. --- .../main/c/io_netty_channel_epoll_Native.c | 12 +++++++++++ .../channel/epoll/EpollChannelOption.java | 1 + .../epoll/EpollSocketChannelConfig.java | 20 +++++++++++++++++++ .../java/io/netty/channel/epoll/Native.java | 2 ++ 4 files changed, 35 insertions(+) diff --git a/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.c b/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.c index cc1915fefa..5fcc2e77ae 100644 --- a/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.c +++ b/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.c @@ -1271,6 +1271,10 @@ JNIEXPORT void Java_io_netty_channel_epoll_Native_setTcpKeepCnt(JNIEnv* env, jcl setOption(env, fd, IPPROTO_TCP, TCP_KEEPCNT, &optval, sizeof(optval)); } +JNIEXPORT void Java_io_netty_channel_epoll_Native_setTcpUserTimeout(JNIEnv* env, jclass clazz, jint fd, jint optval) { + setOption(env, fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &optval, sizeof(optval)); +} + JNIEXPORT void JNICALL Java_io_netty_channel_epoll_Native_setIpFreeBind(JNIEnv* env, jclass clazz, jint fd, jint optval) { setOption(env, fd, IPPROTO_IP, IP_FREEBIND, &optval, sizeof(optval)); } @@ -1391,6 +1395,14 @@ JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_getTcpKeepCnt(JNIEnv* return optval; } +JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_getTcpUserTimeout(JNIEnv* env, jclass clazz, jint fd) { + int optval; + if (getOption(env, fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &optval, sizeof(optval)) == -1) { + return -1; + } + return optval; +} + JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_isIpFreeBind(JNIEnv* env, jclass clazz, jint fd) { int optval; if (getOption(env, fd, IPPROTO_TCP, IP_FREEBIND, &optval, sizeof(optval)) == -1) { diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollChannelOption.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollChannelOption.java index 4a3c5d19b5..1f231f2f80 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollChannelOption.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollChannelOption.java @@ -26,6 +26,7 @@ public final class EpollChannelOption extends ChannelOption { public static final ChannelOption TCP_KEEPIDLE = valueOf("TCP_KEEPIDLE"); public static final ChannelOption TCP_KEEPINTVL = valueOf("TCP_KEEPINTVL"); public static final ChannelOption TCP_KEEPCNT = valueOf("TCP_KEEPCNT"); + public static final ChannelOption TCP_USER_TIMEOUT = valueOf("TCP_USER_TIMEOUT"); public static final ChannelOption IP_FREEBIND = valueOf("IP_FREEBIND"); public static final ChannelOption DOMAIN_SOCKET_READ_MODE = diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollSocketChannelConfig.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollSocketChannelConfig.java index 2f89403a1b..65337c3e23 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollSocketChannelConfig.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollSocketChannelConfig.java @@ -94,6 +94,9 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement if (option == EpollChannelOption.TCP_KEEPCNT) { return (T) Integer.valueOf(getTcpKeepCnt()); } + if (option == EpollChannelOption.TCP_USER_TIMEOUT) { + return (T) Integer.valueOf(getTcpUserTimeout()); + } return super.getOption(option); } @@ -127,6 +130,8 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement setTcpKeepCntl((Integer) value); } else if (option == EpollChannelOption.TCP_KEEPINTVL) { setTcpKeepIntvl((Integer) value); + } else if (option == EpollChannelOption.TCP_USER_TIMEOUT) { + setTcpUserTimeout((Integer) value); } else { return super.setOption(option, value); } @@ -205,6 +210,13 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement return Native.getTcpKeepCnt(channel.fd().intValue()); } + /** + * Get the {@code TCP_USER_TIMEOUT} option on the socket. See {@code man 7 tcp} for more details. + */ + public int getTcpUserTimeout() { + return Native.getTcpUserTimeout(channel.fd().intValue()); + } + @Override public EpollSocketChannelConfig setKeepAlive(boolean keepAlive) { Native.setKeepAlive(channel.fd().intValue(), keepAlive ? 1 : 0); @@ -297,6 +309,14 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement return this; } + /** + * Set the {@code TCP_USER_TIMEOUT} option on the socket. See {@code man 7 tcp} for more details. + */ + public EpollSocketChannelConfig setTcpUserTimeout(int milliseconds) { + Native.setTcpUserTimeout(channel.fd().intValue(), milliseconds); + return this; + } + @Override public boolean isAllowHalfClosure() { return allowHalfClosure; diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/Native.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/Native.java index 4def6e42b0..3a7136809d 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/Native.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/Native.java @@ -635,6 +635,7 @@ public final class Native { public static native int getTcpKeepIdle(int fd); public static native int getTcpKeepIntvl(int fd); public static native int getTcpKeepCnt(int fd); + public static native int getTcpUserTimeout(int milliseconds); public static native int getSoError(int fd); public static native int isIpFreeBind(int fd); @@ -652,6 +653,7 @@ public final class Native { public static native void setTcpKeepIdle(int fd, int seconds); public static native void setTcpKeepIntvl(int fd, int seconds); public static native void setTcpKeepCnt(int fd, int probes); + public static native void setTcpUserTimeout(int fd, int milliseconds); public static native void setIpFreeBind(int fd, int freeBind); public static void tcpInfo(int fd, EpollTcpInfo info) { tcpInfo0(fd, info.info);