3
votes

TL;DR: SSDP library not receiving datagram. Wireshark shows expected(?) traffic.


I am using the android-dlna library to support SSDP in an Android app. The goal is to discover a custom SSDP-enabled device, get its IP Address, then make RESTful API calls to it. This works well on iOS, but I am having some trouble receiving the datagram on Android.

Using Wireshark, I can determine that the SSDP search goes out, and the device returns with a status OK, but this loop never gets past the receive() method:

SSDPSearchMsg search = new SSDPSearchMsg(SSDP.ST_ContentDirectory);
Log.e("SSDP", search.toString());

SSDPSocket sock = null;

try {
    sock = new SSDPSocket();
    sock.send(search.toString());

    while (true) {
        Log.e("SSDP", "Receive...");//only called once (stuck here)
        DatagramPacket dp = sock.receive();
        Log.e("SSDP", "Datagram Received with data " + new String(dp.getData()));
    }
} catch (IOException e) {
    e.printStackTrace();
}
finally {
    Log.e("SSDP", "Closing Socket");
    if (sock != null)
        sock.close();
}

This is all done in anAsyncTask. I see the following printed to logcat:

SSDP    M-SEARCH * HTTP/1.1
SSDP    Host:239.255.255.250:1900
SSDP    Man:"ssdp:discover"
SSDP    ST:urn:schemas-upnp-org:service:ContentDirectory:1
SSDP    MX:3
SSDP    
SSDP    Receive...

Wireshark Reports the following related datagrams:

    Source      Destination    Protocol    Length    Info
---------------------------------------------------------------------------
 192.168.1.7  239.255.255.250    SSDP       175       M-SEARCH * HTTP/1.1
 192.168.1.1    192.168.1.7      SSDP       356       HTTP/1.1 200 OK

Finally, I have the following Manifest Permissions:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />

What am I overlooking? Why aren't I receiving the Response Datagram?

1
The only difference I can see between my code and yours is instead of DatagramPacket dp = sock.receive(); I use a byte array as a buffer and use DatagramPacket dp = new DatagramPacket(buf, buf.length);. The byte array is simply byte[] buf = new byte[1024];. I then call mSSDPSocket.receive(dp); where mSSDPSocket is my MulticastSocket.Squonk

1 Answers

1
votes

I know this is an old question, but it tripped me up, too, so maybe this will help someone else who stumbles on this question. If you do not acquire a MulticastLock, Android filters out multicast packets, so update the code to acquire a MulticastLock and release it when done.

final WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock lock = wifi.createMulticastLock("ssdp");
try {
    lock.acquire();
    sock = new SSDPSocket();
    sock.send(search.toString());

    while (true) {
        Log.e("SSDP", "Receive...");//only called once (stuck here)
        DatagramPacket dp = sock.receive();
        Log.e("SSDP", "Datagram Received with data " + new String(dp.getData()));
    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    Log.e("SSDP", "Closing Socket");
    if (sock != null)
        sock.close();
    if(lock.isHeld()) {
        lock.release();
    }
}

The following permission are required (already in the OP's manifest file) --

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