From 30fe2e868fcc99d24046e505f9406067ba6e9d07 Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Mon, 22 Aug 2016 08:25:32 +0200 Subject: [PATCH] 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. --- .../io/netty/channel/nio/NioEventLoop.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/transport/src/main/java/io/netty/channel/nio/NioEventLoop.java b/transport/src/main/java/io/netty/channel/nio/NioEventLoop.java index c59e0109e0..677d1c81fe 100644 --- a/transport/src/main/java/io/netty/channel/nio/NioEventLoop.java +++ b/transport/src/main/java/io/netty/channel/nio/NioEventLoop.java @@ -613,6 +613,18 @@ public final class NioEventLoop extends SingleThreadEventLoop { try { 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 // to a spin loop 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 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) { unsafe.close(unsafe.voidPromise()); }