From e4507396b1fe4436c0407f945d0d352e3c1f9754 Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Fri, 25 Aug 2023 10:11:58 +0000 Subject: [PATCH 1/2] Ignore `ENOTCONN` on socket shutdown --- .../internal/ch/EpollAsyncSocketChannel.scala | 5 +++-- .../src/test/scala/epollcat/TcpSuite.scala | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/epollcat/internal/ch/EpollAsyncSocketChannel.scala b/core/src/main/scala/epollcat/internal/ch/EpollAsyncSocketChannel.scala index 0199d80..80820db 100644 --- a/core/src/main/scala/epollcat/internal/ch/EpollAsyncSocketChannel.scala +++ b/core/src/main/scala/epollcat/internal/ch/EpollAsyncSocketChannel.scala @@ -38,6 +38,7 @@ import scala.scalanative.annotation.stub import scala.scalanative.libc.errno import scala.scalanative.meta.LinktimeInfo import scala.scalanative.posix +import scala.scalanative.posix.errno._ import scala.scalanative.posix.netdbOps._ import scala.scalanative.unsafe._ import scala.scalanative.unsigned._ @@ -79,14 +80,14 @@ final class EpollAsyncSocketChannel private ( def isOpen = _isOpen def shutdownInput(): AsynchronousSocketChannel = { - if (posix.sys.socket.shutdown(fd, 0) == -1) + if (posix.sys.socket.shutdown(fd, 0) == -1 && errno.errno != ENOTCONN) throw new IOException(s"shutdown: ${errno.errno}") this } def shutdownOutput(): AsynchronousSocketChannel = { outputShutdown = true - if (posix.sys.socket.shutdown(fd, 1) == -1) + if (posix.sys.socket.shutdown(fd, 1) == -1 && errno.errno != ENOTCONN) throw new IOException(s"shutdown: ${errno.errno}") this } diff --git a/tests/shared/src/test/scala/epollcat/TcpSuite.scala b/tests/shared/src/test/scala/epollcat/TcpSuite.scala index aa0ad70..4eea816 100644 --- a/tests/shared/src/test/scala/epollcat/TcpSuite.scala +++ b/tests/shared/src/test/scala/epollcat/TcpSuite.scala @@ -362,4 +362,22 @@ class TcpSuite extends EpollcatSuite { .flatMap(address => IOServerSocketChannel.open.evalTap(_.bind(address)).use_) } + test("shutdown ignores ENOTCONN".only) { + IOServerSocketChannel + .open + .evalTap(_.bind(new InetSocketAddress("localhost", 0))) + .use { server => + server.localAddress.flatTap { address => + val connect = + IOSocketChannel.open.evalTap(_.connect(address)).surround(IO.sleep(100.millis)) + val accept = server.accept.use { ch => + ch.write(ByteBuffer.wrap("hello".getBytes)) *> + IO.sleep(1.second) *> ch.shutdownInput *> ch.shutdownOutput + } + connect.both(accept).void + } + } + .flatMap(address => IOServerSocketChannel.open.evalTap(_.bind(address)).use_) + } + } From 5a16c123b1868463805e832ff2b925ce50bf7e8f Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Fri, 25 Aug 2023 10:16:38 +0000 Subject: [PATCH 2/2] Remove `.only` --- tests/shared/src/test/scala/epollcat/TcpSuite.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/shared/src/test/scala/epollcat/TcpSuite.scala b/tests/shared/src/test/scala/epollcat/TcpSuite.scala index 4eea816..34e0fce 100644 --- a/tests/shared/src/test/scala/epollcat/TcpSuite.scala +++ b/tests/shared/src/test/scala/epollcat/TcpSuite.scala @@ -362,7 +362,7 @@ class TcpSuite extends EpollcatSuite { .flatMap(address => IOServerSocketChannel.open.evalTap(_.bind(address)).use_) } - test("shutdown ignores ENOTCONN".only) { + test("shutdown ignores ENOTCONN") { IOServerSocketChannel .open .evalTap(_.bind(new InetSocketAddress("localhost", 0)))