Broadcasting over Wi-Fi Direct

KatoStoelen picture KatoStoelen · Mar 20, 2013 · Viewed 14.3k times · Source

I'm looking at the possibility to broadcast over a Wi-Fi Direct connection between multiple Android devices. I've created a simple message broadcasting application to test whether or not it works, but so far I haven't been able to broadcast a message. When I try to send the packet I get a SocketException (Network is unreachable):

03-20 13:23:00.148: E/UdpBroadcaster(4180): sendto failed: ENETUNREACH (Network is unreachable)
03-20 13:23:00.148: E/UdpBroadcaster(4180): java.net.SocketException: sendto failed: ENETUNREACH (Network is unreachable)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at libcore.io.IoBridge.maybeThrowAfterSendto(IoBridge.java:496)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at libcore.io.IoBridge.sendto(IoBridge.java:465)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at java.net.PlainDatagramSocketImpl.send(PlainDatagramSocketImpl.java:182)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at java.net.DatagramSocket.send(DatagramSocket.java:307)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at com.example.android.wifidirect.UdpBroadcaster.sendMessage(UdpBroadcaster.java:59)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at com.example.android.wifidirect.UdpBroadcaster.run(UdpBroadcaster.java:44)
03-20 13:23:00.148: E/UdpBroadcaster(4180): Caused by: libcore.io.ErrnoException: sendto failed: ENETUNREACH (Network is unreachable)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at libcore.io.Posix.sendtoBytes(Native Method)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at libcore.io.Posix.sendto(Posix.java:146)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at libcore.io.BlockGuardOs.sendto(BlockGuardOs.java:177)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at libcore.io.IoBridge.sendto(IoBridge.java:463)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     ... 4 more

This is the essence of my code:

InetAddress broadcastAddress = InetAddress.getByName("255.255.255.255");
int port = 8888;

DatagramSocket socket = new DatagramSocket(port);
socket.setBroadcast(true);
socket.connect(broadcastAddress, port);

String message = "Hello";
byte[] buffer = message.getBytes();

DatagramPacket packet = new DatagramPacket(
        buffer, buffer.length, broadcastAddress, port);

try {
    socket.send(packet); // <----- Causes a SocketException
} catch (IOException e) {
    Log.e(TAG, e.getMessage(), e);
}

This post suggests that broadcasting over Wi-Fi Direct should be possible.

Does anyone know whether broadcasting over Wi-Fi Direct on Android devices actually works? If it should work, what am I doing wrong?

I'm starting to think the devices does not know where to route the broadcast packets. In my case it needs to work without having to root the device and manually add a route for broadcast packets.


Update

After using the getBroadcastAddress() function suggested by Romain Hippeau the SocketException disappeared and it seems like the broadcasting is working as intended. However, I'm having problems receiving the broadcast on the second device.

I'm using the following code to receive the broadcast:

DatagramSocket socket = null;
try {
    socket = new DatagramSocket(8888);
    socket.setBroadcast(true); // Not needed?
    socket.setSoTimeout(200);

    DatagramPacket packet = null;
    while (!mStopping) {
        byte[] buffer = new byte[1024];
        packet = new DatagramPacket(buffer, buffer.length);

        try {
            socket.receive(packet);

            if (packet.getData().length > 0) {
                String receivedString = new String(packet.getData());

                Log.i(TAG, "Received string: " + receivedString);
            }
        } catch (InterruptedIOException e) { /* Ignore */ }
    }
} catch (IOException e) {
    Log.e(TAG, e.getMessage(), e);
} finally {
    if (socket != null)
        socket.close();
}

I have also tried to add a wildcard address to the DatagramSocket by adding InetAddress.getByName("0.0.0.0") as argument, but no luck.

Suggestions?

Answer

Romain Hippeau picture Romain Hippeau · Mar 20, 2013

Shamelessly stolen from https://code.google.com/p/boxeeremote/wiki/AndroidUDP

Try getting you network connection this way:

InetAddress getBroadcastAddress() throws IOException {
    WifiManager wifi = mContext.getSystemService(Context.WIFI_SERVICE);
    DhcpInfo dhcp = wifi.getDhcpInfo();
    // handle null somehow

    int broadcast = (dhcp.ipAddress & dhcp.netmask) | ~dhcp.netmask;
    byte[] quads = new byte[4];
    for (int k = 0; k < 4; k++)
      quads[k] = (byte) ((broadcast >> k * 8) & 0xFF);
    return InetAddress.getByAddress(quads);
}  

Then try sending a packet this way:

DatagramSocket socket = new DatagramSocket(PORT);
socket.setBroadcast(true);
DatagramPacket packet = new DatagramPacket(data.getBytes(), data.length(),
    getBroadcastAddress(), PORT);
socket.send(packet);

// If you want to listen for a response ...
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);

Edit: From same page to read try this ...

WifiManager wifi = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
MulticastLock lock = wifi.createMulticastLock("dk.aboaya.pingpong");
lock.acquire();
serverSocket = new DatagramSocket(19876);
serverSocket.setSoTimeout(15000); //15 sec wait for the client to connect
byte[] data = new byte[UDPBatPositionUpdater.secretWord.length()]; 
DatagramPacket packet = new DatagramPacket(data, data.length);
serverSocket.receive(packet);
lock.release();
String s = new String(packet.getData());
System.out.println(s);

Remember, that you need the following permission for it to work:
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>