[#2280] Correct logic in Native.finishConnect. Fix use of optval parameter in c getOption function. In epoll event loop, check that channel is open before processing event.
This commit is contained in:
parent
3c1bcb7279
commit
223deb255e
@ -102,7 +102,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;
|
||||
}
|
||||
@ -699,14 +699,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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_accept(JNIEnv * env, jclass clazz, jint fd) {
|
||||
|
@ -40,7 +40,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);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -445,9 +445,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) {
|
||||
@ -458,6 +462,7 @@ public final class EpollSocketChannel extends AbstractEpollChannel implements So
|
||||
|
||||
fulfillConnectPromise(connectPromise, t);
|
||||
} finally {
|
||||
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) {
|
||||
@ -466,6 +471,7 @@ public final class EpollSocketChannel extends AbstractEpollChannel implements So
|
||||
connectPromise = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void epollOutReady() {
|
||||
@ -504,9 +510,14 @@ public final class EpollSocketChannel extends AbstractEpollChannel implements So
|
||||
/**
|
||||
* Finish the connect
|
||||
*/
|
||||
private void doFinishConnect() throws Exception {
|
||||
Native.finishConnect(fd);
|
||||
private boolean doFinishConnect() throws Exception {
|
||||
if (Native.finishConnect(fd)) {
|
||||
clearEpollOut();
|
||||
return true;
|
||||
} else {
|
||||
setEpollOut();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -109,7 +109,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);
|
||||
|
Loading…
Reference in New Issue
Block a user