Why Does Inetaddress.Isreachable Return False, When I Can Ping the Ip Address

Why does InetAddress.isReachable return false, when I can ping the IP address?

The "isReachable" method has not been worthy of using for me in many cases. You can scroll to the bottom to see my alternative for simply testing if you're online and capable of resolving external hosts (i.e. google.com) ... Which generally seems to work on *NIX machines.

The issue

There is alot of chatter about this :

  • Here are other, similar questions :

    Detect internet Connection using Java

    How do I test the availability of the internet in Java?

  • And even a reported bug on this same matter :

    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4921816

Part 1 : A reproducible example of the problem

Note that in this case, it fails.

       //also, this fails for an invalid address, like "www.sjdosgoogle.com1234sd" 
InetAddress[] addresses = InetAddress.getAllByName("www.google.com");
for (InetAddress address : addresses) {
if (address.isReachable(10000))
{
System.out.println("Connected "+ address);
}
else
{
System.out.println("Failed "+address);
}
}
//output:*Failed www.google.com/74.125.227.114*

Part 2 : A Hackish Workaround

As an alternative, you can do this :

// in case of Linux change the 'n' to 'c'
Process p1 = java.lang.Runtime.getRuntime().exec("ping -n 1 www.google.com");
int returnVal = p1.waitFor();
boolean reachable = (returnVal==0);

The -c option of ping will allow ping to simply try to reach the server once(as opposed to the infinite ping which we're used to using at the terminal).

This will return 0 if the host is reachable. Otherwise, you will get "2" as a return value.

Much simpler - but of course it is platform specific.
And there may be certain privilege caveats to using this command - but I find it works on my machines.


PLEASE Note that :
1) This solution is not production quality. Its a bit of a hack. If google is down, or your internet is temporarily slow, or maybe even if there is some funniness in your privileges/system settings, if could return false negatives (i.e. it could fail even though the input address is reachable).
2) The isReachable failure is an outstanding issue. Again - there are several online resources indicating that there is no "perfect" way of doing this at the time of this writing, due to the way the JVM tries to reach hosts - I guess it is an intrinsically platform specific task which, although simple, hasn't yet been abstracted sufficiently by the JVM.

isReachable always returning true regardless of what the IP address is

A way to check if some address is reachable, via java.net.InetAddress.isReachable() methods.
The implementation of these methods goes native and tries to do its best to "ping" the address represented by the InetAddress.

Surprisingly, there are many differences between the Windows and the Linux/Unix implementation of java.net.InetAddress.isReachable().

Windows, as strange as it seems, does not officially support an ICMP "ping" system call. The Java SE 5 implementation hence tries to open a TCP socket on port 7 (the echo service) and hopes to get some sort of reply.

Linux/Unix, instead, supports an ICMP "ping" system call. So the implementation of java.net.InetAddress.isReachable() first tries to perform the "ping" system call; if this fails, it falls back trying to open a TCP socket on port 7, as in Windows.

It turns out that in Linux/Unix the ping system call requires root privileges, so most of the times java.net.InetAddress.isReachable() will fail, because many Java programs are not run as root.

The correct approach is the ICMP protocol. This is what ping uses internally. It is recommended see THIS to gather knowledge and proceed.

FROM: Simone Bordet's Blog

Why does InetAddress.isReachable return false, when I can ping the IP address?

The "isReachable" method has not been worthy of using for me in many cases. You can scroll to the bottom to see my alternative for simply testing if you're online and capable of resolving external hosts (i.e. google.com) ... Which generally seems to work on *NIX machines.

The issue

There is alot of chatter about this :

  • Here are other, similar questions :

    Detect internet Connection using Java

    How do I test the availability of the internet in Java?

  • And even a reported bug on this same matter :

    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4921816

Part 1 : A reproducible example of the problem

Note that in this case, it fails.

       //also, this fails for an invalid address, like "www.sjdosgoogle.com1234sd" 
InetAddress[] addresses = InetAddress.getAllByName("www.google.com");
for (InetAddress address : addresses) {
if (address.isReachable(10000))
{
System.out.println("Connected "+ address);
}
else
{
System.out.println("Failed "+address);
}
}
//output:*Failed www.google.com/74.125.227.114*

Part 2 : A Hackish Workaround

As an alternative, you can do this :

// in case of Linux change the 'n' to 'c'
Process p1 = java.lang.Runtime.getRuntime().exec("ping -n 1 www.google.com");
int returnVal = p1.waitFor();
boolean reachable = (returnVal==0);

The -c option of ping will allow ping to simply try to reach the server once(as opposed to the infinite ping which we're used to using at the terminal).

This will return 0 if the host is reachable. Otherwise, you will get "2" as a return value.

Much simpler - but of course it is platform specific.
And there may be certain privilege caveats to using this command - but I find it works on my machines.


PLEASE Note that :
1) This solution is not production quality. Its a bit of a hack. If google is down, or your internet is temporarily slow, or maybe even if there is some funniness in your privileges/system settings, if could return false negatives (i.e. it could fail even though the input address is reachable).
2) The isReachable failure is an outstanding issue. Again - there are several online resources indicating that there is no "perfect" way of doing this at the time of this writing, due to the way the JVM tries to reach hosts - I guess it is an intrinsically platform specific task which, although simple, hasn't yet been abstracted sufficiently by the JVM.

