Android - Call to REST service failing with EHOSTUNREACH

I’m developing an app which is going to use the Estimote beacons to retrieve information about the environment and have them sent to a server using a REST service. In order to verify how the communication would work, I firstly created a “mock” of the data that would be sent to the server, using a button on my application to trigger it. Then, once this was working, I introduced the beacons, and tried to do the same, but this time, once the beacons were discovered, the data gathered would be sent to the server. Even though the code is the same, using the beacons does not work, throwing the error “connect failed: EHOSTUNREACH (No route to host)”, and I cannot figure out why.

Class that finds the beacons

public class MainActivity extends AppCompatActivity {
    private static final String ESTIMOTE_PROXIMITY_UUID = "B9407F30-F5F8-466E-AFF9-25556B57FE6D";
    private static final Region ALL_ESTIMOTE_BEACONS = new Region("regionId", ESTIMOTE_PROXIMITY_UUID, null, null);
    private static final String TAG = "MainActivity";
    private BeaconManager beaconManager;
    private String host;
    private JSONInterface jsonInterface;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        jsonInterface = new JSONInterface();
        setContentView(R.layout.activity_main);
        beaconManager = new BeaconManager(this);
        final TextView view = (TextView) findViewById(R.id.text);
        Button button = (Button) findViewById(R.id.sendRequest);
        button.setOnClickListener(new View.OnClickListener(){
            public void onClick(View v){
                EditText ip = (EditText) findViewById(R.id.ip);
                host = ip.getText().toString();
                EditText id = (EditText) findViewById(R.id.id);
            }
        });
        beaconManager.setRangingListener(new BeaconManager.RangingListener() {
            @Override
            public void onBeaconsDiscovered(Region region, final List<Beacon> beacons) {
                Log.d("Estimote", "Ranged beacons: " + beacons);
                JSONObject root = null;
                try {
                    Handler handler = new Handler();
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            jsonInterface.sendJson(beacons);
                        }
                    });
                }
                catch(Exception e )
                {
                    e.printStackTrace();
                }
            }
        });
    }
    private void setHost(String host)
    {
        this.host = host;
    }
    @Override
    protected void onStart() {
        super.onStart();
       beaconManager.connect(new BeaconManager.ServiceReadyCallback() {
            @Override
            public void onServiceReady() {
                try {
                    beaconManager.startRanging(ALL_ESTIMOTE_BEACONS);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    @Override
    protected void onStop()
    {
        super.onStop();
        try{
            beaconManager.stopRanging(ALL_ESTIMOTE_BEACONS);
        }catch(Exception e)
        {
            e.printStackTrace();
        }
        finally{
            super.onStop();
        }
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

Class that sends the requests

public class JSONInterface {
    public  JSONObject sendJson(List<Beacon> beacons)
    {
        JSONObject root = new JSONObject();
        JSONObject json = new JSONObject();
        JSONArray jsonArray = new JSONArray();
        try {
            //for (Beacon beacon : beacons) {
            for(int i=0;i<3;i++){
                json.put("id", 4);
                json.put("controller_id", i);
                json.put("proximity", "FAR");
                jsonArray.put(json);
                json = new JSONObject();
            }
            root.put("controllers", jsonArray);
            Log.d("JSONInterface ", root.toString());
            String retorno = new JSONCall().execute(root).get();


            return root;
        }catch(Exception e)
        {
            e.printStackTrace();
            while(true){}
        }
    }

    private class JSONCall extends AsyncTask<JSONObject,Void,String> {


        @Override
        protected String doInBackground(JSONObject... jsons)
        {
            String ret = "Success!";
            HttpPost httpPost=null;
            try {

                JSONObject json = (JSONObject) jsons[0];
                Log.d("JSONInterface ", json.toString());
                String host = "192.168.0.13:3002";
                URL url = new URL("http://"+host+"/controller/addagent");

                Log.d("JSONInterface ",json.toString());

                HttpClient httpClient = new DefaultHttpClient();
                httpPost = new HttpPost(url    .toURI());

                httpPost.setEntity(new StringEntity(json.toString(), "UTF-8"));

                httpPost.setHeader("Content-Type", "application/json");
                httpPost.setHeader("Accept-Encoding", "application/json");
                httpPost.setHeader("Accept-Language", "en-US");
                httpClient.execute(httpPost);
                httpPost.abort();
            } catch (Exception e) {
                e.printStackTrace();
                httpPost.abort();
                ret = e.toString();
            }
            finally{

                return ret;
            }

        }
        @Override
        protected void onPostExecute(String result) {
        }

        @Override
        protected void onPreExecute() {
        }

        @Override
        protected void onProgressUpdate(Void... values) {
        }
    }
}

Exception:

09-26 16:00:03.313 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ org.apache.http.conn.HttpHostConnectException:
Connection to http://192.168.0.13:3002 refused 09-26 16:00:03.313
29064-30218/tccii.fernando.tccii_agentsmonitoring W/System.err﹕ at
org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:183)
09-26 16:00:03.313 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ at
org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
09-26 16:00:03.313 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ at
org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
09-26 16:00:03.313 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ at
org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360)
09-26 16:00:03.313 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ at
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:670)
09-26 16:00:03.313 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ at
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:509)
09-26 16:00:03.313 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ at
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
09-26 16:00:03.313 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ at
tccii.fernando.tccii_agentsmonitoring.JSONInterface$JSONCall.doInBackground(JSONInterface.java:79)
09-26 16:00:03.313 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ at
tccii.fernando.tccii_agentsmonitoring.JSONInterface$JSONCall.doInBackground(JSONInterface.java:53)
09-26 16:00:03.313 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ at android.os.AsyncTask$2.call(AsyncTask.java:288) 09-26
16:00:03.313 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ at
java.util.concurrent.FutureTask.run(FutureTask.java:237) 09-26
16:00:03.313 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ at
android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) 09-26
16:00:03.313 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
09-26 16:00:03.313 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
09-26 16:00:03.313 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ at java.lang.Thread.run(Thread.java:841) 09-26
16:00:03.313 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ Caused by: java.net.ConnectException: failed to connect
to /192.168.0.13 (port 3002): connect failed: EHOSTUNREACH (No route
to host) 09-26 16:00:03.313
29064-30218/tccii.fernando.tccii_agentsmonitoring W/System.err﹕ at
libcore.io.IoBridge.connect(IoBridge.java:114) 09-26 16:00:03.313
29064-30218/tccii.fernando.tccii_agentsmonitoring W/System.err﹕ at
java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192) 09-26
16:00:03.313 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ at
java.net.PlainSocketImpl.connect(PlainSocketImpl.java:460) 09-26
16:00:03.313 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ at java.net.Socket.connect(Socket.java:833) 09-26
16:00:03.313 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ at
org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:119)
09-26 16:00:03.313 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ at
org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:144)
09-26 16:00:03.313 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ … 14 more 09-26 16:00:03.313
29064-30218/tccii.fernando.tccii_agentsmonitoring W/System.err﹕ Caused
by: libcore.io.ErrnoException: connect failed: EHOSTUNREACH (No route
to host) 09-26 16:00:03.323
29064-30218/tccii.fernando.tccii_agentsmonitoring W/System.err﹕ at
libcore.io.Posix.connect(Native Method) 09-26 16:00:03.323
29064-30218/tccii.fernando.tccii_agentsmonitoring W/System.err﹕ at
libcore.io.BlockGuardOs.connect(BlockGuardOs.java:85) 09-26
16:00:03.323 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ at libcore.io.IoBridge.connectErrno(IoBridge.java:127)
09-26 16:00:03.323 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ at libcore.io.IoBridge.connect(IoBridge.java:112) 09-26
16:00:03.323 29064-30218/tccii.fernando.tccii_agentsmonitoring
W/System.err﹕ … 19 more

