ktor: ktor websocket client crashes with java.io.IOException: Software caused connection in Android abort

Version: 1.2.2, client, io.ktor:ktor-client-cio, io.ktor:ktor-client-websockets Android 7.0

When using websocket client

To Reproduce code:

val uri = URLBuilder().takeFrom(configuration.url).build()
val httpClientEngine = CIO.create { }
val client = HttpClient(httpClientEngine).config {
    install(WebSockets)
}

suspend fun process(session: DefaultClientWebSocketSession): ConnectionStatus {
            while (session.isActive && !session.closeReason.isCompleted) {
                try {
                    select<Unit> {
                         session.incoming.onReceiveOrNull { frame ->
                            when (frame) {
                                null -> { // channel has been closed
                                    println("closed")
                                    session.close()
                                }
                                else -> Unit
                            }
                        }
                    }
                } catch (e: IOException) {
                    println("io exception: ${e}")
                    session.close()
                } catch (e: Throwable) {
                    println("exception: ${e}")
                    session.close()
                }
            }
}
runBlocking {
  try {
    when (uri.protocol.isSecure()) {
        true -> client.wss(host = uri.host, port = uri.port, path = uri.encodedPath) { process(this) }
        false -> client.ws(host = uri.host, port = uri.port, path = uri.encodedPath) { process(this) }
    }
  } catch (ex: Exception) {
    println("catched: ${ex}")
  }
}
  1. Start code with internet enabled and with some websocket url
  2. disconnect internet IOException will be thrown, but not caught anywhere.

Expected behavior I’m expecting that this IOException won’t leak and can be caught by try/catch.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 7
  • Comments: 16 (3 by maintainers)

Commits related to this issue

Most upvoted comments

Investigation history:

maybe problem is here: Socket.tls(coroutineContext: CoroutineContext, config: TLSConfig) function:

  1. calls val reader = openReadChannel()
  2. which calls attachForReading(channel: ByteChannel): WriterJob
  3. which calls CoroutineScope.attachForReadingDirectImpl(...) // <— this is implemented in internal abstract class NIOSocketImpl<out S> with CoroutineScope
  4. which call writer(Dispatchers.Unconfined, channel) { .. block .. }
  5. and it this block there is “val rc = nioChannel.read(buffer)” <<- which throws that IOException code:
internal abstract class NIOSocketImpl<out S> implements CoroutineScope:

    override val socketContext: CompletableJob = Job()

    override val coroutineContext: CoroutineContext
        get() = socketContext
  1. and attachForReadingDirectImpl() is called on this coroutineScope which is just Job() without any specified dispatchers nor any parent contexts, so this scope is not bound to any of coroutines nor callees of tls() nor ktor CIO context, this just runs on Dispatchers.Default with Job() So there is no way to catch this exception and its bubbled to global exception handler.
  2. app fatally crashes.

We are still waiting while ktor team will fix this critical bug which was introduced in some versions later and never got fixed. This bug cause crashes not only android but also server side thus making multiplatform websockets unusable.

On 2020-01-12, Sun at 21:03, David Alan Cohen notifications@github.com wrote:

This may not be applicable to every application that is running into this issue, but if you want to swallow this IOException so that the app doesn’t fatally crash, you can override the thread’s default exception handler with custom behavior using Thread.setDefaultUncaughtExceptionHandler() in MainActivity.onCreate().

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/ktorio/ktor/issues/1237?email_source=notifications&email_token=ABABZHB4WLWQTOXJYYMJIEDQ5OATVA5CNFSM4IE3THVKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEIXEEXI#issuecomment-573456989, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABABZHFP2WXR3BCG2OYPRVLQ5OATVANCNFSM4IE3THVA .

This may not be applicable to every application that is running into this issue, but if you want to swallow this IOException so that the app doesn’t fatally crash, you can override the thread’s default exception handler with custom behavior using Thread.setDefaultUncaughtExceptionHandler() in MainActivity.onCreate().

I think it’s not reliable solution, maybe with this fix probability of crash will be lower, but not impossible, as by looking inside the ktor’s code there is no way to handle exception if it will be thrown during non blocking socket read.

No, currently there is no way to use ktor websockets in android platform to prevent crash. We’ve temporarily removed websocket from our app as it was used only for telemetry data.

I had hope that this will be fixed with latest release, but seems it’s not trivial to fix.

On Mon, 5 Aug 2019 at 13:29, Saddam Asmatullayev notifications@github.com wrote:

Have you found any temporary solution for that? And also, how the sockets are connected back when you turn your connection on?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/ktorio/ktor/issues/1237?email_source=notifications&email_token=ABABZHCRZJU2EKZUISCFRL3QC76IDA5CNFSM4IE3THVKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD3RMY5I#issuecomment-518179957, or mute the thread https://github.com/notifications/unsubscribe-auth/ABABZHHNST2RY2APKMIIDNTQC76IDANCNFSM4IE3THVA .