From 2c1f17faa268b9a1b8ef8f1ddaf832d1397719a3 Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Tue, 16 Aug 2016 16:01:37 +0200 Subject: [PATCH] Throw correct NotYetConnectedException when ENOTCONN errno is set Motivation: We should throw a NotYetConnectedException when ENOTCONN errno is set. This is also consistent with NIO. Modification: Throw correct exception and add test case Result: More correct and consistent behavior. --- .../SocketChannelNotYetConnectedTest.java | 63 +++++++++++++++++++ .../java/io/netty/channel/unix/Errors.java | 7 ++- .../java/io/netty/channel/unix/Socket.java | 6 +- ...EpollSocketChannelNotYetConnectedTest.java | 29 +++++++++ .../channel/epoll/EpollSocketChannelTest.java | 16 ----- 5 files changed, 101 insertions(+), 20 deletions(-) create mode 100644 testsuite/src/main/java/io/netty/testsuite/transport/socket/SocketChannelNotYetConnectedTest.java create mode 100644 transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollSocketChannelNotYetConnectedTest.java diff --git a/testsuite/src/main/java/io/netty/testsuite/transport/socket/SocketChannelNotYetConnectedTest.java b/testsuite/src/main/java/io/netty/testsuite/transport/socket/SocketChannelNotYetConnectedTest.java new file mode 100644 index 0000000000..88e9d4bcd5 --- /dev/null +++ b/testsuite/src/main/java/io/netty/testsuite/transport/socket/SocketChannelNotYetConnectedTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2016 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.testsuite.transport.socket; + +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.socket.SocketChannel; +import org.junit.Test; + +import java.net.InetSocketAddress; +import java.net.SocketException; +import java.nio.channels.NotYetConnectedException; + +import static org.junit.Assert.fail; + +public class SocketChannelNotYetConnectedTest extends AbstractClientSocketTest { + @Test(timeout = 30000) + public void testShutdownNotYetConnected() throws Throwable { + run(); + } + + public void testShutdownNotYetConnected(Bootstrap cb) throws Throwable { + SocketChannel ch = (SocketChannel) cb.handler(new ChannelInboundHandlerAdapter()) + .bind(new InetSocketAddress(0)).syncUninterruptibly().channel(); + try { + try { + ch.shutdownInput().syncUninterruptibly(); + fail(); + } catch (Throwable cause) { + checkThrowable(cause); + } + + try { + ch.shutdownOutput().syncUninterruptibly(); + fail(); + } catch (Throwable cause) { + checkThrowable(cause); + } + } finally { + ch.close().syncUninterruptibly(); + } + } + + private static void checkThrowable(Throwable cause) throws Throwable { + // Depending on OIO / NIO both are ok + if (!(cause instanceof NotYetConnectedException) && !(cause instanceof SocketException)) { + throw cause; + } + } +} diff --git a/transport-native-epoll/src/main/java/io/netty/channel/unix/Errors.java b/transport-native-epoll/src/main/java/io/netty/channel/unix/Errors.java index 9c00beec53..25ff4a70b8 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/unix/Errors.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/unix/Errors.java @@ -20,6 +20,7 @@ import io.netty.util.internal.EmptyArrays; import java.io.IOException; import java.net.ConnectException; import java.nio.channels.ClosedChannelException; +import java.nio.channels.NotYetConnectedException; import static io.netty.channel.unix.ErrorsStaticallyReferencedJniMethods.errnoEAGAIN; import static io.netty.channel.unix.ErrorsStaticallyReferencedJniMethods.errnoEBADF; @@ -118,9 +119,13 @@ public final class Errors { if (err == resetCause.expectedErr()) { throw resetCause; } - if (err == ERRNO_EBADF_NEGATIVE || err == ERRNO_ENOTCONN_NEGATIVE) { + if (err == ERRNO_EBADF_NEGATIVE) { throw closedCause; } + if (err == ERRNO_ENOTCONN_NEGATIVE) { + throw new NotYetConnectedException(); + } + // TODO: We could even go further and use a pre-instantiated IOException for the other error codes, but for // all other errors it may be better to just include a stack trace. throw newIOException(method, err); diff --git a/transport-native-epoll/src/main/java/io/netty/channel/unix/Socket.java b/transport-native-epoll/src/main/java/io/netty/channel/unix/Socket.java index c9361e9dfa..fe52d79eea 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/unix/Socket.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/unix/Socket.java @@ -58,9 +58,9 @@ public final class Socket extends FileDescriptor { private static final Errors.NativeIoException CONNECTION_RESET_EXCEPTION_SENDMSG = unknownStackTrace( Errors.newConnectionResetException("syscall:sendmsg(...)", Errors.ERRNO_EPIPE_NEGATIVE), Socket.class, "sendToAddresses(...)"); - private static final Errors.NativeIoException CONNECTION_NOT_CONNECTED_SHUTDOWN_EXCEPTION = + private static final Errors.NativeIoException CONNECTION_RESET_SHUTDOWN_EXCEPTION = unknownStackTrace(Errors.newConnectionResetException("syscall:shutdown(...)", - Errors.ERRNO_ENOTCONN_NEGATIVE), Socket.class, "shutdown(...)"); + Errors.ERRNO_ECONNRESET_NEGATIVE), Socket.class, "shutdown(...)"); private static final Errors.NativeConnectException FINISH_CONNECT_REFUSED_EXCEPTION = unknownStackTrace(new Errors.NativeConnectException("syscall:getsockopt(...)", Errors.ERROR_ECONNREFUSED_NEGATIVE), Socket.class, "finishConnect(...)"); @@ -100,7 +100,7 @@ public final class Socket extends FileDescriptor { } int res = shutdown(fd, read, write); if (res < 0) { - ioResult("shutdown", res, CONNECTION_NOT_CONNECTED_SHUTDOWN_EXCEPTION, SHUTDOWN_CLOSED_CHANNEL_EXCEPTION); + ioResult("shutdown", res, CONNECTION_RESET_SHUTDOWN_EXCEPTION, SHUTDOWN_CLOSED_CHANNEL_EXCEPTION); } } diff --git a/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollSocketChannelNotYetConnectedTest.java b/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollSocketChannelNotYetConnectedTest.java new file mode 100644 index 0000000000..a8072926cf --- /dev/null +++ b/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollSocketChannelNotYetConnectedTest.java @@ -0,0 +1,29 @@ +/* + * Copyright 2016 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.channel.epoll; + +import io.netty.bootstrap.Bootstrap; +import io.netty.testsuite.transport.TestsuitePermutation; +import io.netty.testsuite.transport.socket.SocketChannelNotYetConnectedTest; + +import java.util.List; + +public class EpollSocketChannelNotYetConnectedTest extends SocketChannelNotYetConnectedTest { + @Override + protected List> newFactories() { + return EpollSocketTestPermutation.INSTANCE.clientSocket(); + } +} diff --git a/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollSocketChannelTest.java b/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollSocketChannelTest.java index 54b2ded43d..9637006217 100644 --- a/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollSocketChannelTest.java +++ b/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollSocketChannelTest.java @@ -16,28 +16,12 @@ package io.netty.channel.epoll; import io.netty.bootstrap.Bootstrap; -import io.netty.bootstrap.ServerBootstrap; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelOption; -import io.netty.channel.ChannelPipeline; import io.netty.channel.EventLoopGroup; -import io.netty.channel.ServerChannel; -import io.netty.util.ReferenceCountUtil; import org.junit.Assert; import org.junit.Test; import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; public class EpollSocketChannelTest {