Fix race-condition when closing a NioSocketChannel or EpollSocketChannel

Motivation:

Fix a race-condition when closing NioSocketChannel or EpollSocketChannel while try to detect if a close executor should be used and the underlying socket was already closed. This could lead to an exception that then leave the channel / in an invalid state and so could lead to side-effects like heavy CPU usage.

Modifications:

Catch possible socket exception while try to get the SO_LINGER options from the underlying socket.

Result:

No more race-condition when closing the channel is possible with bad side-effects.
This commit is contained in:
Norman Maurer 2015-11-24 04:54:39 +01:00
parent 4978266d52
commit 0ec34b5f76
2 changed files with 19 additions and 6 deletions

View File

@ -219,10 +219,16 @@ public final class EpollSocketChannel extends AbstractEpollStreamChannel impleme
private final class EpollSocketChannelUnsafe extends EpollStreamUnsafe {
@Override
protected Executor closeExecutor() {
// Check isOpen() first as otherwise it will throw a RuntimeException
// when call getSoLinger() as the fd is not valid anymore.
if (isOpen() && config().getSoLinger() > 0) {
return GlobalEventExecutor.INSTANCE;
try {
// Check isOpen() first as otherwise it will throw a RuntimeException
// when call getSoLinger() as the fd is not valid anymore.
if (isOpen() && config().getSoLinger() > 0) {
return GlobalEventExecutor.INSTANCE;
}
} catch (Throwable ignore) {
// Ignore the error as the underlying channel may be closed in the meantime and so
// getSoLinger() may produce an exception. In this case we just return null.
// See https://github.com/netty/netty/issues/4449
}
return null;
}

View File

@ -36,6 +36,7 @@ import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
@ -336,8 +337,14 @@ public class NioSocketChannel extends AbstractNioByteChannel implements io.netty
private final class NioSocketChannelUnsafe extends NioByteUnsafe {
@Override
protected Executor closeExecutor() {
if (javaChannel().isOpen() && config().getSoLinger() > 0) {
return GlobalEventExecutor.INSTANCE;
try {
if (javaChannel().isOpen() && config().getSoLinger() > 0) {
return GlobalEventExecutor.INSTANCE;
}
} catch (Throwable ignore) {
// Ignore the error as the underlying channel may be closed in the meantime and so
// getSoLinger() may produce an exception. In this case we just return null.
// See https://github.com/netty/netty/issues/4449
}
return null;
}