EDIT 1

The part of the code that does not work, when I add the beacons, is the method “doInBackground” from the private class JSONCall.

This is the flow :

  1. MainActivity -> looks for beacons around and creates a list, called “beacons”

  2. MainActivity -> calls the sendJSON method, from JSONInterface, and sends the “beacons” list to it

  3. JSONInterface -> creates the JSON request based on the list provided by MainActivity

  4. JSONInterface -> sends the JSON object to the JSONCall class, which is responsible for calling the REST service that was exposed this is the point where it fails when I add the beacons, if I just use a hard coded request, sent whenever I press a button, it works.

EDIT 2

This code works (I just commented out the part where I look for the beacons)

public class MainActivity extends AppCompatActivity {
    private static final String ESTIMOTE_PROXIMITY_UUID = "B9407F30-F5F8-466E-AFF9-25556B57FE6D";
    private static final Region ALL_ESTIMOTE_BEACONS = new Region("regionId", ESTIMOTE_PROXIMITY_UUID, null, null);
    private static final String TAG = "MainActivity";
    private BeaconManager beaconManager;
    private String host;
    private JSONInterface jsonInterface;
    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        jsonInterface = new JSONInterface();
        setContentView(R.layout.activity_main);
        beaconManager = new BeaconManager(this);
        final TextView view = (TextView) findViewById(R.id.text);

