Search code examples
javaandroidkotlinnetwork-programmingwake-on-lan

Wake-on-Lan app only works for recently shutdown devices


I have written a small application in Kotlin which sends a Magic Packet to a smart tv over my local network. I used this approach (code), rewritten in Kotlin (plus i hardcoded the IP and MAC for testing purposes).

When the tv is shutdown, i can easily restart it with my application. After a while, that doesn't work anymore.

Code

import java.net.DatagramPacket
import java.net.DatagramSocket
import java.net.InetAddress

fun main() {
   magicPacket("A8:23-FE:A0:5C:DB", "192.168.xx.xxx", 7)
}

    /**
     * Android:
     * Network interaction starting in new Thread!
     */
    fun magicPacket(mac: String, ip: String, PORT: Int = 7) {
        // throws IllegalThreadStateException without declaration
        //val t = thread {
        val packet = buildPacket(mac)
        val datagramSocket = DatagramSocket()
        try {
            datagramSocket.send(
                DatagramPacket(
                    packet,
                    packet.size,
                    InetAddress.getByName(ip),
                    PORT
                )
            )
            datagramSocket.close()
        } catch (e: Exception) {
            e.printStackTrace()
        }
        //}
    }

    private fun buildPacket(mac: String): ByteArray {
        // prepare packet   (6 bytes header) (16 * 6 bytes MAC)
        val temp = ByteArray(6 + 6 * 16)
        val macBytes = ByteArray(6)
        for (i in 0..5) {
            temp[i] = 0xFF.toByte()
            macBytes[i] = mac.split(":", "-")[i].toInt(16).toByte()
        }
        for (i in 6 until temp.size step macBytes.size) System.arraycopy(
            macBytes,
            0,
            temp,
            i,
            macBytes.size
        )
        return temp
    }

What i tried in code

  • i changed port numbers (starting with random (11111, 55555, quick google search suggested ports 0, 7, 9) which all failed
  • sending not one but 10 to 100 packets
  • i ran the app as a java (kotlin) project from Intellij on my PC aswell, same results

What i found out yet

  1. WOL doesn't work on every device
  2. power states may be important
  3. Wake On Lan manages to wake up the device no matter what, so i think the problem is the app, not any settings
  4. All network IPs and MACs are static

Solution

  • When sending a wakeonlan packet, you need to make sure the target device can receive the packet.

    At the moment, you are sending the packet to the IPv4 address of the device.

    When your computer has to send a packet to an IPv4 address, it needs to know its MAC address. So it asks the network "Who has IPv4 192.168.2.32? Tell me your mac address". Since you TV is shutdown, it does not respond.

    The real wake on lan packet will never be send, as it des not know the destination mac address.

    The real question then becomes, why does it work directly after shutting down, and the reason for this is that your OS keeps a list of IPv4+mac address table, so it can quickly send the packet out. You can view this list with the command arp -av on Windows

    Note how it shows "dynamic" when your program successfully wakes the TV, but shows "invalid" when it fails to wake the TV up.

    One solution for this, is sending the packet to the broadcast IPv4 address, which every devices receives. This IPv4 address typically ends with .255 with typical consumer IPv4 ranges.