Under the hood, in order to obtain the localhost name the SDK perform a native invocation to the underlying operating system.
The C function which is involved is getLocalHostName
. For both IP version 4 and 6 you can find the appropriate implementation: basically it is the same source code with minimal changes to take into consideration if you are using IP version 6.
Let's assume for instance the code for IP version 4.
For Java 11, the corresponding native code is implemented in Inet4AddressImpl.c. This is how getLocalHostname
is implemented:
/*
* Class: java_net_Inet4AddressImpl
* Method: getLocalHostName
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL
Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
char hostname[NI_MAXHOST + 1];
hostname[0] = '\0';
if (gethostname(hostname, sizeof(hostname)) != 0) {
strcpy(hostname, "localhost");
} else {
#if defined(__solaris__)
// try to resolve hostname via nameservice
// if it is known but getnameinfo fails, hostname will still be the
// value from gethostname
struct addrinfo hints, *res;
// make sure string is null-terminated
hostname[NI_MAXHOST] = '\0';
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_INET;
if (getaddrinfo(hostname, NULL, &hints, &res) == 0) {
getnameinfo(res->ai_addr, res->ai_addrlen, hostname, sizeof(hostname),
NULL, 0, NI_NAMEREQD);
freeaddrinfo(res);
}
#else
// make sure string is null-terminated
hostname[NI_MAXHOST] = '\0';
#endif
}
return (*env)->NewStringUTF(env, hostname);
}
As you can see, when using something different from Solaris, it seems that the code only relies on gethostname
to obtain the required value. This restriction was introduced in this commit in the context of this bug.
Here you can see the analogous IP 4 version native source code implementation for Java 8.
In that source code you can find several differences with the previous one for Java 11.
First, the code is divided in two sections depending on whether the following definition applies:
#if defined(__GLIBC__) || (defined(__FreeBSD__) && (__FreeBSD_version >= 601104))
#define HAS_GLIBC_GETHOSTBY_R 1
#endif
#if defined(_ALLBSD_SOURCE) && !defined(HAS_GLIBC_GETHOSTBY_R)
...
#else /* defined(_ALLBSD_SOURCE) && !defined(HAS_GLIBC_GETHOSTBY_R) */
...
and the implementation provided for getLocalHostName
is different if the condition applies or not.
In my opinion, in the case of Redhat the condition does not apply and, as a consequence, the following code is the one used at runtime:
/************************************************************************
* Inet4AddressImpl
*/
/*
* Class: java_net_Inet4AddressImpl
* Method: getLocalHostName
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL
Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
char hostname[NI_MAXHOST+1];
hostname[0] = '\0';
if (JVM_GetHostName(hostname, sizeof(hostname))) {
/* Something went wrong, maybe networking is not setup? */
strcpy(hostname, "localhost");
} else {
struct addrinfo hints, *res;
int error;
hostname[NI_MAXHOST] = '\0';
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_INET;
error = getaddrinfo(hostname, NULL, &hints, &res);
if (error == 0) {/* host is known to name service */
getnameinfo(res->ai_addr,
res->ai_addrlen,
hostname,
NI_MAXHOST,
NULL,
0,
NI_NAMEREQD);
/* if getnameinfo fails hostname is still the value
from gethostname */
freeaddrinfo(res);
}
}
return (*env)->NewStringUTF(env, hostname);
}
As you can see, this last implementation call gethostname
in first place as well, although indirectly, using JVM_GetHostName
, wrapped in C++ code:
JVM_LEAF(int, JVM_GetHostName(char* name, int namelen))
JVMWrapper("JVM_GetHostName");
return os::get_host_name(name, namelen);
JVM_END
Depending on the actual OS, os::get_host_name
will translate to different functions. For linux it will invoke gethostname
:
inline int os::get_host_name(char* name, int namelen) {
return ::gethostname(name, namelen);
}
If the call to gethostname
succeeds, getaddrinfo
is invoked with the host name returned by gethostname
. If in turn, this last call succeeds, getnameinfo
is invoked, with the address returned by getaddrinfo
to get the final hostname.
In a certain way it seems strange to me, I feel I'm missing something, but these differences can be very likely the cause of the different behavior you experienced; the hypothesis can be tested using the provided native code and debugging the results obtained for your system.