Search code examples
androidkotlintry-catchkotlin-coroutines

try catch can't catch a ENETUNREACH error inside a socket helper class


I was testing my app what would happen if I turned off the device's internet, and it was crashing. I already preemptively added a bunch of catch case on the "init" code of the socket helper, and they doesn't seems to be getting triggered. Here's what my code looks like:

fun start() {
    GlobalScope.launch(Dispatchers.IO) {
        try {
            basicSocket = DatagramSocket(UDP_SERVER_PORT)

            val udpPayload = "some string payload"
            basicSendToUDP(udpPayload, getBroadcastAddr())

            while (true) {
                basicReceiveFromUDP()
            }
        } catch (e: SocketException) {
            Log.e(TAG, "Socket Error:", e)
        } catch (e: SecurityException) {
            Log.e(TAG, "Sec Error:", e)
        } catch (e: IOException) {
            Log.e(TAG, "IO Error:", e)
        } catch (e: Exception) {
            Log.e(TAG, "Error:", e)
        }
    }
}

That start() method gets called around the top of my MainActivity's onCreate.

I already tried some different approach that looks like this:

val t = Thread {
    try {
        basicSocket = DatagramSocket(UDP_SERVER_PORT)

        val udpPayload = "some string payload"
        basicSendToUDP(udpPayload, getBroadcastAddr())

        while (true) {
            basicReceiveFromUDP()
        }
    } catch (e: Exception) {
        Log.e(TAG, "Error:", e)
    }
}

t.start()

But I'm still getting the same error:

java.io.IOException: sendto failed: ENETUNREACH (Network is unreachable) at libcore.io.IoBridge.maybeThrowAfterSendto(IoBridge.java:721) at libcore.io.IoBridge.sendto(IoBridge.java:688) at java.net.PlainDatagramSocketImpl.send(PlainDatagramSocketImpl.java:126) at java.net.DatagramSocket.send(DatagramSocket.java:723) at com.bsu.atlantis.utils.helpers.SocketHelper.basicSendToUDP$lambda$3(SocketHelper.kt:74)

basicSendToUDP() looks like this:

fun basicSendToUDP(payload: String, iAddr: InetAddress) {
    Thread {
        val sendPacket =
            DatagramPacket(
                payload.toByteArray(),
                payload.length,
                iAddr,
                UDP_SERVER_PORT
            )
        basicSocket.send(sendPacket)
    }.start()
}

All the code I posted works perfectly when I turn on the WiFi on my device


Solution

  • The problem is that the code throwing is run in a different thread Thread { .. }.start() in basicSendTuUDP(). You should catch the exception inside that thread like so:

    fun basicSendToUDP(payload: String, iAddr: InetAddress) {
        Thread {
            try {
                val sendPacket =
                    DatagramPacket(
                        payload.toByteArray(),
                        payload.length,
                        iAddr,
                        UDP_SERVER_PORT
                    )
                basicSocket.send(sendPacket)
            } catch (e: Exception) {
                Log.e(TAG, "Error:", e)
            }
        }.start()
    }