using JNI i'm trying to let a C program works under java. Here's the issue.
First i created the java class testcli.java:
public class testcli {
public native void stdErr();
public native int cliFromC();
static {
System.loadLibrary("ctest");
}
public static void main(String[] args) {
new testcli().stdErr();
new testcli().cliFromC();
}
Then compiled with
javac testcli.java
and created header with
javah testcli
after that created the librari ctest.c and compiled with
gcc -o libctest.so -shared -I/path/to/jni.h ctest.c -lc
and i got the libctest.so created, then added to bashrc the following code:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:~/Desktop/project2/thesys/src
and when i go to type
java testcli
it says me "No such file or directory".
I'm running java 8 oracle on a 32 bit machine with xubuntu 32 bit. Any ideas?
EDIT: ADDED right here the ctest.c code ( i think there might be some errors here)
#include <jni.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <signal.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <netdb.h>
#define PORT 20000
#define LENGTH 512
JNIEXPORT void JNICALL Java_testcli_stdErr
(JNIEnv *env, jobject jobj)
{
const char *msg = NULL;
perror(msg);
exit(1);
}
JNIEXPORT jint JNICALL Java_testcli_cliFromC
(JNIEnv *env, jobject jobj)
{
/* Variable Definition */
int sockfd;
int nsockfd;
char revbuf[LENGTH];
struct sockaddr_in remote_addr;
//struct hostent *server; // per la parte scritta da me
/* Get the Socket file descriptor */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
fprintf(stderr, "ERROR: Failed to obtain Socket Descriptor! (errno = %d)\n",errno);
exit(1);
}
/* Fill the socket address struct */
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(PORT);
/*questo lo faccio così perchè localhost è 127.0.0.1, nel caso in cui debba recuperare l'ip dall'hostname uso la parte commentata sopra*/
inet_pton(AF_INET, "127.0.0.1", &remote_addr.sin_addr); //metto in remote_addr.sin_addr l'indirizzo ip 127.0.0.1 nel formato desiderato
bzero(&(remote_addr.sin_zero), 8);
/* Try to connect the remote */
if (connect(sockfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1)
{
fprintf(stderr, "ERROR: Failed to connect to the host! (errno = %d)\n",errno);
exit(1);
}
else
printf("[Client] Connected to server at port %d...ok!\n", PORT);
/* Send File to Server */
//if(!fork())
//{
char* fs_name = "/home/elia/Desktop/project/tesi/PublicKey1";
char sdbuf[LENGTH];
printf("[Client] Sending %s to the Server... ", fs_name);
FILE *fs = fopen(fs_name, "r");
if(fs == NULL)
{
printf("ERROR: File %s not found.\n", fs_name);
exit(1);
}
bzero(sdbuf, LENGTH);
int fs_block_sz;
while((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs)) > 0)
{
if(send(sockfd, sdbuf, fs_block_sz, 0) < 0)
{
fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", fs_name, errno);
break;
}
bzero(sdbuf, LENGTH);
}
printf("Ok File %s from Client was Sent!\n", fs_name);
//}
close (sockfd);
printf("[Client] Connection lost.\n");
return (0);
}
Actually, everything is fine. The error comes from your stdErr() function, and it actually shows it is working. I get the same error. Why does this happen?
const char *msg = NULL;
perror(msg);
exit(1);
This prints the last error that was caused in the program. Now, you should only use perror() if you actually had an error in your program. Otherwise, it will print the message of whatever was in the errno variable previously.
errno may have been set by something inside Java itself. It may have been looking for some file, but its non-existence is not a problem for Java so it continued to work. But errno is set to that value and keeps that value, and that's what's printed in your program.
To prove this, I have added the following to your testcli.java:
public native void clearErr();
And my main is:
public static void main(String[] args) {
new testcli().clearErr();
new testcli().stdErr();
new testcli().cliFromC();
}
And to ctest.c I added:
JNIEXPORT void JNICALL Java_testcli_clearErr
(JNIEnv *env, jobject jobj)
{
errno = 0;
}
Did the javac, javah and gcc again, ran the program, and now I get:
Success
Note that your third method is not called because of the exit() in stdErr().
Related
I want to implement image mosaicking with Java call C++ and This is my Java code
package com.example.jni;
public class JNITest {
static {
System.loadLibrary("ConsoleApplication123");
}
// native method : the floder url that has pictures to be mosaic
public native String hello(String name);
}
I compile it to JNITest.h and in this way I pass a folder rul there have photos,
And then in c + + carry on image splicing.but i do not konw how to read these photos in this folder.If I can read these pictures,I can implement image mosaicking,and finaly I want to return the new foler url that has the mosaicked picturess and this is my image_mosaicking.cpp
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
#include <iostream>
#include <fstream>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/stitching/stitching.hpp"
using namespace std;
using namespace cv;
bool try_use_gpu = true; //false;
vector<Mat> imgs;
string result_name = "result.jpg";
/* Header for class com_example_jni_JNITest */
#ifndef _Included_com_example_jni_JNITest
#define _Included_com_example_jni_JNITest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_jni_JNITest
* Method: hello
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_jni_JNITest_hello
(JNIEnv *env, jobject, jstring path) {
//read the path of this folder
const char* temp_path = env->GetStringUTFChars(path, false);
int numberOfPics = 0;
string pics[100];
//how to get the number of pictures in this folder
//how to get every picture's name into pics[]
for (int i = 1; i < numberOfPics; ++i) {
Mat img = imread(pics[i]); //read every pictures in this folder
if (img.empty()) {
cout << "Can't read image '" << argv[i] << "'\n";
// return null;
}
imgs.push_back(img);
}
Mat pano;
Stitcher stitcher = Stitcher::createDefault(try_use_gpu);
Stitcher::Status status = stitcher.stitch(imgs, pano);
if (status != Stitcher::OK) {
cout << "Can't stitch images, error code = " << int(status) << endl;
// retrun null;
}
imwrite(result_name, pano);
imshow("show", pano);
cv::waitKey(0);
jclass strClass = env->FindClass("Ljava/lang/String;");
jstring imgName = env->NewStringUTF(temp_path);
//rteurn the new folder that has mosaicked pictures
}
#ifdef __cplusplus
}
#endif
#endif
After successfully fire command ndk-build I got .so file in my libs folder, then after some changes in gradle file I got native_libs.xml .idea/libraries folder.
Now I am accessing c function from my java code/ android activity. I am getting signal 11 error
My code is
C file
#include <jni.h>
#include <android/log.h>
#include <stdlib.h>
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#define LOG_TAG "mylib"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
//JNIEXPORT jint JNICALL Java_com_xxx_xxx_activities_SplashActivity_logFileInfo(JNIEnv * env, jobject this, jstring filename);
jint Java_com_xxx_xxx_activities_TutorialsActivity_logFileInfo(JNIEnv * env, jobject this, jstring filename)
{
av_register_all();
AVFormatContext *pFormatCtx;
const jbyte *str;
str = (*env)->GetStringUTFChars(env, filename, NULL);
if(avformat_open_input(&pFormatCtx, str, NULL, NULL)!=0)
{
LOGE("Can't open file '%s'\n", str);
return 1;
}
else
{
LOGI("File was opened\n");
LOGI("File '%s', Codec %s",
pFormatCtx->filename,
pFormatCtx->iformat->name
);
}
return 0;
}
Loading and try to access method in java code is
private static native int logFileInfo(String filename);
static {
System.loadLibrary("framegrabber");
}
In OnCreate of activity
logFileInfo(file.getAbsolutePath());
Finally error at point logFileInfo(file.getAbsolutePath()); is
A/libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0x106e in tid 8905 (Thread-20972)
Please replay if you have any solution, Thanking in advance.
I am trying to use O_direct in Java over JNI in Linux.
here is the java part:
public class jnitest {
static {
System.loadLibrary("jnitest"); // Load native library at runtime
// hello.dll (Windows) or libhello.so (Unixes)
}
private native void test();
private native void write(String path, byte[] chunkpayload);
public static void main(String[] args) {
try{
jnitest t=new jnitest();
byte[] chunk=new byte[5];
chunk[0]=1;
chunk[1]=2;
chunk[2]=3;
chunk[3]=4;
chunk[4]=5;
String s="outtest";
t.write(s,chunk);
}catch(Exception e){
System.out.println("fehler lol");
}
}
}
This is the C part:
#define _GNU_SOURCE
#include <jni.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include "jnitest.h"
#define BLOCKSIZE 512
JNIEXPORT void JNICALL Java_jnitest_write(JNIEnv *env, jobject obj, jstring jpath, jbyteArray jchunkpayload){
const char *path=(*env)->GetStringUTFChars(env, jpath, 0);
printf("path=%s \n",path);
(*env)->ReleaseStringUTFChars(env, jpath, path);
int len = (*env)->GetArrayLength (env,jchunkpayload);
printf("lenght= %d \n",len);
unsigned char* payload =(*env)->GetByteArrayElements(env,jchunkpayload,0);
int i=0;
for(i=0;i<len-1;i++){
printf("%02x \n",(int)payload[i]);
}
void *buffer;
int fd = open(path, O_SYNC|O_APPEND|O_CREAT|O_DIRECT);
posix_memalign(&buffer,BLOCKSIZE,BLOCKSIZE);
memcpy(buffer,payload,len);
write(fd,buffer,BLOCKSIZE);
printf("writen to file\n");
(*env)->ReleaseByteArrayElements(env,jchunkpayload,payload,JNI_ABORT);
free(buffer);
return;
}
JNIEXPORT void JNICALL Java_jnitest_test(JNIEnv *env, jobject obj){
printf("test\n");
return;
}
The program does not fail but the data is never written. I know I can use JNA, but i want to use JNI. Does somebody have a working example for writing a byte array in java over JNI using O_direct?
first of all i'd like to point the fact i'm not too expert with Java and less with C, after that, i'm using JNI to use a C program which is a client application for sockets.
First i've created the main class testcli:
public class testcli {
public native void stdErr();
public native int cliFromC();
static {
System.loadLibrary("ctest");
}
public static void main(String[] args) {
new testcli().stdErr();
new testcli().cliFromC();
}
}
After that i compiled with
javac testcli.java
then created the header file
javah testcli
At this point i've copied the strings i needed and pasted in the new file ctest:
#include <jni.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <signal.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <netdb.h>
#define PORT 20000
#define LENGTH 512
JNIEXPORT void JNICALL Java_testcli_stdErr
(JNIEnv *, jobject)
{
perror(msg);
exit(1);
}
JNIEXPORT jint JNICALL Java_testcli_cliFromC
(JNIEnv *, jobject)
{
/* Variable Definition */
int sockfd;
int nsockfd;
char revbuf[LENGTH];
struct sockaddr_in remote_addr;
//struct hostent *server; // per la parte scritta da me
/* Get the Socket file descriptor */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
fprintf(stderr, "ERROR: Failed to obtain Socket Descriptor! (errno =%d)\n",errno);
exit(1);
}
/* Fill the socket address struct */
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(PORT);
/*questo lo faccio così perchè localhost è 127.0.0.1, nel caso in cui debba recuperare l'ip dall'hostname uso la parte commentata sopra*/
inet_pton(AF_INET, "127.0.0.1", &remote_addr.sin_addr); //metto in remote_addr.sin_addr l'indirizzo ip 127.0.0.1 nel formato desiderato
bzero(&(remote_addr.sin_zero), 8);
/* Try to connect the remote */
if (connect(sockfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1)
{
fprintf(stderr, "ERROR: Failed to connect to the host! (errno = %d)\n",errno);
exit(1);
}
else
printf("[Client] Connected to server at port %d...ok!\n", PORT);
/* Send File to Server */
//if(!fork())
//{
char* fs_name = "/home/elia/Desktop/project/tesi/PublicKey1";
char sdbuf[LENGTH];
printf("[Client] Sending %s to the Server... ", fs_name);
FILE *fs = fopen(fs_name, "r");
if(fs == NULL)
{
printf("ERROR: File %s not found.\n", fs_name);
exit(1);
}
bzero(sdbuf, LENGTH);
int fs_block_sz;
while((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs)) > 0)
{
if(send(sockfd, sdbuf, fs_block_sz, 0) < 0)
{
fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", fs_name, errno);
break;
}
bzero(sdbuf, LENGTH);
}
printf("Ok File %s from Client was Sent!\n", fs_name);
//}
close (sockfd);
printf("[Client] Connection lost.\n");
return (0);
}
At this point i added to my bashrc those lines:
C_INCLUDE_PATH=/usr/lib/jvm/java-8-oracle/include/
C_INCLUDE_PATH=/usr/lib/jvm/java-8-oracle/include/linux/
export C_INCLUDE_PATH
Saved and wrote in terminal
ECHO $C_INCLUDE_PATH
and it gave me only
/usr/lib/jvm/java-8-oracle/include/linux/
which i don't know if it's good or not cause first string is missing. After it i try to compile my ctest.c with this command line:
gcc -o libctest.so -shared -I/usr/lib/jvm/java-8-oracle/include ctest.c -lc
and have this errors, which i completely don't understand.
ctest.c: In function ‘Java_testcli_stdErr’:
ctest.c:19: error: parameter name omitted
ctest.c:19: error: parameter name omitted
ctest.c:22: error: ‘msg’ undeclared (first use in this function)
ctest.c:22: error: (Each undeclared identifier is reported only once
ctest.c:22: error: for each function it appears in.)
ctest.c: In function ‘Java_testcli_cliFromC’:
ctest.c:27: error: parameter name omitted
ctest.c:27: error: parameter name omitted
I'm figurin out that completely copy-pasting my working client.c into the ctest.c not work
well but i sincerely don't know how to fix it. One thing to know is that C code works alone, with obvious
void error(const char *msg)
before the first brace bracket and
int main(int argc, char *argv[])
before second one. If some1 can help it's really really appreciated. Thx very much for the effort!!
Cheers
JNIEXPORT void JNICALL Java_testcli_stdErr
(JNIEnv *, jobject)
{
perror(msg);
exit(1);
}
The first thing wrong here is that your parameters don't have names. While this can be effectively ignored with the proper compiler flags, I wouldn't recommend it. You should give your parameters names, e.g.:
JNIEXPORT void JNICALL Java_testcli_stdErr
(JNIEnv* env, jobject obj)
...
The next issue is perror(msg);, as msg isn't declared nor defined. Did you forget to pass it into your function? Is it supposed to be a global variable? Either way, it doesn't exist, and you can't print something that doesn't exist.
I'm running a basic Java wrapper for a C++ BSD socket client. I can compile the Java and generate a header file, but when I try to run it, it returns Exception in thread "main" java.lang.UnsatisfiedLinkError: JavaClient.socketComm()V
From what I've been able to find, it seems like this is indicative of a mismatch between method signatures, but I can't find anything wrong with mine.
Java Code
public class JavaClient
{
public native void socketComm();
public static void main(String[] args)
{
System.load("/home/cougar/workspace/ArbiterBSDSocketComms/JNIClient/JavaClient.so");
JavaClient client = new JavaClient();
client.socketComm();
System.out.println("Done");
}
}
C Implementation
#include <iostream>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <cstdlib>
#include <stdio.h>
#include <jni.h>
#include "JavaClient.h"
#define MAXHOSTNAME 256
JNIEXPORT void JNICALL Java_JavaClient_socketComm
(JNIEnv *env, jobject obj) {
struct sockaddr_in remoteSocketInfo;
struct hostent *hPtr;
int socketHandle;
char *remoteHost="localhost";
int portNumber = 8080;
memset(&remoteSocketInfo, 0, sizeof(struct sockaddr_in)); //Clear structure memory
if ((hPtr = gethostbyname(remoteHost)) == NULL) //Get sysinfo
{
printf("System DNS resolution misconfigured.");
printf("Error number: ", ECONNREFUSED);
exit(EXIT_FAILURE);
}
if((socketHandle = socket(AF_INET, SOCK_STREAM, 0)) < 0) //Create socket
{
close(socketHandle);
exit(EXIT_FAILURE);
}
memcpy((char *)&remoteSocketInfo.sin_addr,
hPtr->h_addr, hPtr->h_length); //Load sys info into sock data structures
remoteSocketInfo.sin_family = AF_INET;
remoteSocketInfo.sin_port = htons((u_short)portNumber); //Set port number
if(connect(socketHandle, (struct sockaddr *)&remoteSocketInfo, sizeof(struct sockaddr_in)) < 0)
{
close(socketHandle);
exit(EXIT_FAILURE);
}
int rc=0;
char buf[512];
strcpy(buf, "Sup server");
send(socketHandle, buf, strlen(buf)+1, 0);
}
void main(){}
Header File
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JavaClient */
#ifndef _Included_JavaClient
#define _Included_JavaClient
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: JavaClient
* Method: socketComm
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_JavaClient_socketComm
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
Excuse some of the bad formatting, I haven't used stackoverflow much and the code formatting is a bit sketchy.
These files all reside in /JNIClient.
I'm running Ubuntu 12.04 x64, and I have both 32- and 64-bit JDKs installed. I tried generating the .so with the 32-bit verison first, which would have been ideal, but I got an ELF mismatch, so I just went with the 64-bit so I wouldn't have to deal with that. (Any insight on that is welcome as well.)
My process is:
$>javac JavaClient.java
$>javah JavaClient
$>cc -m64 -g -I/usr/lib/jvm/java-6-openjdk-amd64/include -I/usr/lib/jvm/java-6-openjdk-amd64/include/linux -shared JavaClient.c -o JavaClient.so
$>java JavaClient
The full error message is
Exception in thread "main" java.lang.UnsatisfiedLinkError: JavaClient.socketComm()V
at JavaClient.socketComm(Native Method)
at JavaClient.main(JavaClient.java:9)
$>nm JavaClient.so returns:
cougar#Wanda:~/workspace/ArbiterBSDSocketComms/JNIClient$ nm JavaClient.so
0000000000200e50 a _DYNAMIC
0000000000200fe8 a _GLOBAL_OFFSET_TABLE_
w _Jv_RegisterClasses
0000000000200e30 d __CTOR_END__
0000000000200e28 d __CTOR_LIST__
0000000000200e40 d __DTOR_END__
0000000000200e38 d __DTOR_LIST__
00000000000005e0 r __FRAME_END__
0000000000200e48 d __JCR_END__
0000000000200e48 d __JCR_LIST__
0000000000201010 A __bss_start
w __cxa_finalize##GLIBC_2.2.5
0000000000000540 t __do_global_ctors_aux
0000000000000490 t __do_global_dtors_aux
0000000000201008 d __dso_handle
w __gmon_start__
0000000000201010 A _edata
0000000000201020 A _end
0000000000000578 T _fini
0000000000000438 T _init
0000000000000470 t call_gmon_start
0000000000201010 b completed.6531
0000000000201018 b dtor_idx.6533
0000000000000510 t frame_dummy
Edit: I have a theory that the .so is being built improperly, as $>nm JavaClient.so doesn't show the method names in it. Any suggestions on what's wrong about that cc command?
Okay, SO: I kept at this because nothing seemed right. The method signatures were all matched, nothing should be wrong, eclipse file properties said it was editing the right file, etc etc. I finally catted the JavaClient.c, and it was blank. Apparently eclipse wasn't ACTUALLY editing the file it said it was. Fixed that up and now everything's fine.
I will give you a far better solution.
public void socketComm() throws IOException
{
Socket socket = new Socket("localhost", 8080);
try
{
socket.getOutputStream().write("Sup server\u0000".getBytes());
}
finally
{
socket.close(); // You forgot this
}
}
No JNI required at all. It also doesn't close an invalid handle if socket() returns < 0, unlike your code.
I kept at this because nothing seemed right. The method signatures were all matched, nothing should be wrong, eclipse file properties said it was editing the right file, etc etc. I finally catted the JavaClient.c, and it was blank. Apparently eclipse wasn't ACTUALLY editing the file it said it was. Fixed that up and now everything's fine.
Not sure why Eclipse claimed to be editing a blank file, I checked and rechecked and it wasn't referencing any links or anything, but if you're having the same problem as me check it out.