Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android device not receiving multicast package

I am developing a chat application where Android clients will exchange their IP's using multicasting(UDP).

Every device will send its ip to multiple clients(all the devices running this app) in one separate Thread. There will be another receiver thread which will listen to these multicast packets. Here is my code.

//Multicasting code.

DatagramSocket socket = new DatagramSocket(9898);
            byte buff[] = ip.getBytes();
            DatagramPacket packet = new DatagramPacket(buff, buff.length, InetAddress.getByName("224.0.0.1"),9999);
            socket.send(packet);
            socket.close();

//Receiver code

MulticastSocket socket = new MulticastSocket(9999);
        InetAddress group = InetAddress.getByName("224.0.0.1");
        socket.joinGroup(group);

        DatagramPacket packet;

            byte[] buf = new byte[256];
            byte  b = 'x'; //just a separator for time being
            Arrays.fill(buf,b);
            packet = new DatagramPacket(buf, buf.length);
            String received= "";
            while(received!=null)
            {
                socket.receive(packet);
                received = new String(packet.getData());
                received = received.substring(0,received.indexOf('x'));
                this.setIp(received);
                System.out.println("Address: " + received);
            }

        socket.leaveGroup(group);
        socket.close();

The problem is every device prints its own address. It seems it never listens to other multicast packages(I mean it should print other ip's as well). I also get a below log, not sure if that's related.

11-04 23:56:17.985: I/OSNetworkSystem(603): mcastAddDropMembership interfaceIndex=0

Any help will be appreciated.

like image 318
Shashank Kadne Avatar asked Nov 04 '12 18:11

Shashank Kadne


2 Answers

IPv4 multicast support in android is poorely implemented. There are bugs from cupcake era still present.

I ran into a similar problem I was doing a project that relied on mDNS/multicast for service discovery. My Android app would simply not subscribe to the multicast group. I verified this by creating a portable access point on a Ubuntu 14.04 machine and running tcpdump on it. Android devices connected to it simply didn't emit IGMP messages required for joining a group. I could send packets but not receive them.

What I noticed that I was getting an IPv6 join group message to all-systems whenever I joined the networked. This prompted me to try a IPv6 multicast address and that worked.

Newer android devices support IPv6, which has built-in and mandatory multicast support. So instead of using an Class 4 IPv4 multicast address, modify your code to use an IPv6 address. This will make your code to work on at least the local level.

http://developer.android.com/reference/java/net/Inet6Address.html

This page has a wealth of information about which IP to use as per your needs.

Some say that it works without the WiFiManager.crrateMulticastLock() but I didn't try that.

Multicasting to global networks is certainly possible theoretically. But I've never seen a successful practical implementation of one. Given the esoteric routers and firewalls that exist all around.

This SO question shows how it is done on desktop. Similar code also works with android.

IPv6 Multicast example

like image 51
recrsn Avatar answered Nov 03 '22 21:11

recrsn


You need acquire a MulticastLock in your app, which will allow your app receive packets that are not explicitly addressed to this device on the network.

Permission required:

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

Sample code:

// Acquire multicast lock
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
MulticastLock multicastLock = wifi.createMulticastLock("multicastLock");
multicastLock.setReferenceCounted(true);
multicastLock.acquire();

//Do some mutlicast job here
... ...

// Once your finish using it, release multicast lock
if (multicastLock != null) {
    multicastLock.release();
    multicastLock = null;
}
like image 25
yorkw Avatar answered Nov 03 '22 20:11

yorkw