JDK-8060470 : Unify and simplify the implementations of Inet{4,6}AddressImpl_getLocalHostName()
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.net
  • Priority: P4
  • Status: In Progress
  • Resolution: Unresolved
  • Submitted: 2014-10-14
  • Updated: 2015-05-13
Related Reports
Relates :  
Relates :  
Description
I wonder why the implementations of Inet6AddressImpl_getLocalHostName() and
Inet4AddressImpl_getLocalHostName() are different . It seems to me
that this is simply copy/paste error since the very first 1.4 version.
Here's what we currently have:

Inet4AddressImpl_getLocalHostName()

if (gethostname(hostname, NI_MAXHOST)) {
    /* Something went wrong, maybe networking is not setup? */
    strcpy(hostname, "localhost");
} else {
...
    error = getaddrinfo(hostname, NULL, &hints, &res);
...
    error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname,
...
}

We first call gethostname(). If that succeeds we call getaddrinfo()
with the host name returned by gethostname() and if that succeeds
again we call getnameinfo() with the address returned by getaddrinfo()
to get the final hostname. This is uniformly done on all Unix
platforms.

And here's how the corresponding IPv6 version looks like:

Inet6AddressImpl_getLocalHostName()

    ret = gethostname(hostname, NI_MAXHOST);

#if defined(__solaris__) && defined(AF_INET6)
...
    error = getaddrinfo(hostname, NULL, &hints, &res);
...
    error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname,
#endif

As you can see, for the IPv6 version we only do the
getaddrinfo()/getnameinfo() roundtrip on Solaris although there is no
evidence that the inovolved system calls behave differently for IPv4
and IPv6. Instead I think the IPv6 version is just a leftover of the
very first implementation which hasn't been updated in the same way
like its IPv4 counterpart. Notice the comment in the IPv6 version
which says "Solaris doesn't want to give us a fully qualified domain
name". But that holds true for the Linux version as well -
gethostname() on Linux returns "uname -n"  which is usually
unqualified. The comment further notices that even the reverse lookup
may not return a fully qualified name which is true because that's
highly system and name service dependent.

I think we can therefore safely use the same implementation for both,
Inet4AddressImpl_getLocalHostName() and
Inet6AddressImpl_getLocalHostName(). We should actually refactor this
implementation into its own function to avoid differences in the
future.

There's also a funny punchline in this whole story: trough a bug
introduced by the Mac OS port, the two implementations have been
semanticall equal for a while. But then this has been changed back as
a fix for "7166687: InetAddress.getLocalHost().getHostName() returns
FQDN " (https://bugs.openjdk.java.net/browse/JDK-7166687 ,
http://hg.openjdk.java.net/jdk9/dev/jdk/rev/b26c04717735). But I'm
pretty sure that change didn't really fixed the problem described in
the bug report (maybe just incidentally worked around). Here's why:

getLocalHostName() is used by InetAddress.getLocalHost(), but it's
result (i.e. the host name) is immediately converted back into an
address (i.e. InetAddress) on which subsequently getHostName() is
called. The result of  getHostName() only depends on the available
name services and not on the fact if getLocalHostName() returned a
simple or a fully qualified host name. However the resolution of a
host name to an IP-address may be different depending on whether we
have a simple (may resolve trough /etc/hosts) or fully qualified name
(may resolve through name service like DNS).

The hacky way to fix issue 7166687 would be to have the corresponding
entries in your /etc/hosts (i.e. short names for both, IPv4 and IPv6
interfaces). The right way to handle it would be to actually expect
both, simple and full qualified host names as return values from
InetAddress.getHostName().

Notice the InetAddress.getLocalHost() isn't guaranteed to not return
the loopback address. If you have configured your system such that
/etc/hosts associates your host name with the loopback device and
/etc/resolve.conf in such a way to first query /etc/hosts before doing
a name service lookup (which is not unusual) than
InetAddress.getLocalHost() will do just that - return the address of
your loopback device!

So to finally cut a long story short, I propose the following:

 - refactor the implementation of Inet6AddressImpl_getLocalHostName()
and Inet4AddressImpl_getLocalHostName() into a single function which
corresponds to the current Inet4AddressImpl_getLocalHostName()
implementation.

 - it may be also possible to complete omit the call to getnameinfo()
in that new implementation, because as far as I can see the
'ai_canonname' field of the first addrinfo structure returned by
getaddrinfo() already contains the canonical name of the host if we
pass AI_CANONNAME as 'hints' to getaddrinfo (which we already do).

More information can be found in the following mail threads:

http://mail.openjdk.java.net/pipermail/net-dev/2014-October/thread.html#8721
http://mail.openjdk.java.net/pipermail/net-dev/2013-June/thread.html#6543