Call finishConnect() before try to call read(...) / write(...) when using NIO

Motivation:

The JDK implementation of SocketChannel has an internal state that is tracked for its operations. Because of this we need to ensure we call finishConnect() before try to call read(...) / write(...) as otherwise it may produce a NotYetConnectedException.

Modifications:

First process OP_CONNECT flag.

Result:

No more possibility of NotYetConnectedException because OP_CONNECT is handled not early enough when processing interestedOps for a Channel.
This commit is contained in:
Norman Maurer 2016-08-22 08:25:32 +02:00
parent 54b1a100f4
commit 30fe2e868f

View File

@ -613,6 +613,18 @@ public final class NioEventLoop extends SingleThreadEventLoop {
try { try {
int readyOps = k.readyOps(); int readyOps = k.readyOps();
// We first need to call finishConnect() before try to trigger a read(...) or write(...) as otherwise
// the NIO JDK channel implementation may throw a NotYetConnectedException.
if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
// remove OP_CONNECT as otherwise Selector.select(..) will always return without blocking
// See https://github.com/netty/netty/issues/924
int ops = k.interestOps();
ops &= ~SelectionKey.OP_CONNECT;
k.interestOps(ops);
unsafe.finishConnect();
}
// Also check for readOps of 0 to workaround possible JDK bug which may otherwise lead // Also check for readOps of 0 to workaround possible JDK bug which may otherwise lead
// to a spin loop // to a spin loop
if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) { if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
@ -626,15 +638,6 @@ public final class NioEventLoop extends SingleThreadEventLoop {
// Call forceFlush which will also take care of clear the OP_WRITE once there is nothing left to write // Call forceFlush which will also take care of clear the OP_WRITE once there is nothing left to write
ch.unsafe().forceFlush(); ch.unsafe().forceFlush();
} }
if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
// remove OP_CONNECT as otherwise Selector.select(..) will always return without blocking
// See https://github.com/netty/netty/issues/924
int ops = k.interestOps();
ops &= ~SelectionKey.OP_CONNECT;
k.interestOps(ops);
unsafe.finishConnect();
}
} catch (CancelledKeyException ignored) { } catch (CancelledKeyException ignored) {
unsafe.close(unsafe.voidPromise()); unsafe.close(unsafe.voidPromise());
} }