Correct throw ClosedChannelException when attempt to call shutdown*(...) on closed EpollSocketChannel.
Motivition: NIO throws ClosedChannelException when a user tries to call shutdown*() on a closed Channel. We should do the same for the EPOLL transport Modification: Throw ClosedChannelException when a user tries to call shutdown*() on a closed channel. Result: Consistent behavior.
This commit is contained in:
parent
3051df8961
commit
eb450d8b2f
@ -25,6 +25,8 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.nio.channels.ClosedChannelException;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
@ -76,6 +78,48 @@ public class SocketShutdownOutputBySelfTest extends AbstractClientSocketTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 30000)
|
||||||
|
public void testShutdownOutputAfterClosed() throws Throwable {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testShutdownOutputAfterClosed(Bootstrap cb) throws Throwable {
|
||||||
|
TestHandler h = new TestHandler();
|
||||||
|
ServerSocket ss = new ServerSocket();
|
||||||
|
Socket s = null;
|
||||||
|
try {
|
||||||
|
ss.bind(addr);
|
||||||
|
SocketChannel ch = (SocketChannel) cb.handler(h).connect().sync().channel();
|
||||||
|
assertTrue(ch.isActive());
|
||||||
|
s = ss.accept();
|
||||||
|
|
||||||
|
ch.close().syncUninterruptibly();
|
||||||
|
try {
|
||||||
|
ch.shutdownInput().syncUninterruptibly();
|
||||||
|
fail();
|
||||||
|
} catch (Throwable cause) {
|
||||||
|
checkThrowable(cause);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ch.shutdownOutput().syncUninterruptibly();
|
||||||
|
fail();
|
||||||
|
} catch (Throwable cause) {
|
||||||
|
checkThrowable(cause);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (s != null) {
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
ss.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkThrowable(Throwable cause) throws Throwable {
|
||||||
|
// Depending on OIO / NIO both are ok
|
||||||
|
if (!(cause instanceof ClosedChannelException) && !(cause instanceof SocketException)) {
|
||||||
|
throw cause;
|
||||||
|
}
|
||||||
|
}
|
||||||
private static class TestHandler extends SimpleChannelInboundHandler<ByteBuf> {
|
private static class TestHandler extends SimpleChannelInboundHandler<ByteBuf> {
|
||||||
volatile SocketChannel ch;
|
volatile SocketChannel ch;
|
||||||
final BlockingQueue<Byte> queue = new LinkedBlockingQueue<Byte>();
|
final BlockingQueue<Byte> queue = new LinkedBlockingQueue<Byte>();
|
||||||
|
@ -82,6 +82,9 @@ public final class Socket extends FileDescriptor {
|
|||||||
// represents the previous incarnation of the FD we need to be sure we don't inadvertently shutdown the
|
// represents the previous incarnation of the FD we need to be sure we don't inadvertently shutdown the
|
||||||
// "new" FD without explicitly having a change.
|
// "new" FD without explicitly having a change.
|
||||||
final int oldState = this.state;
|
final int oldState = this.state;
|
||||||
|
if (isClosed(oldState)) {
|
||||||
|
throw new ClosedChannelException();
|
||||||
|
}
|
||||||
int newState = oldState;
|
int newState = oldState;
|
||||||
if (read && !isInputShutdown(newState)) {
|
if (read && !isInputShutdown(newState)) {
|
||||||
newState = inputShutdown(newState);
|
newState = inputShutdown(newState);
|
||||||
|
Loading…
Reference in New Issue
Block a user