[#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 01daefe925
commit f62012cba5
5 changed files with 46 additions and 21 deletions

View File

@ -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) { jint getOption(JNIEnv *env, jint fd, int level, int optname, const void *optval, socklen_t optlen) {
int code; int code;
code = getsockopt(fd, level, optname, &optval, &optlen); code = getsockopt(fd, level, optname, optval, &optlen);
if (code == 0) { if (code == 0) {
return 0; return 0;
} }
@ -750,14 +750,28 @@ JNIEXPORT jboolean JNICALL Java_io_netty_channel_epoll_Native_connect(JNIEnv * e
return JNI_TRUE; return JNI_TRUE;
} }
JNIEXPORT void JNICALL Java_io_netty_channel_epoll_Native_finishConnect(JNIEnv * env, jclass clazz, jint fd) { JNIEXPORT jboolean JNICALL Java_io_netty_channel_epoll_Native_finishConnect(JNIEnv * env, jclass clazz, jint fd) {
// connect done, check for error // 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 optval;
int res = getOption(env, fd, SOL_SOCKET, SO_ERROR, &optval, sizeof(optval)); int res = getOption(env, fd, SOL_SOCKET, SO_ERROR, &optval, sizeof(optval));
if (res == 0) { if (res != 0) {
return; // 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) { JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_accept(JNIEnv * env, jclass clazz, jint fd) {

View File

@ -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_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); 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); 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); 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); 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); 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); AbstractEpollChannel ch = ids.get(id);
if (ch != null) { if (ch != null) {
AbstractEpollUnsafe unsafe = (AbstractEpollUnsafe) ch.unsafe(); AbstractEpollUnsafe unsafe = (AbstractEpollUnsafe) ch.unsafe();
if (write) { if (write && ch.isOpen()) {
// force flush of data as the epoll is writable again // force flush of data as the epoll is writable again
unsafe.epollOutReady(); unsafe.epollOutReady();
} }
if (read) { if (read && ch.isOpen()) {
// Something is ready to read, so consume it now // Something is ready to read, so consume it now
unsafe.epollInReady(); unsafe.epollInReady();
} }
if (close) { if (close && ch.isOpen()) {
unsafe.epollRdHupReady(); unsafe.epollRdHupReady();
} }
} }

View File

@ -485,9 +485,13 @@ public final class EpollSocketChannel extends AbstractEpollChannel implements So
assert eventLoop().inEventLoop(); assert eventLoop().inEventLoop();
boolean connectStillInProgress = false;
try { try {
boolean wasActive = isActive(); boolean wasActive = isActive();
doFinishConnect(); if (!doFinishConnect()) {
connectStillInProgress = true;
return;
}
fulfillConnectPromise(connectPromise, wasActive); fulfillConnectPromise(connectPromise, wasActive);
} catch (Throwable t) { } catch (Throwable t) {
if (t instanceof ConnectException) { if (t instanceof ConnectException) {
@ -498,12 +502,14 @@ public final class EpollSocketChannel extends AbstractEpollChannel implements So
fulfillConnectPromise(connectPromise, t); fulfillConnectPromise(connectPromise, t);
} finally { } finally {
// Check for null as the connectTimeoutFuture is only created if a connectTimeoutMillis > 0 is used if (!connectStillInProgress) {
// See https://github.com/netty/netty/issues/1770 // Check for null as the connectTimeoutFuture is only created if a connectTimeoutMillis > 0 is used
if (connectTimeoutFuture != null) { // See https://github.com/netty/netty/issues/1770
connectTimeoutFuture.cancel(false); 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 * Finish the connect
*/ */
private void doFinishConnect() throws Exception { private boolean doFinishConnect() throws Exception {
Native.finishConnect(fd); if (Native.finishConnect(fd)) {
clearEpollOut(); clearEpollOut();
return true;
} else {
setEpollOut();
return false;
}
} }
/** /**

View File

@ -113,7 +113,7 @@ final class Native {
return connect(fd, address, scopeId, port); return connect(fd, address, scopeId, port);
} }
public static native boolean connect(int fd, byte[] address, int scopeId, int port) throws IOException; 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 remoteAddress(int fd);
public static native InetSocketAddress localAddress(int fd); public static native InetSocketAddress localAddress(int fd);