I wrote a simple java program to basically run:
System.out.println(InetAddress.getLocalHost().getHostName());
If I compile it and run it on Java 1.7.231 or 1.8.221 On RHEL 7.7, it returns the FQDN (computer.domain.com), but ON THE SAME SERVER, compile it in RHEL JDK 11.0.2 it returns only the server name.
As I understand it should do a reverse DNS lookup (basically a hostname -f) but with JDK 11 the behavior is definitely different. Any idea why is this happening?
This might be the same problem as reported here: InetAddress.getLocalhost() does not give same result in java7 and java8.
It boils down to a change in the JDK:
Since: http://hg.openjdk.java.net/jdk8/jdk8/jdk/rev/81987765cb81 was pushed, we call getaddrinfo / getnameinfo to get a local host name instead of the older (obseleted) gethostbyname_r/gethostbyaddr_r calls.
The newer calls respect the localhosts /etc/nsswitch.conf configuration files. In the case of this machine that file tells these calls to look in files before referencing other naming services.
Since the /etc/hosts file contains an explicit mapping for this hostname / IP combination, that is what is returned.
In the older JDK's the gethostbyname_r actually ignored the local machines settings and immediately delegated to the naming service.
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.
This answer from oracle documentation may help you :
On Red Hat Linux installations InetAddress.getLocalHost() may return an InetAddress corresponding to the loopback address (127.0.0.1). This arises because the default installation creates an association in /etc/hosts between the hostname of the machine and the loopback address. To ensure that InetAddress.getLocalHost() returns the actual host address, update the /etc/hosts file or the name service configuration file (/etc/nsswitch.conf) to query dns or nis before searching hosts.
Link : https://docs.oracle.com/javase/7/docs/technotes/guides/idl/jidlFAQ.html
Similar bug on JDK 1.7
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=7166687
There's a possibility that on JDK 11 the localhostname might have a builtin predefined JDK keyword which can be called when retrieving the localhostname, and you might be overriding the system predefined keyword with your own variable call in which you are calling the localhostname, because sometime we accidentally override a builtin variable with our own userdefined varibale which cause the original builtin keyword to loose its value which in returns shows empty or some other results
This might not be the best answer for your question but I suggest you should check out JDK builtin keywords and RHEL linux builtin keywords for Inet call for returning localhostname in result
In JNI, I am calling a custom array object. I got its type from the foo.getclass().getName() and used that to get GetFieldID.
The type is like: [L fully-qualified-class-name.
In SDK 25, I am able to get the 'GetObjectField' without any error.
In SDK 26, I am getting the following error:
A/zygote64: java_vm_ext.cc:534] JNI DETECTED ERROR IN APPLICATION:
JNI GetObjectField called with pending exception
java.lang.NoSuchFieldError: no type "[Lcom..customClassName;"
found and so no field "fieldname" could be found in class
"Lcom..parentClass;" or its superclasses
I am aware that there are some changes in the newer SDK. But, I am not sure how to change it so that there is no error.
Thanks.
Not sure about #Alex's comment as I was not able to try it.
I found this workaround though,
Java Side:
The custom object's class, ClassA has this class ClassB's array object as below.
public ClassB objb[] = new ClassB[size];
Now instead of sending just ClassA's object to JNI, I sent the object of ClassA and ClassB separately.
As from JNI, it is not accepting custom object's type from SDK 26.
sendA(obja);
sendB(obja.objb[0]);
JNI Side:
ClassA a;
//sendA function for classA similiar as below.
extern "C"
JNIEXPORT jint JNICALL
Java_<PATH_TO_FUNCTION>_sendB(JNIEnv *env,jobject instance,jobject BObj) {
LOGD(TAG,"sendB: START");
jclass jBClass=env->FindClass("com/< path to class separated by '/' >");
// int Field jbid
jfieldID jbid = env->GetFieldID(jBClass, "bId", "I");
jint bId = env->GetIntField(BObj, jbid);
obja.objb[0].bId = (int) bId;
LOGI(TAG, "\t bId[%d]: %d ", 0, obja.objb[0].bId);
return 0;
}
For iterations, you can use for loop at java side and send the iterator as a parameter of sendA() and sendB() to JNI.
Also, there is a way of serializing object into string and deserializing it back to object from JNI side.. But, being a novice in JNI, I was not confident enough to deserialize the custom array object on JNI side.
I use Jpcap in order to create ARP requests but when calling the method JpcapCaptor.openDevice(interface,snaplen,promisc,to_ms);, I get the following error :
java.lang.NoSuchMethodError: setPacketValue
at jpcap.JpcapCaptor.nativeOpenLive(Native Method)
at jpcap.JpcapCaptor.openDevice(JpcapCaptor.java:61)
The jpcap dll file I'm using was compiled from the source in order to work on Windows 64 bits. Is there anyway I can solve that weird problem ?
After having looked in the jpcap.dll file source code, I see that the following code is used in the openDevice method (the one that crashes) of the JpcapCaptor.java file:
JpcapCaptor jpcap = new JpcapCaptor();
String ret = jpcap.nativeOpenLive(intrface.name, snaplen, (promisc ? 1 : 0), to_ms);
According to the compiler, this is the second line of this piece of code that crashes. So I looked in the nativeOpenLive method which comes from the file JpcapCaptor.c which starts with:
JNIEXPORT jstring JNICALL
Java_jpcap_JpcapCaptor_nativeOpenLive(JNIEnv *env,jobject obj,jstring device,jint snaplen,jint promisc,jint to_ms){
char *dev;
jint id;
set_Java_env(env);
However, in this last function (set_Java_env), I found the call to the setPacketValue method in the following form: setPacketValueMID=(*env)->GetMethodID(env,Packet,"setPacketValue","(JJII)V");
Having only very weak bases in C, I would like to know the meaning of these different methods and, if possible, where the error comes from.
The source is available at the following address: https://github.com/jovigb/jpcap-x64/blob/master/src
Using Android JNI , I have created file and writing data with file descriptor.
example :-
dest = memalign( BLKSIZE, sz);
if (dest == NULL) {
LOGE("Unable to allocate memory");
return -1;
}
memcpy(dest, bufferIn, sz);
int rc = write(fd, dest, sz);
LOGI("write %d bytes.", rc);
free(dest);
if(rc == -1) {
LOGI("Error in writing : %d %s\n", errno, strerror(errno));
}
Write is successful and I can see data in file. But for each write I am getting log in adb logcat.
01-06 12:46:36.831 16292-16806/com.test.example I/io: write 1024 bytes.
01-06 12:46:36.831 16292-16806/com.test.example W/art: Attempt to remove
local handle scope entry from IRT, ignoring.
what this log mean:- I unable to understand, or what this log mean.
/W/art: Attempt to remove local handle scope entry from IRT, ignoring/
Is it something related to app need to handle.
After browsing android source code which is at
http://androidxref.com/5.1.1_r6/more/art/runtime/indirect_reference_table.cc?q=Attempt+to+remove+local+handle+scope+entry+from+IRT
I was trying delete local reference
(*env)->DeleteLocalRef(env, jbIn);
we don't need to delete local references yourself, once the JNI function returns to Java the references will get GC.
Local references will be discarded by JNI on return from a native method, but this process has nothing to do with Java garbage collection. Usually, we don't need to worry about local references.
I have an JAVA application for the fingerprint scanning and fingerprint matching.For matching the finger prints I am using the libfprint library.I have done all the settings related with the library.
The basic functions like initialization of library is work fine in the application.Now am trying to allocate the memory for the image using the function fpi_img_new() . Here is the syntax for that function
struct fp_img *fpi_img_new(size_t length);
but when I try to allocate some memory by passing the value to this function it shows the following error
GLib-ERROR **: /build/buildd/glib2.0-2.30.0/./glib/gmem.c:170: failed to allocate 3078340616 bytes
/usr/lib/jvm/java-7-openjdk/bin/java: line 31: 3078 Trace/breakpoint trap $jre $args
I am passing the value manually to just check the functionality of this function.But it gets fail.
Could any one please help me in solving the above problem?
Thank you in advance.
EDIT :
Here is my code where i am using the fpi_img_new() function :
API_EXPORTED struct fp_img *fpi_img_new(size_t length)
{
struct fp_img *img = g_malloc(sizeof(*img) + length);
memset(img, 0, sizeof(*img));
fp_dbg("length=%zd", length);
img->length = length;
return img;
}
And i am calling this function by simply passing the integer value like
fpi_img_new(2)