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 d9c1362706..c1ef8452d5 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 @@ -1079,6 +1079,18 @@ JNIEXPORT void JNICALL Java_io_netty_channel_epoll_Native_setBroadcast(JNIEnv * setOption(env, fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)); } +JNIEXPORT void JNICALL Java_io_netty_channel_epoll_Native_setTcpKeepIdle(JNIEnv *env, jclass clazz, jint fd, jint optval) { + setOption(env, fd, SOL_TCP, TCP_KEEPIDLE, &optval, sizeof(optval)); +} + +JNIEXPORT void JNICALL Java_io_netty_channel_epoll_Native_setTcpKeepIntvl(JNIEnv *env, jclass clazz, jint fd, jint optval) { + setOption(env, fd, SOL_TCP, TCP_KEEPINTVL, &optval, sizeof(optval)); +} + +JNIEXPORT void Java_io_netty_channel_epoll_Native_setTcpKeepCnt(JNIEnv *env, jclass clazz, jint fd, jint optval) { + setOption(env, fd, SOL_TCP, TCP_KEEPCNT, &optval, sizeof(optval)); +} + JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_isReuseAddresss(JNIEnv *env, jclass clazz, jint fd) { int optval; if (getOption(env, fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) { @@ -1155,6 +1167,30 @@ JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_isBroadcast(JNIEnv *en return optval; } +JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_getTcpKeepIdle(JNIEnv *env, jclass clazz, jint fd) { + int optval; + if (getOption(env, fd, SOL_TCP, TCP_KEEPIDLE, &optval, sizeof(optval)) == -1) { + return -1; + } + return optval; +} + +JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_getTcpKeepIntvl(JNIEnv *env, jclass clazz, jint fd) { + int optval; + if (getOption(env, fd, SOL_TCP, TCP_KEEPINTVL, &optval, sizeof(optval)) == -1) { + return -1; + } + return optval; +} + +JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_getTcpKeepCnt(JNIEnv *env, jclass clazz, jint fd) { + int optval; + if (getOption(env, fd, SOL_TCP, TCP_KEEPCNT, &optval, sizeof(optval)) == -1) { + return -1; + } + return optval; +} + JNIEXPORT jstring JNICALL Java_io_netty_channel_epoll_Native_kernelVersion(JNIEnv *env, jclass clazz) { struct utsname name; @@ -1165,4 +1201,4 @@ JNIEXPORT jstring JNICALL Java_io_netty_channel_epoll_Native_kernelVersion(JNIEn int err = errno; throwRuntimeException(env, exceptionMessage("Error during uname(...): ", err)); return NULL; -} \ No newline at end of file +} diff --git a/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.h b/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.h index c9eb68a599..296d24a4f1 100644 --- a/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.h +++ b/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.h @@ -63,6 +63,10 @@ void Java_io_netty_channel_epoll_Native_setTcpCork(JNIEnv *env, jclass clazz, ji void Java_io_netty_channel_epoll_Native_setSoLinger(JNIEnv *env, jclass clazz, jint fd, jint optval); void Java_io_netty_channel_epoll_Native_setTrafficClass(JNIEnv *env, jclass clazz, jint fd, jint optval); void Java_io_netty_channel_epoll_Native_setBroadcast(JNIEnv *env, jclass clazz, jint fd, jint optval); +void Java_io_netty_channel_epoll_Native_setTcpKeepIdle(JNIEnv *env, jclass clazz, jint fd, jint optval); +void Java_io_netty_channel_epoll_Native_setTcpKeepIntvl(JNIEnv *env, jclass clazz, jint fd, jint optval); +void Java_io_netty_channel_epoll_Native_setTcpKeepCnt(JNIEnv *env, jclass clazz, jint fd, jint optval); + jint Java_io_netty_channel_epoll_Native_isReuseAddresss(JNIEnv *env, jclass clazz, jint fd); jint Java_io_netty_channel_epoll_Native_isReusePort(JNIEnv *env, jclass clazz, jint fd); jint Java_io_netty_channel_epoll_Native_isTcpNoDelay(JNIEnv *env, jclass clazz, jint fd); @@ -72,4 +76,8 @@ jint Java_io_netty_channel_epoll_Native_isTcpCork(JNIEnv *env, jclass clazz, jin jint Java_io_netty_channel_epoll_Native_getSoLinger(JNIEnv *env, jclass clazz, jint fd); jint Java_io_netty_channel_epoll_Native_getTrafficClass(JNIEnv *env, jclass clazz, jint fd); jint Java_io_netty_channel_epoll_Native_isBroadcast(JNIEnv *env, jclass clazz, jint fd); +jint Java_io_netty_channel_epoll_Native_getTcpKeepIdle(JNIEnv *env, jclass clazz, jint fd); +jint Java_io_netty_channel_epoll_Native_getTcpKeepIntvl(JNIEnv *env, jclass clazz, jint fd); +jint Java_io_netty_channel_epoll_Native_getTcpKeepCnt(JNIEnv *env, jclass clazz, jint fd); + jstring Java_io_netty_channel_epoll_Native_kernelVersion(JNIEnv *env, jclass clazz); 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 060874563b..b3771945ee 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 @@ -22,6 +22,9 @@ public final class EpollChannelOption { public static final ChannelOption TCP_CORK = ChannelOption.valueOf(T, "TCP_CORK"); public static final ChannelOption SO_REUSEPORT = ChannelOption.valueOf(T, "SO_REUSEPORT"); + public static final ChannelOption TCP_KEEPIDLE = ChannelOption.valueOf(T, "TCP_KEEPIDLE"); + public static final ChannelOption TCP_KEEPINTVL = ChannelOption.valueOf(T, "TCP_KEEPINTVL"); + public static final ChannelOption TCP_KEEPCNT = ChannelOption.valueOf(T, "TCP_KEEPCNT"); private EpollChannelOption() { } 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 171b9821de..d43063feec 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 @@ -50,7 +50,8 @@ public final class EpollSocketChannelConfig extends DefaultChannelConfig return getOptions( super.getOptions(), SO_RCVBUF, SO_SNDBUF, TCP_NODELAY, SO_KEEPALIVE, SO_REUSEADDR, SO_LINGER, IP_TOS, - ALLOW_HALF_CLOSURE, EpollChannelOption.TCP_CORK); + ALLOW_HALF_CLOSURE, EpollChannelOption.TCP_CORK, EpollChannelOption.TCP_KEEPCNT, + EpollChannelOption.TCP_KEEPIDLE, EpollChannelOption.TCP_KEEPINTVL); } @SuppressWarnings("unchecked") @@ -83,6 +84,15 @@ public final class EpollSocketChannelConfig extends DefaultChannelConfig if (option == EpollChannelOption.TCP_CORK) { return (T) Boolean.valueOf(isTcpCork()); } + if (option == EpollChannelOption.TCP_KEEPIDLE) { + return (T) Integer.valueOf(getTcpKeepIdle()); + } + if (option == EpollChannelOption.TCP_KEEPINTVL) { + return (T) Integer.valueOf(getTcpKeepIntvl()); + } + if (option == EpollChannelOption.TCP_KEEPCNT) { + return (T) Integer.valueOf(getTcpKeepCnt()); + } return super.getOption(option); } @@ -108,6 +118,12 @@ public final class EpollSocketChannelConfig extends DefaultChannelConfig setAllowHalfClosure((Boolean) value); } else if (option == EpollChannelOption.TCP_CORK) { setTcpCork((Boolean) value); + } else if (option == EpollChannelOption.TCP_KEEPIDLE) { + setTcpKeepIdle((Integer) value); + } else if (option == EpollChannelOption.TCP_KEEPCNT) { + setTcpKeepCntl((Integer) value); + } else if (option == EpollChannelOption.TCP_KEEPINTVL) { + setTcpKeepIntvl((Integer) value); } else { return super.setOption(option, value); } @@ -150,10 +166,34 @@ public final class EpollSocketChannelConfig extends DefaultChannelConfig return Native.isTcpNoDelay(channel.fd) == 1; } + /** + * Get the {@code TCP_CORK} option on the socket. See {@code man 7 tcp} for more details. + */ public boolean isTcpCork() { return Native.isTcpCork(channel.fd) == 1; } + /** + * Get the {@code TCP_KEEPIDLE} option on the socket. See {@code man 7 tcp} for more details. + */ + public int getTcpKeepIdle() { + return Native.getTcpKeepIdle(channel.fd); + } + + /** + * Get the {@code TCP_KEEPINTVL} option on the socket. See {@code man 7 tcp} for more details. + */ + public int getTcpKeepIntvl() { + return Native.getTcpKeepIntvl(channel.fd); + } + + /** + * Get the {@code TCP_KEEPCNT} option on the socket. See {@code man 7 tcp} for more details. + */ + public int getTcpKeepCnt() { + return Native.getTcpKeepCnt(channel.fd); + } + @Override public EpollSocketChannelConfig setKeepAlive(boolean keepAlive) { Native.setKeepAlive(channel.fd, keepAlive ? 1 : 0); @@ -196,6 +236,9 @@ public final class EpollSocketChannelConfig extends DefaultChannelConfig return this; } + /** + * Set the {@code TCP_CORK} option on the socket. See {@code man 7 tcp} for more details. + */ public EpollSocketChannelConfig setTcpCork(boolean tcpCork) { Native.setTcpCork(channel.fd, tcpCork ? 1 : 0); return this; @@ -207,6 +250,30 @@ public final class EpollSocketChannelConfig extends DefaultChannelConfig return this; } + /** + * Set the {@code TCP_KEEPIDLE} option on the socket. See {@code man 7 tcp} for more details. + */ + public EpollSocketChannelConfig setTcpKeepIdle(int seconds) { + Native.setTcpKeepIdle(channel.fd, seconds); + return this; + } + + /** + * Set the {@code TCP_KEEPINTVL} option on the socket. See {@code man 7 tcp} for more details. + */ + public EpollSocketChannelConfig setTcpKeepIntvl(int seconds) { + Native.setTcpKeepIntvl(channel.fd, seconds); + return this; + } + + /** + * Set the {@code TCP_KEEPCNT} option on the socket. See {@code man 7 tcp} for more details. + */ + public EpollSocketChannelConfig setTcpKeepCntl(int probes) { + Native.setTcpKeepCnt(channel.fd, probes); + 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 3baae8212b..2e9cb439e5 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 @@ -179,6 +179,9 @@ final class Native { public static native int getSoLinger(int fd); public static native int getTrafficClass(int fd); public static native int isBroadcast(int fd); + public static native int getTcpKeepIdle(int fd); + public static native int getTcpKeepIntvl(int fd); + public static native int getTcpKeepCnt(int fd); public static native void setKeepAlive(int fd, int keepAlive); public static native void setReceiveBufferSize(int fd, int receiveBufferSize); @@ -190,6 +193,9 @@ final class Native { public static native void setSoLinger(int fd, int soLinger); public static native void setTrafficClass(int fd, int tcpNoDelay); public static native void setBroadcast(int fd, int broadcast); + 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); private static NativeInetAddress toNativeInetAddress(InetAddress addr) { byte[] bytes = addr.getAddress();