        Button button = (Button) findViewById(R.id.sendRequest);
        button.setOnClickListener(new View.OnClickListener(){
            public void onClick(View v){
                EditText ip = (EditText) findViewById(R.id.ip);
                host = ip.getText().toString();
                EditText id = (EditText) findViewById(R.id.id);
                jsonInterface.sendJson(null);
            }
        });


      /* beaconManager.setRangingListener(new BeaconManager.RangingListener() {
            @Override
            public void onBeaconsDiscovered(Region region, final List<Beacon> beacons) {
                Log.d("Estimote", "Ranged beacons: " + beacons);
                JSONObject root = null;
                try {

                    Handler handler = new Handler();
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            jsonInterface.sendJson(beacons);
                        }
                    });

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

            }
        });*/


    }
    private void setHost(String host)
    {
        this.host = host;
    }


    @Override
    protected void onStart() {
        super.onStart();
      /* beaconManager.connect(new BeaconManager.ServiceReadyCallback() {
            @Override
            public void onServiceReady() {
                try {
                    beaconManager.startRanging(ALL_ESTIMOTE_BEACONS);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });*/
    }

    @Override
    protected void onStop()
    {
        super.onStop();
        /*try{
            beaconManager.stopRanging(ALL_ESTIMOTE_BEACONS);
        }catch(Exception e)
        {
            e.printStackTrace();
        }
        finally{
            super.onStop();
        }*/
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }



}

EDIT 3

After going through the code, we found out that the line below makes this error happen

                beaconManager.startRanging(ALL_ESTIMOTE_BEACONS);

If we keep it commented, then it works. We have changed the code so we could control the requests made by hard coding them and having a button trigger them.

That’s very interesting and I’m thinking how those two can be related at all.

Let’s start with error
org.apache.http.conn.HttpHostConnectException: Connection to http://192.168.0.13:3002 refused 09-26 16:00:03.313 as it would indicate network error but you write that occurs only after starting ranging.

EstimoteSDK uses OkHttp library underneath but in case of simple ranging it is not used.

One thing that I would try is use OkHttp library to perform network call instead of HttpClient. Are you able to do that?

Thanks for your reply!

I’ll look into that and I’ll let you know!

Hi,

I tried using OkHTTP and the same error kept happening.

This is the code I’m using now:

import android.os.AsyncTask;
import android.util.Log;

import com.estimote.sdk.Beacon;

import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONObject;

import com.squareup.okhttp.HttpUrl;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request.Builder;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;

import java.net.URL;
import java.util.List;

/**
 * Created by Fernando on 26/09/2015.
 */
public class JSONInterface {

