From f51465977e19e56026c15c7360fbdd211fbd44b0 Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Mon, 1 Jun 2015 21:17:51 +0200 Subject: [PATCH] [#3848] Respect EPOLLERR event Motivation: Some glibc/kernel versions will trigger an EPOLLERR event to notify about failed connect and not an EPOLLOUT. Also EPOLLERR may be triggered when a connection is broke. Modification: React on EPOLLERR like if an EPOLLOUT / EPOLLIN was received, this will work in all cases as we handle errors in EPOLLOUT / EPOLLIN anyway. Result: Correctly detect errors. --- .../src/main/c/io_netty_channel_epoll_Native.c | 4 ++++ .../src/main/c/io_netty_channel_epoll_Native.h | 1 + .../io/netty/channel/epoll/EpollEventLoop.java | 16 ++++++++++++++-- .../main/java/io/netty/channel/epoll/Native.java | 2 ++ 4 files changed, 21 insertions(+), 2 deletions(-) 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 9ecdc95eae..a277d1695a 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 @@ -1615,6 +1615,10 @@ JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_epollrdhup(JNIEnv* env return EPOLLRDHUP; } +JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_epollerr(JNIEnv* env, jclass clazz) { + return EPOLLERR; +} + JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_sizeofEpollEvent(JNIEnv* env, jclass clazz) { return sizeof(struct epoll_event); } 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 4b0dc93282..4708557ab1 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 @@ -121,6 +121,7 @@ jint Java_io_netty_channel_epoll_Native_epollin(JNIEnv* env, jclass clazz); jint Java_io_netty_channel_epoll_Native_epollout(JNIEnv* env, jclass clazz); jint Java_io_netty_channel_epoll_Native_epollrdhup(JNIEnv* env, jclass clazz); jint Java_io_netty_channel_epoll_Native_epollet(JNIEnv* env, jclass clazz); +jint Java_io_netty_channel_epoll_Native_epollerr(JNIEnv* env, jclass clazz); jint Java_io_netty_channel_epoll_Native_sizeofEpollEvent(JNIEnv* env, jclass clazz); jint Java_io_netty_channel_epoll_Native_offsetofEpollData(JNIEnv* env, jclass clazz); diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollEventLoop.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollEventLoop.java index f6bab7ef28..e01709e545 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollEventLoop.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollEventLoop.java @@ -317,10 +317,18 @@ final class EpollEventLoop extends SingleThreadEventLoop { // past. AbstractEpollUnsafe unsafe = (AbstractEpollUnsafe) ch.unsafe(); + // Check if an error was the cause of the wakeup. + boolean err = (ev & Native.EPOLLERR) != 0; + // First check for EPOLLOUT as we may need to fail the connect ChannelPromise before try // to read from the file descriptor. // See https://github.com/netty/netty/issues/3785 - if ((ev & Native.EPOLLOUT) != 0 && ch.isOpen()) { + // + // It is possible for an EPOLLOUT or EPOLLERR to be generated when a connection is refused. + // In either case epollOutReady() will do the correct thing (finish connecting, or fail + // the connection). + // See https://github.com/netty/netty/issues/3848 + if (err || ((ev & Native.EPOLLOUT) != 0) && ch.isOpen()) { // Force flush of data as the epoll is writable again unsafe.epollOutReady(); } @@ -331,7 +339,11 @@ final class EpollEventLoop extends SingleThreadEventLoop { if ((ev & Native.EPOLLRDHUP) != 0) { unsafe.epollRdHupReady(); } - if ((ev & Native.EPOLLIN) != 0 && ch.isOpen()) { + + // If EPOLLOUT or EPOLLING was received and the channel is still open call epollInReady(). + // This will try to read from the underlying filedescriptor and so notify the user about the + // error. + if ((err || (ev & Native.EPOLLIN) != 0) && ch.isOpen()) { // The Channel is still open and there is something to read. Do it now. unsafe.epollInReady(); } 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 6195818400..ede80dcef6 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 @@ -55,6 +55,7 @@ public final class Native { public static final int EPOLLOUT = epollout(); public static final int EPOLLRDHUP = epollrdhup(); public static final int EPOLLET = epollet(); + public static final int EPOLLERR = epollerr(); public static final int IOV_MAX = iovMax(); public static final int UIO_MAX_IOV = uioMaxIov(); @@ -701,6 +702,7 @@ public final class Native { private static native int epollout(); private static native int epollrdhup(); private static native int epollet(); + private static native int epollerr(); private static native long ssizeMax(); private Native() {