5

I have a question about Guava's InetAddress.coerceToInteger method.

According to docs the method:

public static int coerceToInteger(InetAddress ip)

'Returns an integer representing an IPv4 address regardless of whether the supplied argument is an IPv4 address or not. '

But, IPv4 range is of an unsigned 32 bit while Java's int is a signed one - means the returned value can only cover half of the relevant range of IPv4.

Am I missing someone or there is a real problem in the method?

Thanks

Henrik Aasted Sørensen
  • 6,966
  • 11
  • 51
  • 60
Ido
  • 573
  • 4
  • 11

3 Answers3

8

A 32-bit value is a 32-bit value and it can have 2^32 values whether it is signed or unsigned. If you have an address like 192.168.0.1 it will be a negative number, no information is lost. If you turn this into bytes (which are also signed) no information is lost.

BTW: For IPv4 addresses you can use this trick

int address = ip.hashCode();

To treat a 32-bit signed value as a 32-bit unsigned value you can

int address32 = ...
long address = address32 & 0xFFFFFFFFL;

However, you shouldn't need to do this in most situations.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Thanks Peter. Got the point. I think I will use it as an int in my java code and before inserting to DB (as an unsigned int) I will use your trick with the hexadecimal value. But I didn't understand your point about the hashCode for the IPv4. Can you please expand your explanation? – Ido Jan 13 '13 at 13:09
  • This data structure store the address as an `int` internally and when you ask for the hashCode() it happens to give you this value. I would have preferred to have a method like `getAddress()` which is defined to get this value but it happens to work in this case. – Peter Lawrey Jan 13 '13 at 13:25
  • 1
    Okay, got the hashCode point in the InetAddress class. But' as it said [here](http://stackoverflow.com/questions/2241229/going-from-127-0-0-1-to-2130706433-and-back-again) this is not guaranteed. – Ido Jan 13 '13 at 13:31
  • Which is a why a method which did the same thing but was guaranteed would be better. – Peter Lawrey Jan 13 '13 at 13:47
2

I think the Javadoc contains the answer:

IPv6 addresses are coerced to IPv4 addresses before being converted to integers.

As long as there are applications that assume that all IP addresses are IPv4 addresses and can therefore be converted safely to integers (for whatever purpose) this function can be used to handle IPv6 addresses as well until the application is suitably fixed.

NOTE: an IPv6 address coerced to an IPv4 address can only be used for such purposes as rudimentary identification or indexing into a collection of real InetAddresses. They cannot be used as real addresses for the purposes of network communication.

In other words, if you provide an IPv6 address, do not expect it to be an actual, usable address. Be prepared to handle the coerced address with special conditions in your code or network. The documentation could benefit greatly from an example, in my opinion.

Henrik Aasted Sørensen
  • 6,966
  • 11
  • 51
  • 60
1

A long in Java is a 64-bit value, an IPv4 address is only a 32-bit value. The challenge is that Java does not have unsigned data types thus some magic is required to read the unsigned value, typically by upconverting to a long. Guava also has this covered though:

InetAddress addr = InetAddress.getLocalHost();
long ip = UnsignedInts.toLong (InetAddresses.coerceToInteger (addr));
Steve-o
  • 12,678
  • 2
  • 41
  • 60