    public  JSONObject sendJson(List<Beacon> beacons)
    {
        JSONObject root = new JSONObject();
        JSONObject json = new JSONObject();
        JSONArray jsonArray = new JSONArray();
        try {
            //for (Beacon beacon : beacons) {
            for(int i=0;i<1;i++){
                json.put("id", 4);
                json.put("controller_id", i);
                json.put("proximity", "FAR");
                jsonArray.put(json);
                json = new JSONObject();
            }
            root.put("controllers", jsonArray);
            Log.d("JSONInterface ", root.toString());
            JSONCall jsonCall = new JSONCall();
            String retorno = jsonCall.execute(root).get();


            return root;
        }catch(Exception e)
        {
            e.printStackTrace();
            while(true){}
        }
    }

    private class JSONCall extends AsyncTask<JSONObject,Void,String> {


        @Override
        protected String doInBackground(JSONObject... jsons)
        {
            return postJson(jsons);
        }

        private JSONObject getJson()
        {
            return null;
        }

        private String postJson(JSONObject... jsons ){
            String ret = "Success!";
            HttpPost httpPost=null;
            try {

                JSONObject json = (JSONObject) jsons[0];
                Log.d("JSONInterface ", json.toString());
                String url = "http://192.168.0.13:3002/controller/addagent";

                OkHttpClient okClient = new OkHttpClient();

                final MediaType JSON = MediaType.parse("application/json; charset=utf-8");

                RequestBody body = RequestBody.create(JSON, json.toString());
                Request request = new Request.Builder().url(url).post(body).build();
                Response response = okClient.newCall(request).execute();
                Log.d("RESPONSE ",response.body().string());

                /*String host = "192.168.0.13:3002";
                URL url = new URL("http://"+host+"/controller/addagent");

                Log.d("JSONInterface ",json.toString());

                HttpClient httpClient = new DefaultHttpClient();
                httpPost = new HttpPost(url    .toURI());

                httpPost.setEntity(new StringEntity(json.toString(), "UTF-8"));

                httpPost.setHeader("Content-Type", "application/json");
                httpPost.setHeader("Accept-Encoding", "application/json");
                httpPost.setHeader("Accept-Language", "en-US");
                httpClient.execute(httpPost);*/
                //httpPost.abort();
            } catch (Exception e) {
                e.printStackTrace();
                //httpPost.abort();
                ret = e.toString();
            }
            finally{

                return ret;
            }
        }

        @Override
        protected void onPostExecute(String result) {
        }

        @Override
        protected void onPreExecute() {
        }

        @Override
        protected void onProgressUpdate(Void... values) {
        }
    }
}

What was the exception this time?

Can you publish your sample server somewhere and attach app source to this event?

Hi,

You can find my code here: https://github.com/FernandoNos/TCCII/tree/2351efd8df3b042e4b208da439f3e22eaba62ada5

The server is not even called, I can upload it if necessary.

I’m using Android 4.4.2 on a Galaxy S4 GT-I9515L, version com.estimote:sdk:0.8.7@aar.

The exception is still the same.

Hi @Fernando_Nos,

Unfortunately link you gave does not work, results in 404 not found. Can you also deploy server code somewhere so I can test it from mobile app?

Hi,

This should work https://github.com/FernandoNos/TCCII

I can’t upload the server code now, I’ll do it asap.

I uploaded the server code to the same repository (https://github.com/FernandoNos/TCCII).

Hi,

I created another project so I could try some things on the randing code, since as part of my project I would have to identify all the beacons in a given area. What I did was: I started connecting and disconnecting the beaconManager, and it worked, the problem I started having was that the application would close with no exception being thrown. You can find the code here https://www.dropbox.com/s/qpw1fos628jpkyv/AgentsMonitoring.rar?dl=0.

I was also facing issues with the ranging, which would stop listing the beacons.

After including the new code in my main project, the problem happened again, I then moved on to making asynchronous calls to the same service, which seem to avoid the error, but then I lose control over the time when the request will reach the server.

EDIT1
After running it for some time, the same issue started happening again.

EDIT 2
If I uninstall the application and run it again, the issue doesn’t happen for some time.

I can help only if you deploy server somewhere where it is publicly reachable.