Jpcap crashes when trying to open device - java

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

Related

Where can I find the set of exit codes that may be returned by dvd+rw-mediainfo

Running on redhat 7.9. I will be using dvd+rw-mediainfo wrapped by either ProcBuilder from apache or the ProcessBuilder from java 11 to query the state of media inserted into an optical drive. I'd like information about the possible exit values dvd+rw-mediainfo can produce. Empirically I have determined that 251 means there is no disc inserted into the drive and 130 means there is no drive matching the argument to the command. Are there any other exit codes I should be aware of? I looked at the c source I found at https://sources.debian.org/src/dvd+rw-tools/7.1-3/dvd+rw-mediainfo.cpp/ but there is no definition of the return codes in there. There are not a lot of included h files. I was unable to find stddef.h on my system which I sort of suspected might be the location.
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
I'm not very adept at c++ (strictly java) but I was hoping to find a h file that defined the exit codes. They are not listed in the man page entries for the command. Where I see exit called in the source it is not clear to me where the values are defined.
if ((err=cmd.transport(READ,inq,36)))
sperror ("INQUIRY",err),
exit (FATAL_START(errno));
I don't see where the value of errno is set. I also can't find the definitation of FATAL_START. Also one exit calls uses a constant that I can't find defined anywhere.
exit (FATAL_START(EINVAL));
For the errno values, see errno.h (and other files included from therein), which on a RedHat-based system you will find in /usr/include/errno.h, provided by package glibc-headers.
Looking at your link to the source code, the macro FATAL_START seems to be defined in the header file transport.hxx, and it just sets bit 7:
#define FATAL_START(er) (0x80|(er))
So, exit code 251 = 128 + 123 would correspond to this:
#define ENOMEDIUM 123 /* No medium found */
And 130 = 128 + 2 corresponds to this:
#define ENOENT 2 /* No such file or directory */

InetAddress.getLocalHost().getHostName() different behavior between JDK 11 and JDK 8

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

JNAerator generates method with __stdcall return value

I'm currently struggling to generate a JNA wrapper for a DLL that I have to use.
The DLL and the corresponding .h files are provided by IBM (Spectrum Protect aka Tivoli Storage Manager or ADSTAR) and for the life of me, I cannot use JNAerator properly, as it seems.
Example:
This is an excerpt of one of the header files:
extern dsInt16_t DSMLINKAGE dsmInitEx(
dsUint32_t *dsmHandleP,
dsmInitExIn_t *dsmInitExInP,
dsmInitExOut_t *dsmInitExOutP
);
This dsInt16_t turns out to be defined in a separate .h file:
typedef signed short dsInt16_t;
The result after running JNAerator is not what I would have expected:
Tsmapi64Library.__stdcall dsmInitEx(NativeLongByReference dsmHandleP, dsmInitExIn_t dsmInitExInP, dsmInitExOut_t dsmInitExOutP);
The return type is defined as follows:
public static class __stdcall extends PointerType {
...
};
Mind you, last time I worked with C was in school, and that is 20+ years ago, so I am definitely a bit rusty.
What am I missing here? I would have hoped that the return value would be a dsInt16_t or short, for example.
A follow-up question: the DLL provides a method for explaining return codes (the aforementioned dsInt16_t return value).
Again, this is the definition in the .h file:
extern dsInt16_t DSMLINKAGE dsmRCMsg(
dsUint32_t dsmHandle,
dsInt16_t dsmRC,
char *msg
);
...and this is the resulting Java code:
Tsmapi64Library.__stdcall dsmRCMsg(NativeLong dsmHandle, dsInt16_t dsmRC, ByteBuffer msg);
So, it "translated" the C-parameter type dsInt16_t into the Java type dsInt16_t, which is nice.
Since this Java type dsInt16_t is an interface, how would I be able to create an instance of this type so that I could actually call the method? (I guess this question is obsolete once the first one is resolved.)

JNI call to dll method does not work - UnsatisfiedLinkError

I have created Java proxies with swig from a Header File.
Now i get an UnsatisfiedLinkError which (i think) points to a non existing method.
LcDll:DLL_PROCESS_ATTACH
Exception in thread "main" java.lang.UnsatisfiedLinkError: barJNI._LC_application_get()J
at barJNI._LC_application_get(Native Method)
at bar.LC_application_get(bar.java:31)
at LumicamTest.main(LumicamTest.java:171)
LcDll:DLL_THREAD_DETACH
LcDll:DLL_THREAD_DETACH
LcDll:DLL_THREAD_DETACH
LcDll:DLL_THREAD_DETACH
LcDll:DLL_THREAD_DETACH
LcDll:DLL_THREAD_DETACH
LcDll:DLL_PROCESS_DETACH
The LcDll messages show me, that the DLL could get loaded.
I want to call the following method:
public final static native long _LC_application_get();
The methow was generated by swig as LC_application_get(); without underscore.
I have tried both variants, with and without underscore, cause the DLL explorer shows the method with underscore.
The dll explorer shows the method as following: _LC_application_get#0
I suppose that the #0 means, that the method has no parameters in it's signature.
Has someone an idea, what could be the problem?
thanks in advance

Java Strings via SWIG in Android NDK have strange characters in place of null bytes

I am using SWIG to generate an interface to some C code which I have compiled as an Android NDK library. My C code NDK library uses a structure, MY_STRUCT that contains char* elements that pass data in both the in and out directions and the SWIG generated JNI works fine as far as that goes, ie I can read the strings in the C code, set data and read the result in the Java code as required.
However I have a problem in that if I pass in a java String that contains null bytes the nulls are replaced by "\300\200"
Eg, if I create a string in java as follows :
MY_STRUCT myStruct = new MY_STRUCT();
byte[] myBytes = new byte[21];
String myString = new String(myBytes);
myStruct.setName(myString);
then myStruct has it's name field set to 21 null bytes as required and this is visible in the java debugger, but the string passed across to my NDK library code as seen in the NDK C debugger is as follows :
"\300\200\300\200\300\200\300\200\300\200\300\200\300\200\300\200\300\200\300\200\300\200\300\200\300\200\300\200\300\200\300\200\300\200\300\200\300\200\300\200\300\200"
My SWIG .i file has the following relevant portion :
%include various.i
%include cpointer.i
%pointer_functions(int, intp);
%include ../../../mydir/myheader.h
myheader.h has the following relevant portion :
typedef struct
{
...
char* name;
...
} *P_MY_STRUCT, MY_STRUCT;
The C code debugs fine and I can read and write all the strings pointed to by the name etc elements of MY_STRUCT, the only issue is the transformation of null elements of the strings input to the SWIG generated JNI code into the strange "\300\200" elements in the C code in the NDK library.
EDIT:
Considering an alternative : I have several functions that take byte arrays instead of strings for C-function char* arguments and this is achieved in the myModule.i file as follows :
bool myFunc(P_MY_STRUCT, char* BYTE, int32_t);
Is there any way in SWIG of achieving the equivalent of the BYTE functionality for structure members ? I tried using the same BYTE trick in myModule.i as follows but it didn't work :
typedef struct
{
...
char* BYTE;
...
} *P_MY_STRUCT, MY_STRUCT;
Thanks again,
This is known crazy behavior by Java and described in the answers to this question:
What does it mean to say "Java Modified UTF-8 Encoding"?

Categories

Resources