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 c3418faddd..bcaa1f8975 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 @@ -105,7 +105,7 @@ jint epollCtl(JNIEnv * env, jint efd, int op, jint fd, jint flags, jint id) { jint getOption(JNIEnv *env, jint fd, int level, int optname, const void *optval, socklen_t optlen) { int code; - code = getsockopt(fd, level, optname, &optval, &optlen); + code = getsockopt(fd, level, optname, optval, &optlen); if (code == 0) { return 0; } @@ -750,14 +750,28 @@ JNIEXPORT jboolean JNICALL Java_io_netty_channel_epoll_Native_connect(JNIEnv * e return JNI_TRUE; } -JNIEXPORT void JNICALL Java_io_netty_channel_epoll_Native_finishConnect(JNIEnv * env, jclass clazz, jint fd) { - // connect done, check for error +JNIEXPORT jboolean JNICALL Java_io_netty_channel_epoll_Native_finishConnect(JNIEnv * env, jclass clazz, jint fd) { + // connect may be done + // return true if connection finished successfully + // return false if connection is still in progress + // throw exception if connection failed int optval; - int res = getOption(env, fd, SOL_SOCKET, SO_ERROR, &optval, sizeof(optval)); - if (res == 0) { - return; + int res = getOption(env, fd, SOL_SOCKET, SO_ERROR, &optval, sizeof(optval)); + if (res != 0) { + // getOption failed + throwIOException(env, exceptionMessage("finishConnect getOption failed: ", res)); + return JNI_FALSE; + } else if (optval == EINPROGRESS) { + // connect still in progress + return JNI_FALSE; + } else if (optval == 0) { + // connect succeeded + return JNI_TRUE; + } else { + // connect failed + throwIOException(env, exceptionMessage("Unable to connect to remote host: ", optval)); + return JNI_FALSE; } - throwIOException(env, exceptionMessage("Unable to connect to remote host: ", optval)); } JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_accept(JNIEnv * env, jclass clazz, jint fd) { 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 76753cca2b..6b6943da45 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 @@ -42,7 +42,7 @@ jint Java_io_netty_channel_epoll_Native_socket(JNIEnv * env, jclass clazz); void Java_io_netty_channel_epoll_Native_bind(JNIEnv * env, jclass clazz, jint fd, jbyteArray address, jint scopeId, jint port); void Java_io_netty_channel_epoll_Native_listen(JNIEnv * env, jclass clazz, jint fd, jint backlog); jboolean Java_io_netty_channel_epoll_Native_connect(JNIEnv * env, jclass clazz, jint fd, jbyteArray address, jint scopeId, jint port); -void Java_io_netty_channel_epoll_Native_finishConnect(JNIEnv * env, jclass clazz, jint fd); +jboolean Java_io_netty_channel_epoll_Native_finishConnect(JNIEnv * env, jclass clazz, jint fd); jint Java_io_netty_channel_epoll_Native_accept(JNIEnv * env, jclass clazz, jint fd); jlong Java_io_netty_channel_epoll_Native_sendfile(JNIEnv *env, jclass clazz, jint fd, jobject fileRegion, jlong off, jlong len); jobject Java_io_netty_channel_epoll_Native_remoteAddress(JNIEnv * env, jclass clazz, jint fd); 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 8d110146a3..409284a96d 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 @@ -323,15 +323,15 @@ final class EpollEventLoop extends SingleThreadEventLoop { AbstractEpollChannel ch = ids.get(id); if (ch != null) { AbstractEpollUnsafe unsafe = (AbstractEpollUnsafe) ch.unsafe(); - if (write) { + if (write && ch.isOpen()) { // force flush of data as the epoll is writable again unsafe.epollOutReady(); } - if (read) { + if (read && ch.isOpen()) { // Something is ready to read, so consume it now unsafe.epollInReady(); } - if (close) { + if (close && ch.isOpen()) { unsafe.epollRdHupReady(); } } diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollSocketChannel.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollSocketChannel.java index 494d71c5ae..3b0e985001 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollSocketChannel.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollSocketChannel.java @@ -485,9 +485,13 @@ public final class EpollSocketChannel extends AbstractEpollChannel implements So assert eventLoop().inEventLoop(); + boolean connectStillInProgress = false; try { boolean wasActive = isActive(); - doFinishConnect(); + if (!doFinishConnect()) { + connectStillInProgress = true; + return; + } fulfillConnectPromise(connectPromise, wasActive); } catch (Throwable t) { if (t instanceof ConnectException) { @@ -498,12 +502,14 @@ public final class EpollSocketChannel extends AbstractEpollChannel implements So fulfillConnectPromise(connectPromise, t); } finally { - // Check for null as the connectTimeoutFuture is only created if a connectTimeoutMillis > 0 is used - // See https://github.com/netty/netty/issues/1770 - if (connectTimeoutFuture != null) { - connectTimeoutFuture.cancel(false); + if (!connectStillInProgress) { + // Check for null as the connectTimeoutFuture is only created if a connectTimeoutMillis > 0 is used + // See https://github.com/netty/netty/issues/1770 + if (connectTimeoutFuture != null) { + connectTimeoutFuture.cancel(false); + } + connectPromise = null; } - connectPromise = null; } } @@ -544,9 +550,14 @@ public final class EpollSocketChannel extends AbstractEpollChannel implements So /** * Finish the connect */ - private void doFinishConnect() throws Exception { - Native.finishConnect(fd); - clearEpollOut(); + private boolean doFinishConnect() throws Exception { + if (Native.finishConnect(fd)) { + clearEpollOut(); + return true; + } else { + setEpollOut(); + return false; + } } /** 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 8633743b33..74a85e9c1e 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 @@ -113,7 +113,7 @@ final class Native { return connect(fd, address, scopeId, port); } public static native boolean connect(int fd, byte[] address, int scopeId, int port) throws IOException; - public static native void finishConnect(int fd) throws IOException; + public static native boolean finishConnect(int fd) throws IOException; public static native InetSocketAddress remoteAddress(int fd); public static native InetSocketAddress localAddress(int fd);