2

Retrofit on Android 6.0 has a problem making Http calls after connecting to Access Point

Steps to reproduce:

  1. Connect to Esp8266 Access Point
  2. Make an http call to http://192.168.4.1 (Default gateway of esp8266 accesspoint) The IP address of WIFI is 192.168.4.2
  3. It throws the below exception

I have tried the same on Android 5.1 and the same code works flawlessly

java.net.SocketException: socket failed: ENONET (Machine is not on the network)
at libcore.io.IoBridge.socket(IoBridge.java:619)
at java.net.PlainSocketImpl.create(PlainSocketImpl.java:198)
at java.net.Socket.checkOpenAndCreate(Socket.java:689)
at java.net.Socket.setSoTimeout(Socket.java:543)
at okhttp3.internal.io.RealConnection.connectSocket(RealConnection.java:183) at okhttp3.internal.io.RealConnection.buildConnection(RealConnection.java:170) at okhttp3.internal.io.RealConnection.connect(RealConnection.java:111) at okhttp3.internal.http.StreamAllocation.findConnection(StreamAllocation.java:187) at okhttp3.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:123) at okhttp3.internal.http.StreamAllocation.newStream(StreamAllocation.java:93) at okhttp3.internal.http.HttpEngine.connect(HttpEngine.java:296)
at okhttp3.internal.http.HttpEngine.sendRequest(HttpEngine.java:248)
at okhttp3.RealCall.getResponse(RealCall.java:243)
at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:201) at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:163) at okhttp3.RealCall.access$100(RealCall.java:30)
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:127)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) at java.lang.Thread.run(Thread.java:818)
Caused by: android.system.ErrnoException: socket failed: ENONET (Machine is not on the network)
at libcore.io.Posix.socket(Native Method)
at libcore.io.BlockGuardOs.socket(BlockGuardOs.java:282)
at libcore.io.IoBridge.socket(IoBridge.java:604)
at java.net.PlainSocketImpl.create(PlainSocketImpl.java:198) 
at java.net.Socket.checkOpenAndCreate(Socket.java:689) 
at java.net.Socket.setSoTimeout(Socket.java:543)  at okhttp3.internal.io.RealConnection.connectSocket(RealConnection.java:183)  at okhttp3.internal.io.RealConnection.buildConnection(RealConnection.java:170) at okhttp3.internal.io.RealConnection.connect(RealConnection.java:111) 
at okhttp3.internal.http.StreamAllocation.findConnection(StreamAllocation.java:187) at okhttp3.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:123)  at okhttp3.internal.http.StreamAllocation.newStream(StreamAllocation.java:93) at okhttp3.internal.http.HttpEngine.connect(HttpEngine.java:296) 
at okhttp3.internal.http.HttpEngine.sendRequest(HttpEngine.java:248)  at okhttp3.RealCall.getResponse(RealCall.java:243)  at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:201) at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:163) 
at okhttp3.RealCall.access$100(RealCall.java:30) 
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:127) 
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588 at java.lang.Thread.run(Thread.java:818)

thehellmaker
  • 162
  • 3
  • 13
  • 1
    `ENONET (Machine is not on the network)` can have several reasons. The most probable one is that you try to do the socket connection too early, i.e. you don't wait for the android smartphone to be fully connected to the network. Please print out your own IP address before the HTTP request to ensure that. The other thing could be wrong DHCP settings on the ESP created network (like network mask or network gateway). Can you connect to the network with a normal computer? What IP does it draw? Can you ping the gateway? – Maximilian Gerhardt Nov 27 '16 at 15:06
  • It draws the IP 192.168.4.2. It still throws the same exception only on android 6.0.1. On android 5.1 its working fine. – thehellmaker Nov 27 '16 at 15:57
  • I added 5 seconds delay and then got dns info and tried connectin. Ip Address 192.168.4.2 Netmask 255.255.255.0 gateway 192.168.4.1 dns1 192.168.4.1 dns2 0.0.0.0 – thehellmaker Nov 29 '16 at 02:47
  • I am able to ping the gateway. And chrome is able to access http://192.168.4.1 – thehellmaker Nov 29 '16 at 03:56
  • This is nothing to do with retrofit but happening with Volley also. – thehellmaker Dec 01 '16 at 14:19
  • I also found out that if i connect to this on the same thread on click it has an issue. If i do wifi ap transition in the activity or fragment and then on click execute the network call this doesn't happen. But if in case wifi reconnects back then it again has the same issue – thehellmaker Dec 02 '16 at 09:53
  • Looks like change in Access point from the app is causing all successive network calls to fail – thehellmaker Apr 20 '17 at 14:46
  • @AkashA : Did you find any solution, as I'm facing same issue. – Harish Godara May 25 '18 at 07:48
  • I found a solution, This can never be sequential. I use broadcast recievers to figure out network change events and then take appropriate actions rather than waiting on the same async thread. That solves the issue – thehellmaker Apr 02 '19 at 15:28

1 Answers1

1

Problem

Error ENONET means that NetworkInfo.isConnected() returns false

Indicates whether network connectivity exists and it is possible to establish connections and pass data. Always call this before attempting to perform data transactions.

Solution

Spawn a daemon Thread which waits for the Wifi network (given by ssid) to "fully" connect (see above) and call your callback with either true (successfully connected) or false (timeout or error).

Implementation

private ConnectivityManager connectivity = ...;
private WifiManager wifi = ...;

private void waitForWifi(final String ssid, final Consumer<Boolean> callback) {
    final Thread thread = new Thread(() -> {
        for (int i = 0; i < 300; i++) {
            final WifiInfo info = wifi.getConnectionInfo();
            NetworkInfo networkInfo = null;

            for (final Network network : connectivity.getAllNetworks()) {
                final NetworkCapabilities capabilities = connectivity.getNetworkCapabilities(network);

                if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
                    networkInfo = connectivity.getNetworkInfo(network);
                    break;
                }
            }

            if (info != null && info.ssid == ssid && networkInfo != null && networkInfo.isConnected()) {
                callback.accept(true);
                return;
            }

            Thread.sleep(100);
        }

        callback.accept(false);
    });

    thread.setDaemon(true);
    thread.start();
}

Notes

  • ssid must be enclosed in double quotation marks (see wifiConfiguration.SSID)
  • ConnectivityManager.getAllNetworks() requires permission ACCESS_NETWORK_STATE
  • WifiManager.getConnectionInfo() requires permissions ACCESS_NETWORK_STATE and ACCESS_COARSE_LOCATION (runtime permission)
Androbin
  • 991
  • 10
  • 27