Why does InetAddress.isReachable return false, when I can ping the IP address?

The "isReachable" method has not been worthy of using for me in many cases. You can scroll to the bottom to see my alternative for simply testing if you're online and capable of resolving external hosts (i.e. google.com) ... Which generally seems to work on *NIX machines.

The issue

There is alot of chatter about this :

  • Here are other, similar questions :

    Detect internet Connection using Java

    How do I test the availability of the internet in Java?

  • And even a reported bug on this same matter :

    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4921816

Part 1 : A reproducible example of the problem

Note that in this case, it fails.

       //also, this fails for an invalid address, like "www.sjdosgoogle.com1234sd" 
InetAddress[] addresses = InetAddress.getAllByName("www.google.com");
for (InetAddress address : addresses) {
if (address.isReachable(10000))
{
System.out.println("Connected "+ address);
}
else
{
System.out.println("Failed "+address);
}
}
//output:*Failed www.google.com/74.125.227.114*

Part 2 : A Hackish Workaround

As an alternative, you can do this :

// in case of Linux change the 'n' to 'c'
Process p1 = java.lang.Runtime.getRuntime().exec("ping -n 1 www.google.com");
int returnVal = p1.waitFor();
boolean reachable = (returnVal==0);

The -c option of ping will allow ping to simply try to reach the server once(as opposed to the infinite ping which we're used to using at the terminal).

This will return 0 if the host is reachable. Otherwise, you will get "2" as a return value.

Much simpler - but of course it is platform specific.
And there may be certain privilege caveats to using this command - but I find it works on my machines.


PLEASE Note that :
1) This solution is not production quality. Its a bit of a hack. If google is down, or your internet is temporarily slow, or maybe even if there is some funniness in your privileges/system settings, if could return false negatives (i.e. it could fail even though the input address is reachable).
2) The isReachable failure is an outstanding issue. Again - there are several online resources indicating that there is no "perfect" way of doing this at the time of this writing, due to the way the JVM tries to reach hosts - I guess it is an intrinsically platform specific task which, although simple, hasn't yet been abstracted sufficiently by the JVM.

Odd InetAddress.isReachable() issue

Thanks everyone, but I never did figure out or pinpoint why this oddity was happening. Everything I checked for was not the cause, so this question can be closed.

In any case, I ended up working around it completely. Instead of using InetAddress, I just went native and built my own ICMP ping class instead, via JNA, invoking Windows libraries IPHLPAPI.DLL and WSOCK32.DLL. Here is what I used...

public interface InetAddr extends StdCallLibrary {
InetAddr INSTANCE = (InetAddr)
Native.loadLibrary("wsock32.dll", InetAddr.class);

ULONG inet_addr(String cp); //in_addr creator. Creates the in_addr C struct used below
}

public interface IcmpEcho extends StdCallLibrary {
IcmpEcho INSTANCE = (IcmpEcho)
Native.loadLibrary("iphlpapi.dll", IcmpEcho.class);

int IcmpSendEcho(
HANDLE IcmpHandle, //Handle to the ICMP
ULONG DestinationAddress, //Destination address, in the form of an in_addr C Struct defaulted to ULONG
Pointer RequestData, //Pointer to the buffer where my Message to be sent is
short RequestSize, //size of the above buffer. sizeof(Message)
byte[] RequestOptions, //OPTIONAL!! Can set this to NULL
Pointer ReplyBuffer, //Pointer to the buffer where the replied echo is written to
int ReplySize, //size of the above buffer. Normally its set to the sizeof(ICMP_ECHO_REPLY), but arbitrarily set it to 256 bytes
int Timeout); //time, as int, for timeout

HANDLE IcmpCreateFile(); //win32 ICMP Handle creator

boolean IcmpCloseHandle(HANDLE IcmpHandle); //win32 ICMP Handle destroyer
}

And then using those to create the following method...

public void SendReply(String ipAddress) {
final IcmpEcho icmpecho = IcmpEcho.INSTANCE;
final InetAddr inetAddr = InetAddr.INSTANCE;
HANDLE icmpHandle = icmpecho.IcmpCreateFile();
byte[] message = new String("thisIsMyMessage!".toCharArray()).getBytes();
Memory messageData = new Memory(32); //In C/C++ this would be: void *messageData = (void*) malloc(message.length);
messageData.write(0, message, 0, message.length); //but ignored the length and set it to 32 bytes instead for now
Pointer requestData = messageData;
Pointer replyBuffer = new Memory(256);
replyBuffer.clear(256);

// HERE IS THE NATIVE CALL!!
reply = icmpecho.IcmpSendEcho(icmpHandle,
inetAddr.inet_addr(ipAddress),
requestData,
(short) 32,
null,
replyBuffer,
256,
timeout);
// NATIVE CALL DONE, CHECK REPLY!!

icmpecho.IcmpCloseHandle(icmpHandle);
}

public boolean IsReachable () {
return (reply > 0);
}


Related Topics



Leave a reply



Submit