Send Broadcast UDP but not receive it on other Android devices

Lara picture Lara · Jun 26, 2013 · Viewed 34.5k times · Source

I am trying to develop an app that sends some broadcast messages and receives some answers from the other android devices. I am having some trouble receiving the UDP messages from the other devices. I should mention that this code worked on Gingerbread but on JellyBean it's not working anymore and I do not know what might be the problem.

Here is where I send the broadcast message (I know the other devices listen on port 5000) :

 private void sendUDPMessage(String msg) {

    try {
        DatagramSocket clientSocket = new DatagramSocket();

        clientSocket.setBroadcast(true);
        InetAddress address = InetAddress.getByName(Utils.getBroadcastAddress());

        byte[] sendData;

        sendData = msg.getBytes();
        DatagramPacket sendPacket = new DatagramPacket(sendData,
                sendData.length, address, 5000);
        clientSocket.send(sendPacket);

        clientSocket.close();
    } catch (Exception e) {
        e.printStackTrace();
    }

}

And here is where I receive it :

private void start_UDP()
{
    try {
            serverSocketUDP = new DatagramSocket(5000);
        }
    catch (Exception e) {

        Log.i(LOGTAG, "Exception opening DatagramSocket UDP");
    }

    final byte[] receiveData = new byte[1024];


    while(runningUDP) {
        Log.d(LOGTAG, "Waiting for Broadcast request in ServerUDP.");

        final DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);

        serverSocketUDP.receive(receivePacket);


                byte[] sendData = new byte[1024];
                InetAddress address = receivePacket.getAddress();
                int port = receivePacket.getPort();
                if(!receivePacket.getAddress().getHostAddress().equals(Utils.getLocalIpAddress()))
                {
                    String req = new String(receivePacket.getData(), 0, receivePacket.getLength());


                    Log.d(LOGTAG, "Received UDP message : "+req+" from: "+receivePacket.getAddress().getHostAddress());
                }
                      }// while ends
       }//method ends

I should mention that these 2 functions are separate in 2 different threads so I can send and receive simultaneously.

I also acquire the following locks:

    powerManager =(PowerManager)context.getSystemService(Context.POWER_SERVICE);
    wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK ,LOGTAG); // PARTIAL_WAKE_LOCK Only keeps CPU on
    wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
    wifiLock = wifiManager.createWifiLock(3, LOGTAG);
    multicastLock = wifiManager.createMulticastLock(LOGTAG);

    wakeLock.acquire();
    multicastLock.acquire();
    wifiLock.acquire();

And the permissions on the Manifest file :

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>

I have tested if the messages are sent using wireshark and tcpdump and they are sent. Moreover, what is even more strange, I receive the broadcast messages that I send (but I discard them because I dont need to process the messages sent from myself) but I dont receive the broadcast messages sent from the other devices (which should have the same format, only the source address would be different and the message contained, either way should not affect the broadcast message).

Please let me know if you have any ideas because I really ran out of anything else I could try. Any help would be appreciated. Thanks!

EDIT: I have made some tests and even if when I run on each of the phones ifconfig wlan0 and it says something like

  ifconfig wlan0
  wlan0: ip 169.254.17.28 mask 255.255.0.0 flags [up broadcast multicast]

which means that the interface is active and the IP is set and can receive broadcast messages and multicast msgs but when I use

                 InetAddress in=InetAddress.getByName("169.254.17.28");
            if (in.isReachable(1000))
                Log.i(LOGTAG, "host is reachable");
            else
                Log.i(LOGTAG, "host is not reachable");

It shows in the logs host is not reachable.

This is where I turn on the Wi-fi

    private void startWifiAdhoc() {

    WifiManager wifiManager =     (WifiManager)SharingFileService.context.getSystemService(Context.WIFI_SERVICE);
    String command="";
    if (condWifiAdhoc == false) {

        condWifiAdhoc=true;
        wifiInterface = Utils.getWifiInterface();


        wifiManager.setWifiEnabled(true);
        localIP = Utils.getLinkLocalAddress();
    }
    else
    {
        wifiManager.setWifiEnabled(true);
        localIP = Utils.getLinkLocalAddress();
    }
        // Set wifi ad-hoc
        command = context.getFilesDir().getPath()
                + "/iwconfig " + wifiInterface + " mode ad-hoc essid "
                + "mcp" + " channel " + "1" + " commit\n";

        Log.i(LOGTAG, command);
        Utils.rootExec(command);


        Log.i(LOGTAG, "Ip address used :" + localIP);
        command = context.getFilesDir().getPath()
                + "/ifconfig " + wifiInterface + " " + localIP
                + " netmask 255.255.0.0 up\n";



        Log.i(LOGTAG, command);
        Utils.rootExec(command);

}

Answer

caspii picture caspii · Aug 27, 2014

I got this working by using a method described here to calculate the broadcast address: https://code.google.com/p/boxeeremote/wiki/AndroidUDP

Here's my receiver:

try {
  //Keep a socket open to listen to all the UDP trafic that is destined for this port
  socket = new DatagramSocket(Constants.PORT, InetAddress.getByName("0.0.0.0"));
  socket.setBroadcast(true);

  while (true) {
    Log.i(TAG,"Ready to receive broadcast packets!");

    //Receive a packet
    byte[] recvBuf = new byte[15000];
    DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
    socket.receive(packet);

    //Packet received
    Log.i(TAG, "Packet received from: " + packet.getAddress().getHostAddress());
    String data = new String(packet.getData()).trim();
    Log.i(TAG, "Packet received; data: " + data);

    // Send the packet data back to the UI thread
    Intent localIntent = new Intent(Constants.BROADCAST_ACTION)
            // Puts the data into the Intent
            .putExtra(Constants.EXTENDED_DATA_STATUS, data);
    // Broadcasts the Intent to receivers in this app.
    LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
  }
} catch (IOException ex) {
  Log.i(TAG, "Oops" + ex.getMessage());
}

And here's my sender:

    public void sendBroadcast(String messageStr) {
    // Hack Prevent crash (sending should be done using an async task)
    StrictMode.ThreadPolicy policy = new   StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);

    try {
      //Open a random port to send the package
      DatagramSocket socket = new DatagramSocket();
      socket.setBroadcast(true);
      byte[] sendData = messageStr.getBytes();
      DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, getBroadcastAddress(), Constants.PORT);
      socket.send(sendPacket);
      System.out.println(getClass().getName() + "Broadcast packet sent to: " + getBroadcastAddress().getHostAddress());
    } catch (IOException e) {
      Log.e(TAG, "IOException: " + e.getMessage());
    }
  }

  InetAddress getBroadcastAddress() throws IOException {
    WifiManager wifi = (WifiManager) 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);
  }