diff --git a/build.sbt b/build.sbt index 8bc5ac3..24ed02d 100644 --- a/build.sbt +++ b/build.sbt @@ -55,6 +55,7 @@ lazy val tests = crossProject(JVMPlatform, NativePlatform) "org.typelevel" %%% "munit-cats-effect" % munitCEVersion % Test ) ) + .jvmSettings(fork := true) lazy val example = project .in(file("example")) diff --git a/core/src/main/scala/epollcat/internal/ch/EpollAsyncServerSocketChannel.scala b/core/src/main/scala/epollcat/internal/ch/EpollAsyncServerSocketChannel.scala index c6db729..ad3685f 100644 --- a/core/src/main/scala/epollcat/internal/ch/EpollAsyncServerSocketChannel.scala +++ b/core/src/main/scala/epollcat/internal/ch/EpollAsyncServerSocketChannel.scala @@ -211,6 +211,7 @@ object EpollAsyncServerSocketChannel { case epoll: EventPollingExecutorScheduler => val fd = SocketHelpers.mkNonBlocking() val ch = new EpollAsyncServerSocketChannel(fd) + ch.setOption(StandardSocketOptions.SO_REUSEADDR, java.lang.Boolean.TRUE) ch.unmonitor = epoll.monitor(fd, reads = true, writes = false)(ch) ch case _ => diff --git a/tests/shared/src/test/scala/epollcat/TcpSuite.scala b/tests/shared/src/test/scala/epollcat/TcpSuite.scala index cca3d82..f14b8c4 100644 --- a/tests/shared/src/test/scala/epollcat/TcpSuite.scala +++ b/tests/shared/src/test/scala/epollcat/TcpSuite.scala @@ -311,4 +311,19 @@ class TcpSuite extends EpollcatSuite { IOServerSocketChannel.open.use_ } + test("closing/re-opening a server does not throw BindException: Address already in use") { + IOServerSocketChannel + .open + .evalTap(_.bind(new InetSocketAddress("localhost", 0))) + .use { server => + server.localAddress.flatTap { address => + val connect = + IOSocketChannel.open.evalTap(_.connect(address)).surround(IO.sleep(1.second)) + val accept = server.accept.surround(IO.sleep(1.second)) + connect.both(accept).void + } + } + .flatMap(address => IOServerSocketChannel.open.evalTap(_.bind(address)).use_) + } + }