[#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:
Aaron Riekenberg 2014-03-09 07:41:14 -05:00 committed by Norman Maurer
parent 3c1bcb7279
commit 223deb255e
5 changed files with 46 additions and 21 deletions

View File

@ -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;
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) {

View File

@ -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);

View File

@ -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();
}
}

View File

@ -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,12 +462,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;
}
}
@ -504,9 +510,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;
}
}
/**

View File

@ -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);