Ktor: Raw client socket crash when connection aborted in Android.

Created on 17 Mar 2020  路  5Comments  路  Source: ktorio/ktor

Ktor Version and Engine Used (client or server and name)

  • Ktor version: 1.3.1
  • Raw TCP Client
  • TLS (optional)

Describe the bug
The issue similar to previously reported #1237
When network connection is switched off (for example: airplaine mode) client socket throws an uncatchable exception.

Actual workaround:
Using a custom dispatcher with exception handler. Idea comes from this fix:
https://github.com/ktorio/ktor/commit/cfd2a841a411e9f4116361e131e0717f38dafe9b

To Reproduce
Steps to reproduce the behavior:

  1. clone https://github.com/fboldog/ktor-rawsocket-crash/
  2. build and install on android device / emulator
  3. start the app
  4. use the CONNECT w/ IO button
  5. press airplane mode button on quick settings panel
  6. app instantly crashing

4.1 use CONNECT w/ CUSTOM button

  1. press airplane mode button on quick settings panel
    6.1 app stays alive

Expected behavior
User able to catch connection aborted error and shutdown the flow gracefully

Stack trace
03-17 17:30:28.440 5803-5909/foo.bar.krs E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-6 Process: foo.bar.krs, PID: 5803 java.net.SocketException: shutdown failed: ENOTCONN (Transport endpoint is not connected) at java.net.PlainSocketImpl.shutdownInput(PlainSocketImpl.java:361) at java.net.Socket.shutdownInput(Socket.java:635) at io.ktor.network.sockets.CIOReaderKt$attachForReadingDirectImpl$1.invokeSuspend(CIOReader.kt:111) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:175) at kotlinx.coroutines.DispatchedTaskKt.resumeUnconfined(DispatchedTask.kt:137) at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:108) at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:306) at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:316) at kotlinx.coroutines.CancellableContinuationImpl.resumeWith(CancellableContinuationImpl.kt:248) at io.ktor.network.selector.SelectorManagerSupport.handleSelectedKey(SelectorManagerSupport.kt:84) at io.ktor.network.selector.SelectorManagerSupport.handleSelectedKeys(SelectorManagerSupport.kt:64) at io.ktor.network.selector.ActorSelectorManager.process(ActorSelectorManager.kt:73) at io.ktor.network.selector.ActorSelectorManager$process$1.invokeSuspend(ActorSelectorManager.kt) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56) at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:738) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665) Caused by: android.system.ErrnoException: shutdown failed: ENOTCONN (Transport endpoint is not connected) at libcore.io.Posix.shutdown(Native Method) at libcore.io.ForwardingOs.shutdown(ForwardingOs.java:159) at java.net.PlainSocketImpl.shutdownInput(PlainSocketImpl.java:359) at java.net.Socket.shutdownInput(Socket.java:635) at io.ktor.network.sockets.CIOReaderKt$attachForReadingDirectImpl$1.invokeSuspend(CIOReader.kt:111) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:175) at kotlinx.coroutines.DispatchedTaskKt.resumeUnconfined(DispatchedTask.kt:137) at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:108) at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:306) at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:316) at kotlinx.coroutines.CancellableContinuationImpl.resumeWith(CancellableContinuationImpl.kt:248) at io.ktor.network.selector.SelectorManagerSupport.handleSelectedKey(SelectorManagerSupport.kt:84) at io.ktor.network.selector.SelectorManagerSupport.handleSelectedKeys(SelectorManagerSupport.kt:64) at io.ktor.network.selector.ActorSelectorManager.process(ActorSelectorManager.kt:73) at io.ktor.network.selector.ActorSelectorManager$process$1.invokeSuspend(ActorSelectorManager.kt) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56) at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:738) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)

bug

Most helpful comment

Works in 1.5.1

All 5 comments

I experience the same issue.
It seems as if Ktor socket does not propagate up the exception properly, and it ends up unhandled on its own dispatcher.

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.

when will a fix be released for this issue?

why is this still open? omg....
its been over 4months now
practically this library is totally pointless in production

Works in 1.5.1

Was this page helpful?
0 / 5 - 0 ratings