Jvalant Dave
Jvalant Dave

Reputation: 531

How to keep using SSDP to search for devices on local network on Android?

I'm developing an app that, at startup, uses SSDP to connect to a server and retrieve it's IP Address. The SSDP class was not developed by me so I'm open to any refactoring suggestions in there as well but for this question, I'm trying to implement the logic that will keep searching for the server using SSDP while avoiding any crashes or timeout exceptions from being thrown.

Currently, my presenter class uses a private AsyncTask class to get the response from the server(called MOTA or OTA station in the commenting):

private class SearchAction extends AsyncTask<Void,Void,String>{
    Context context;

    SearchAction(Context context){
        this.context = context;
    }

    protected void onPreExecute(){
        view.changeVisibility(true);
    }

    @Override
    protected String doInBackground(Void... params) {
        //Get IP Address from MOTA Station
        SSDP ssdp = new SSDP();
        String ip = ssdp.request();
        Log.d(TAG,"IP Address is: "+ ip);
        return ip;
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    protected void onPostExecute(String ip_address){
        Log.d(TAG, "IP address is:  " + ip_address);


        if (Objects.equals(ip_address, "")) {

            view.changeVisibility(false);
            // TODO: give choice to user to enter IP address manually
        }else {
            //otherwise go to MainActivity directly
            Intent intent = new Intent(context, Main2Activity.class);
            intent.putExtra("IP", ip_address);
            view.navigateToMainActivity(intent);

        }
    }
}

The SSDP class looks like so:

public class SSDP {

public String tag = "SSDP";

//m-search string for specific OTA board
private static final String query =
        "M-SEARCH * HTTP/1.1\r\n" +
                "HOST: 239.255.255.250:1900\r\n"+
                "MAN: \"ssdp:discover\"\r\n"+
                "MX: 1\r\n"+
                "ST: urn:schemas-upnp-org:device:MediaServer:1\r\n"+  // Use for OTA Board
                //"ST: ssdp:all\r\n"+  // Use this for all UPnP Devices
                "\r\n";
private static final int port = 1900;

//ssdp to find IP address from server
public String request(){
    //response is to contain the server response in String type
    //initialize send data and receive data in bytes
    String response="";
    byte[] sendData = new byte[1024];
    byte[] receiveData = new byte[1024];
    //transfer m-search string in bytes
    sendData = query.getBytes();
    //wrap m-search data, multicast address and port number to the send package
    DatagramPacket sendPacket = null;
    try {
        sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("239.255.255.250"), port);
    } catch (UnknownHostException e) {
        Log.d(tag,"Unknown Host Exception Thrown after creating DatagramPacket to send to server");
        e.printStackTrace();
    }
    //create socket to transport data
    DatagramSocket clientSocket = null;
    try {
        clientSocket = new DatagramSocket();
    } catch (SocketException e) {
        Log.d(tag, "Socket Exception thrown when creating socket to transport data");
        e.printStackTrace();
    }
    //send out data
    try {
        if (clientSocket != null) {
            //time out is important
            clientSocket.setSoTimeout(10000);
            clientSocket.send(sendPacket);
        }
    } catch (IOException e) {
        Log.d(tag, "IOException thrown when sending data to socket");
        e.printStackTrace();
    }
    // receive data
    DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
    try {
        if (clientSocket != null) {
            clientSocket.receive(receivePacket);
        }
    } catch (IOException e) {
        Log.d(tag,"IOException thrown when receiving data");
        e.printStackTrace();
    }
    //the target package should not be empty
    //try three times

    for (int i =0; i<3; i++){
        Log.d(tag,"Checking target package to see if its empty on iteration#: "+i);
        response = new String(receivePacket.getData());
        Log.d(tag,"Response contains: "+response);
        if (response.contains("Location:")){
            break;
        }
    }


    String adress = "";
    //filter IP address from "Location"
    Matcher ma = Pattern.compile("Location: (.*)").matcher(response);
    if (ma.find()){
        adress+=ma.group(1);
        adress = adress.split("/")[2].split(":")[0];
    }

    return adress;

}
}

My question is, how can I call request() repeatedly (or a specific part of request()) until I get a response from the server?

Upvotes: 0

Views: 1617

Answers (1)

Jvalant Dave
Jvalant Dave

Reputation: 531

I used a Timer Task to perform the AsyncTask every 5 seconds.

private Runnable ssdpTimerTask = new Runnable() {
        @Override
        public void run() {
            startStationSearch();
            Log.d(TAG,"Running SSDP search - iteration: "+ssdpIteration);
            ssdpIteration++;
            mHandler.postDelayed(ssdpTimerTask,5000);
        }
    };

Upvotes: 1

Related Questions