diff --git a/ktor-network/common/test/io/ktor/network/sockets/tests/TCPSocketTest.kt b/ktor-network/common/test/io/ktor/network/sockets/tests/TCPSocketTest.kt index b29b0f40336..ae09a1396b0 100644 --- a/ktor-network/common/test/io/ktor/network/sockets/tests/TCPSocketTest.kt +++ b/ktor-network/common/test/io/ktor/network/sockets/tests/TCPSocketTest.kt @@ -168,4 +168,20 @@ class TCPSocketTest { serverConnection.close() server.close() } + + @Test + fun testAcceptErrorOnSocketClose() = testSockets { selector -> + val socket = aSocket(selector) + .tcp() + .bind(InetSocketAddress("127.0.0.1", 0)) + + launch { + assertFailsWith { + socket.accept() + } + } + delay(100) // Make sure socket is awaiting connection using ACCEPT + + socket.close() + } } diff --git a/ktor-network/jsAndWasmShared/src/io/ktor/network/sockets/ServerSocketContext.kt b/ktor-network/jsAndWasmShared/src/io/ktor/network/sockets/ServerSocketContext.kt index f14801e28e8..1d9284e0311 100644 --- a/ktor-network/jsAndWasmShared/src/io/ktor/network/sockets/ServerSocketContext.kt +++ b/ktor-network/jsAndWasmShared/src/io/ktor/network/sockets/ServerSocketContext.kt @@ -55,7 +55,7 @@ internal class ServerSocketContext( private class ServerSocketImpl( override val localAddress: SocketAddress, override val socketContext: Job, - private val incoming: ReceiveChannel, + private val incoming: Channel, private val server: Server ) : ServerSocket { override suspend fun accept(): Socket = incoming.receive() @@ -68,6 +68,7 @@ private class ServerSocketImpl( } override fun close() { + incoming.close(IOException("Server socket closed")) socketContext.cancel("Server socket closed") } } diff --git a/ktor-network/nix/src/io/ktor/network/selector/SelectUtilsNix.kt b/ktor-network/nix/src/io/ktor/network/selector/SelectUtilsNix.kt index c059fc2fd99..881e95a76b5 100644 --- a/ktor-network/nix/src/io/ktor/network/selector/SelectUtilsNix.kt +++ b/ktor-network/nix/src/io/ktor/network/selector/SelectUtilsNix.kt @@ -200,6 +200,7 @@ internal actual class SelectorHelper { for (event in watchSet) { if (event.descriptor in closeSet) { completed.add(event) + event.fail(IOException("Selectable closed")) continue } diff --git a/ktor-network/windows/src/io/ktor/network/selector/SelectUtilsWindows.kt b/ktor-network/windows/src/io/ktor/network/selector/SelectUtilsWindows.kt index 8cd4f19ae86..58ef5a1c2d6 100644 --- a/ktor-network/windows/src/io/ktor/network/selector/SelectUtilsWindows.kt +++ b/ktor-network/windows/src/io/ktor/network/selector/SelectUtilsWindows.kt @@ -10,6 +10,7 @@ import io.ktor.utils.io.* import io.ktor.utils.io.errors.* import kotlinx.cinterop.* import kotlinx.coroutines.* +import kotlinx.io.IOException import platform.posix.* import kotlin.coroutines.cancellation.CancellationException @@ -152,6 +153,7 @@ internal actual class SelectorHelper { watchSet.forEach { event -> if (event.descriptor in closeSet) { completed.add(event) + event.fail(IOException("Selectable closed")) return@forEach } val wsaEvent = wsaEvents.getValue(event.descriptor)