How to properly reuse a JNI JVM in C++? - java

I have a C++ class that uses a JNI JVM to run a Java method. For whatever reason my program is working for 3 iterations and on the 3rd loop the JVM crashes with a SIGSEGV.
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f2af5de1c81, pid=7669, tid=139822523557696
#
# JRE version: Java(TM) SE Runtime Environment (7.0_45-b18) (build 1.7.0_45-b18)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (24.45-b08 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C [libc.so.6+0x7ac81]
This code is not complete at all.
#include <string>
#include <thread>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include "imgsearch.h"
#define PORT "8675"
#define BACKLOG 10
JNIEnv* create_vm() {
JavaVM* j;
JNIEnv* e;
JavaVMInitArgs j_args;
JavaVMOption opts;
j_args.version = JNI_VERSION_1_6;
j_args.nOptions = 1;
j_args.ignoreUnrecognized = 0;
char* cp = (char *)"-Djava.class.path=.:./lucene-4.4.0/analysis/common/lucene-analyzers-common-4.4.0.jar:./lucene-4.4.0/core/lucene-core-4.4.0.jar:./lucene-4.4.0/queryparser/lucene-queryparser-4.4.0.jar";
opts.optionString = cp;
j_args.options = &opts;
JNI_CreateJavaVM(&j, (void**)&e, &j_args);
return e;
}
JNIEnv* env = create_vm();
JavaVM* jvm;
void sigchld_handler(int s)
{
while(waitpid(-1, NULL, WNOHANG) > 0);
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
void sockcom(int csock) {
std::cout << "Yeah!" << std::endl;
}
int main(int argc, char *argv[]) {
env->GetJavaVM(&jvm);
std::string fP = "features/esp.feature";
ImgSearch *iS;
iS = new ImgSearch();
iS->LoadFeatures(fP);
//iS->BuildClusters(150000, 15);
//iS->ClustersToFile("output.clusters");
iS->FileToClusts("output.clusters");
iS->BuildIndex();
//iS->IndexToFile("output.index");
//iS->FileToIndex("output.index");
//iS->FindNeighbors();
//iS->NeighborsToFile("output.neighbors");
iS->FileToNeighbors("output.neighbors");
iS->BagOfWords("features/imglist.txt", "features/esp.size", "coll/output.bagofwords");
iS->BuildLuceneIndex("coll/output.bagofwords");
//std::string queryfile = "queries/query1.pgm";
int sockfd, new_fd; // listen on sock_fd, new connection on new_fd
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; // connector's address information
socklen_t sin_size;
struct sigaction sa;
int yes=1;
char s[INET6_ADDRSTRLEN];
int rv;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("server: socket");
continue;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("server: bind");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "server: failed to bind\n");
return 2;
}
freeaddrinfo(servinfo); // all done with this structure
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) { perror("sigaction"); exit(1); }
printf("server: waiting for connections...\n");
while(1) { // main accept() loop
int pipefd[2];
int pres = pipe(pipefd);
if (pres < 0) {
perror("pipe");
continue;
}
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr *)&their_addr), s, sizeof s);
printf("server: got connection from %s\n", s);
std::thread th(sockcom, new_fd);
th.detach();
std::string queryfile = "queries/query3.pgm";
iS->Search(queryfile);
}
jvm->DestroyJavaVM();
return 0;
}
So iS->Search(queryfile); basically is the following:
void ImgSearch::Search(std::string &filePath) {
ImgQuery newQuery(filePath, Ndx, WORDS);
newQuery.ExtractKeyPoints();
newQuery.FindNeighbors();
newQuery.BagOfWords();
newQuery.LuceneSearch();
return;
// Error Checking?
}
Where the LuceneSearch function is the only one that uses the JNI JVM.
void ImgQuery::LuceneSearch() {
jclass qcls = env->FindClass("BatchSearch");
if (qcls == NULL) std::cout << "BatchSearch: Not Found." << std::endl;
jmethodID qmid = env->GetStaticMethodID(qcls, "main", "()V");
env->CallStaticVoidMethod(qcls, qmid);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
}
std::cout << "Still working..." << std::endl;
return;
// Error Checking?
}
Basically, what I am wondering is A) do you see anything obviously wrong? and B) How do you properly reuse a JVM throughout a project?
EDIT: Is there a way to wait for a JVM to be ready?

Related

A dynamic link library (DLL) initialization routine failed (Windows 10 / Toast Notifications)

The DLL I made throws this error every time I try and load it in JNI. I narrowed the problem down to the main file, something in there is causing this. I'm not sure if it's because the toast notifications, couldn't find anything about that.
#include "stdafx.h"
#include <iostream>
#include <string>
#include "wintoast\wintoastlib.h"
#include "jni\me_glorantq_aboe_chat_client_notification_WindowsToastNotifier.h"
#include "ToastHandler.h"
std::wstring toastLogoPath = nullptr;
std::wstring jniToWstring(JNIEnv* env, jstring& jString) {
jboolean isCopy = true;
const char* chars = env->GetStringUTFChars(jString, &isCopy);
std::string str = std::string(chars);
std::wstring wstr(str.length(), L' ');
std::copy(str.begin(), str.end(), wstr.begin());
return wstr;
}
JNIEXPORT jboolean JNICALL Java_me_glorantq_aboe_chat_client_notification_WindowsToastNotifier_initialise(JNIEnv* env, jobject object, jstring logoPath) {
if (!WinToastLib::WinToast::instance()->isCompatible()) {
std::cerr << "WinToast is not compatible with this system!" << std::endl;
return false;
}
WinToastLib::WinToast::instance()->setAppName(L"A Bit of Everything");
std::wstring aumi = WinToastLib::WinToast::instance()->configureAUMI(L"me.glorantq", L"aboe", L"chat", L"win10");
WinToastLib::WinToast::instance()->setAppUserModelId(aumi);
if (!WinToastLib::WinToast::instance()->initialize()) {
std::cerr << "Failed to initialise WinToast!" << std::endl;
return false;
}
else {
std::cout << "Initialised WinToast!" << std::endl;
}
toastLogoPath = jniToWstring(env, logoPath);
std::cout << "Set logo path to: " << toastLogoPath.c_str() << std::endl;
return true;
}
JNIEXPORT void JNICALL Java_me_glorantq_aboe_chat_client_notification_WindowsToastNotifier_showNotificationNative(JNIEnv* env, jobject object, jstring header, jstring message) {
ToastHandler* handler = new ToastHandler;
WinToastLib::WinToastTemplate toastTemplate = WinToastLib::WinToastTemplate(WinToastLib::WinToastTemplate::ImageAndText02);
toastTemplate.setImagePath(toastLogoPath);
toastTemplate.setTextField(jniToWstring(env, header), WinToastLib::WinToastTemplate::FirstLine);
toastTemplate.setTextField(jniToWstring(env, message), WinToastLib::WinToastTemplate::SecondLine);
if (!WinToastLib::WinToast::instance()->showToast(toastTemplate, handler)) {
std::cerr << "Failed to show toast!" << std::endl;
}
}
When I remove everything from this file, everything works just fine, apart from the missing implementations of course.

Embed java code from a C++ library without needing top-level program to embed it?

I'm using QtCreator to deploy C++/Java applications on Android. But I think my problem may not be specific to the way QtCreator deploys the app.
I want to create a C++ library providing a specific functionnality. To do so, the library needs to instantiate a Java class, this last one will be used to do some SDK functions class (for stuff that are not available in the NDK/C++ API).
Creating and using java objects from a C++ program works fine. I package the .java file to the application environment during compilation/deployment and then I can use the Java class via two approachs:
Declare JNI_OnLoad, load class id, method id, and later call them using jni
Use Qt QAndroidJniObject objects (this is specific to QtCreator)
Now the problem comes when I want to create and use java objects from a C++ library. It only works if the .java file is packaged with the top-level application. I could not find a way to package the java with and only with the library itself. Meaning that anyone why needs to use my library will not only have to simply link with the library, but will also need to package the .java file(s) needed by my library. This breaks encapsulation and gives a hard time to the end developer writing programs and simply wanting to load a library and expecting it to embed all it needs to work on its own...
My question is: How can the library embed the java file, so that this java file does not need to be part of the top level program package to let the library use it?
Here is a quick sample: MainWindow constrctor calls 4 functions themselves trying to create and use Java objects. Only the first two calls work...
main.cpp:
#include <QApplication>
#include <QMainWindow>
#include "MyLib.h"
#include <QtAndroidExtras/QAndroidJniObject>
#include "jni.h"
#include <assert.h>
// load java classes from main program
JavaVM* s_javaVM = NULL;
jclass s_classID = 0;
jmethodID s_ctorMethodID = 0;
jmethodID s_callmethodID = 0;
bool loadJava( JNIEnv *env )
{
jclass clazz = env->FindClass("my/FooPrg");
if (!clazz)
{
qCritical("Can't find FooPrg class");
return false;
}
// keep a global reference to it
s_classID = (jclass)env->NewGlobalRef(clazz);
// search for its contructor
s_ctorMethodID = env->GetMethodID(s_classID, "<init>", "()V");
if (!s_ctorMethodID )
{
qCritical("Can't find class contructor");
return false;
}
// search for a method
s_callmethodID = env->GetMethodID(s_classID, "Mult", "(I)I");
if (!s_callmethodID )
{
qCritical("Can't find Mult method");
return false;
}
return true;
}
jint JNICALL JNI_OnLoad(JavaVM *vm, void *)
{
s_javaVM = vm;
JNIEnv* env = NULL;
if (s_javaVM->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_4) != JNI_OK)
return -1;
loadJava( env );
return JNI_VERSION_1_4;
}
void callJavaFunctionFromPrgWithQt()
{
if ( QAndroidJniObject::isClassAvailable("my/FooPrg") )
{
QAndroidJniObject obj("my/FooPrg","()V");
if ( obj.isValid() )
{
jint res = obj.callMethod<jint>("Mult", "(I)I", 0x0002);
assert( res == 4 );
}
else
{
assert( false );
}
}
else
{
assert( false );
}
}
void callJavaFunctionFromPrgWithJniLoad()
{
if ( s_classID != 0 && s_ctorMethodID != 0 && s_callmethodID != 0 )
{
JNIEnv* env = NULL;
if (s_javaVM->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_4) != JNI_OK)
assert(false);
jobject j_object = env->NewGlobalRef( env->NewObject(s_classID, s_ctorMethodID ) );
jint res = env->CallIntMethod(j_object, s_callmethodID, 0x0002 );
assert( res == 4 );
}
else
{
assert( false );
}
}
class MainWindow : public QMainWindow
{
public:
MainWindow()
{
callJavaFunctionFromPrgWithQt(); // works
callJavaFunctionFromPrgWithJniLoad(); // works
callJavaFunctionFromLibWithQt(); // fails, assert
callJavaFunctionFromLibWithJniLoad(); // fails, because libraries JNI_OnLoad can't find FooLib.java!
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
MyLib.h:
#pragma once
void callJavaFunctionFromLibWithQt();
void callJavaFunctionFromLibWithJniLoad();
MyLib.cpp:
#include "MyLib.h"
#include <QtAndroidExtras/QAndroidJniObject>
#include "jni.h"
#include <assert.h>
// load java classes from main program
JavaVM* s_javaVM = NULL;
jclass s_classID = 0;
jmethodID s_ctorMethodID = 0;
jmethodID s_callmethodID = 0;
bool loadJava( JNIEnv *env )
{
jclass clazz = env->FindClass("my/FooLib");
if (!clazz)
{
qDebug("Can't find FooLib class");
return false;
}
// keep a global reference to it
s_classID = (jclass)env->NewGlobalRef(clazz);
// search for its contructor
s_ctorMethodID = env->GetMethodID(s_classID, "<init>", "()V");
if (!s_ctorMethodID )
{
qDebug("Can't find class contructor");
return false;
}
// search for a method
s_callmethodID = env->GetMethodID(s_classID, "Mult", "(I)I");
if (!s_callmethodID )
{
qDebug("Can't find Mult method");
return false;
}
return true;
}
jint JNICALL JNI_OnLoad(JavaVM *vm, void *)
{
s_javaVM = vm;
JNIEnv* env = NULL;
if (s_javaVM->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_4) != JNI_OK)
return -1;
// uncommenting this makes the application crash upon load....
//loadJava( env );
return JNI_VERSION_1_4;
}
void callJavaFunctionFromLibWithQt()
{
if ( QAndroidJniObject::isClassAvailable("my/FooLib") )
{
QAndroidJniObject obj("my/FooLib","()V");
if ( obj.isValid() )
{
jint res = obj.callMethod<jint>("Mult", "(I)I", 0x0002);
assert( res == 4 );
}
else
{
assert( false );
}
}
else
{
assert( false ); // this assertion is reached!
}
}
void callJavaFunctionFromLibWithJniLoad()
{
if ( s_classID != 0 && s_ctorMethodID != 0 && s_callmethodID != 0 )
{
JNIEnv* env = NULL;
if (s_javaVM->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_4) != JNI_OK)
assert(false);
jobject j_object = env->NewGlobalRef( env->NewObject(s_classID, s_ctorMethodID ) );
jint res = env->CallIntMethod(j_object, s_callmethodID, 0x0002 );
assert( res == 4 );
}
else
{
assert( false ); // this assertion is reached!
}
}
FooPrg.java:
package my;
import java.lang.Integer;
public class FooPrg
{
public FooPrg()
{
}
public int Mult(int val)
{
return val * 2;
}
}
FooLib.java:
package my;
import java.lang.Integer;
public class FooLib
{
public FooLib()
{
}
public int Mult(int val)
{
return val * 2;
}
}
jniload.pro:
TARGET = jniload
CONFIG += qt resources
QT += core gui widgets
android: QT += androidextras
SOURCES += src/main.cpp
TEMPLATE = app
INCLUDEPATH += ifc
LIBS += \
-l$$OUT_PWD/../../lib/jniload_lib/libjniload_lib.so
ANDROID_EXTRA_LIBS += \
$$OUT_PWD/../../lib/jniload_lib/libjniload_lib.so
ANDROID_PACKAGE_SOURCE_DIR = data/android/root
OTHER_FILES += data/android/root/src/my/FooPrg.java
jniload_lib.pro:
TARGET = jniload_lib
CONFIG += qt resources
QT += core gui widgets
android: QT += androidextras
SOURCES += src/MyLib.cpp
HEADERS += ifc/MyLib.h
TEMPLATE = lib
INCLUDEPATH += ifc
# This does has apparently no effect on library
ANDROID_PACKAGE_SOURCE_DIR = data/android/root
OTHER_FILES += data/android/root/src/my/FooLib.java
Finaly got a way to work this out.
I removed ANDROID_PACKAGE_SOURCE_DIR line from jniload.pro file and hanlde manual copy of the .java files through custom build steps:
custom_jniload_lib_step.target = jniload_lib_mockup.h
custom_jniload_lib_step.commands = $(COPY_DIR) data\android\root ..\..\android-build
QMAKE_EXTRA_TARGETS += custom_jniload_lib_step
PRE_TARGETDEPS += jniload_lib_mockup.h
custom_jniload_step.target = jniload_mockup.h
custom_jniload_step.commands = $(COPY_DIR) data\android\root ..\..\android-build
QMAKE_EXTRA_TARGETS += custom_jniload_step
PRE_TARGETDEPS += jniload_mockup.h
Then, upon deployment, android-build/src contains both FooLib.java and FooPrg.java and then both library and program can access them!

call linux socket function sendto:error,operation not permitted

Environment:
PC sys:windows xp
jdk:1.6
ndk:android-ndk-r9b
compile env:MinGW
Descrpiton:
I'm developing a sip endpoint app, which is based on the opensource sip stack "doubango", in Android device. The socket functions are called using NDK but not directly JAVA. When normally use, it's OK. Then clean the device's memory using some software, or stop Service manully, and make it exit abnormally. Seems that it stops without call function close(socket). Next time when I use, it will throw error calling socket function :sendto(),the errno=1 which means "operation not permitted".
I've added "uses-permission android:name="android.permission.INTERNET""
Does anyone can give me a hand?
PS:I test in devices without ROOT permission, and this issue will happen. But I test a device with ROOT permission, it doesn't happen. Does it matter?
Job Is Done. There are sth mistakes i made in the Java layer. Some parameters i set in Sip stack are wrong.
Here follows the code segment:
int tnet_sockfd_sendto(tnet_fd_t fd, const struct sockaddr *to, const void* buf, tsk_size_t size)
{
tsk_size_t sent = 0;
int ret = -1;
if(fd == TNET_INVALID_FD){
TSK_DEBUG_ERROR("Using invalid FD to send data.");
goto bail;
}
if(!buf || !size){
TSK_DEBUG_ERROR("Using invalid BUFFER.");
ret = -2;
goto bail;
}
while(sent < size){
int try_guard = 10;
#if TNET_UNDER_WINDOWS
WSABUF wsaBuffer;
DWORD numberOfBytesSent = 0;
wsaBuffer.buf = ((CHAR*)buf) + sent;
wsaBuffer.len = (size - sent);
try_again:
ret = WSASendTo(fd, &wsaBuffer, 1, &numberOfBytesSent, 0, to, tnet_get_sockaddr_size(to), 0, 0); // returns zero if succeed
if(ret == 0){
ret = numberOfBytesSent;
}
#else
try_again:
ret = sendto(fd, (((const uint8_t*)buf)+sent), (size-sent), 0, to, tnet_get_sockaddr_size(to)); // returns number of sent bytes if succeed
#endif
if(ret <= 0){
if(tnet_geterrno() == TNET_ERROR_WOULDBLOCK){
TSK_DEBUG_INFO("SendUdp() - WouldBlock. Retrying...");
if(try_guard--){
tsk_thread_sleep(10);
goto try_again;
}
}
else{
***/* Just throw error here*/***
TSK_DEBUG_INFO("errno: %d",tnet_geterrno());
TNET_PRINT_LAST_ERROR("sendto() failed");
}
goto bail;
}
else{
sent += ret;
}
}
bail:
return (size == sent) ? sent : ret;
}
#define tnet_soccket(family, type, protocol) socket((family), (type), (protocol))
tnet_socket_t* tnet_socket_create_2(const char* host, tnet_port_t port_,tnet_socket_type_t type, tsk_bool_t nonblocking, tsk_bool_t bindsocket)
{
tnet_socket_t *sock;
if((sock = tsk_object_new(tnet_socket_def_t))){
int status;
tsk_istr_t port;
struct addrinfo *result = tsk_null;
struct addrinfo *ptr = tsk_null;
struct addrinfo hints;
tnet_host_t local_hostname;
sock->port = port_;
tsk_itoa(sock->port, &port);
sock->type = type;
memset(local_hostname, 0, sizeof(local_hostname));
/* Get the local host name */
if(host != TNET_SOCKET_HOST_ANY && !tsk_strempty(host)){
memcpy(local_hostname, host, tsk_strlen(host)>sizeof(local_hostname)-1 ? sizeof(local_hostname)-1 : tsk_strlen(host));
}
else{
if(TNET_SOCKET_TYPE_IS_IPV6(sock->type)){
memcpy(local_hostname, "::", 2);
}
else{
memcpy(local_hostname, "0.0.0.0", 7);
}
}
TSK_DEBUG_INFO("local_hostname: %s",local_hostname);
/* hints address info structure */
memset(&hints, 0, sizeof(hints));
hints.ai_family = TNET_SOCKET_TYPE_IS_IPV46(sock->type) ? AF_UNSPEC : (TNET_SOCKET_TYPE_IS_IPV6(sock->type) ? AF_INET6 : AF_INET);
hints.ai_socktype = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? SOCK_STREAM : SOCK_DGRAM;
hints.ai_protocol = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? IPPROTO_TCP : IPPROTO_UDP;
hints.ai_flags = AI_PASSIVE
#if !TNET_UNDER_WINDOWS || _WIN32_WINNT>=0x600
| AI_ADDRCONFIG
#endif
;
/* Performs getaddrinfo */
if((status = tnet_getaddrinfo(local_hostname, port, &hints, &result))){
TNET_PRINT_LAST_ERROR("tnet_getaddrinfo(family=%d, hostname=%s and port=%s) failed: [%s]",
hints.ai_family, local_hostname, port, tnet_gai_strerror(status));
goto bail;
}
/* Find our address. */
for(ptr = result; ptr; ptr = ptr->ai_next){
sock->fd = tnet_soccket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if(ptr->ai_family != AF_INET6 && ptr->ai_family != AF_INET){
continue;
}
/* To avoid "Address already in use" error
* Check issue 368 (https://code.google.com/p/doubango/issues/detail?id=368) to understand why it's not used for UDP/DTLS.
*/
//
if (TNET_SOCKET_TYPE_IS_STREAM(sock->type)) {
TSK_DEBUG_INFO("Socket Type: Stream");
if ((status = tnet_sockfd_reuseaddr(sock->fd, 1))) {
// do not break...continue
}
}
if(bindsocket){
/* Bind the socket */
if((status = bind(sock->fd, ptr->ai_addr, ptr->ai_addrlen))){
TNET_PRINT_LAST_ERROR("bind to [%s:%s]have failed", local_hostname, port);
tnet_socket_close(sock);
continue;
}
/* Get local IP string. */
if((status = tnet_get_ip_n_port(sock->fd , tsk_true/*local*/, &sock->ip, &sock->port))) /* % */
//if((status = tnet_getnameinfo(ptr->ai_addr, ptr->ai_addrlen, sock->ip, sizeof(sock->ip), 0, 0, NI_NUMERICHOST)))
{
TNET_PRINT_LAST_ERROR("Failed to get local IP and port.");
tnet_socket_close(sock);
continue;
}
}
/* sets the real socket type (if ipv46) */
if(ptr->ai_family == AF_INET6) {
TNET_SOCKET_TYPE_SET_IPV6Only(sock->type);
}
else{
TNET_SOCKET_TYPE_SET_IPV4Only(sock->type);
}
break;
}
/* Check socket validity. */
if(!TNET_SOCKET_IS_VALID(sock)) {
TNET_PRINT_LAST_ERROR("Invalid socket.");
goto bail;
}
#if TNET_UNDER_IPHONE || TNET_UNDER_IPHONE_SIMULATOR
/* disable SIGPIPE signal */
{
int yes = 1;
if(setsockopt(sock->fd, SOL_SOCKET, SO_NOSIGPIPE, (char*)&yes, sizeof(int))){
TNET_PRINT_LAST_ERROR("setsockopt(SO_NOSIGPIPE) have failed.");
}
}
#endif /* TNET_UNDER_IPHONE */
/* Sets the socket to nonblocking mode */
if(nonblocking){
if((status = tnet_sockfd_set_nonblocking(sock->fd))){
goto bail;
}
}
bail:
/* Free addrinfo */
tnet_freeaddrinfo(result);
/* Close socket if failed. */
if(status){
if(TNET_SOCKET_IS_VALID(sock)){
tnet_socket_close(sock);
}
return tsk_null;
}
}
return sock;
}
int tnet_sockfd_reuseaddr(tnet_fd_t fd, int reuseAddr)
{
if (fd != TNET_INVALID_FD) {
int ret;
#if defined(SOLARIS)
static const char yes = '1';
static const char no = '0';
#else
static const int yes = 1;
static const int no = 0;
#endif
if ((ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char*)(reuseAddr ? &yes : &no), sizeof(int)))) {
TNET_PRINT_LAST_ERROR("setsockopt(SO_REUSEADDR, fd=%d) have failed", fd);
return ret;
}
// #if defined(SO_REUSEPORT)
if ((ret = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char*)(reuseAddr ? &yes : &no), sizeof(int)))) {
TNET_PRINT_LAST_ERROR("setsockopt(SO_REUSEPORT, fd=%d) have failed", fd);
return ret;
}
// #endif
return 0;
}
return -1;
}
#define tnet_sockfd_set_nonblocking(fd) tnet_sockfd_set_mode(fd, 1)
int tnet_sockfd_set_mode(tnet_fd_t fd, int nonBlocking)
{
if(fd != TNET_INVALID_FD)
{
#if TNET_UNDER_WINDOWS
ULONG mode = nonBlocking;
if(ioctlsocket(fd, FIONBIO, &mode))
//if(WSAIoctl(fd, FIONBIO, &nonblocking, sizeof(nonblocking), NULL, 0, NULL, NULL, NULL) == SOCKET_ERROR)
{
TNET_PRINT_LAST_ERROR("ioctlsocket(FIONBIO) have failed.");
return -1;
}
#else
int flags;
if((flags = fcntl(fd, F_GETFL, 0)) < 0) {
TNET_PRINT_LAST_ERROR("fcntl(F_GETFL) have failed.");
return -1;
}
if(fcntl(fd, F_SETFL, flags | (nonBlocking ? O_NONBLOCK : ~O_NONBLOCK)) < 0){
TNET_PRINT_LAST_ERROR("fcntl(O_NONBLOCK/O_NONBLOCK) have failed.");
return -1;
}
#endif
// int on = 1;
// ioctl(fd, FIONBIO, (char *)&on);
}
return 0;
}

UDP connection between C server and Java client

I have another question :) I have a simple UDP server in C that reads some bytes applies some decode to those bytes and when it has a STRING of the form ################ he sends it throug UDP to another server in C. Here is the code for my C server that is called preprocesamiento.c Im posting the whole thing cos is easyer but maybe this has nothing to do with my problem.
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <stdint.h>
#include <string.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#define MAXBUF 512
#define SENDING 0x52
#define RESIVING 0xB4
#define TYPE 0xA3F0
int createSocket();
char *unbase64(unsigned char *input, int length);
/* This function recives bytes(ASCII numbers) and returns the char */
void cambiarAChars(char* bytes, char* result)
{
unsigned int ch;
char a[4];
char buff[50];
strcpy(result,"");
int i=0;
while(i<strlen(bytes))
{
if(bytes[i]=='1')
{
a[0]=bytes[i];
a[1]=bytes[i+1];
a[2]=bytes[i+2];
a[3]='\0';
i=i+3;
}
else
{
a[0]=bytes[i];
a[1]=bytes[i+1];
a[2]='\0';
i=i+2;
}
ch = atoi(a);
sprintf(buff,"%c",ch);
strcat(result,buff);
}
}
/*this is the message that is going to be sent to the other server*/
char msg[MAXBUF];
/*this is the bytes recived*/
char bytes[MAXBUF];
void loadConfig(struct sockaddr_in *udpServer,struct sockaddr_in *thisServer,unsigned char *file);
int sendDataToServerXX(struct sockaddr_in *udpServer, int udpSocket);
int *useStdrr;
int *maxRequests;
int returnStatus;
int main(int argc, char* argv[])
{
if (argc < 2)
{
fprintf(stderr, "Usage: %s <file.config adress>\n", argv[0]);
exit(1);
}
useStdrr=malloc(sizeof(int));
maxRequests=malloc(sizeof(int));
struct sockaddr_in udpServer,thisServer,udpClient;
loadConfig(&udpServer,&thisServer, argv[1]);
int thisServerSocket = createSocket();
int udpSocket=createSocket();
int addrlen;
printf("Listening on.. %d \n",thisServer.sin_port);
thisServer.sin_family = AF_INET;
returnStatus = bind(thisServerSocket, (struct sockaddr*)&thisServer, sizeof(thisServer));
if (returnStatus == 0) {
fprintf(stderr, "Bind completed!\n");
}
else {
fprintf(stderr, "Could not bind to address \n" );
close(thisServerSocket);
exit(1);
}
/*En este while infinito estamos esperando los datos de las tramas*/
while (1)
{
addrlen = sizeof(udpClient);
/* How to resive a struct? */
returnStatus = recvfrom(thisServerSocket,(char*)&bytes, sizeof(bytes), 0,
(struct sockaddr*)&udpClient, &addrlen);
if (returnStatus == -1) {
fprintf(stderr, "Could not receive message!\n");
}
else {
printf("Lo que llego: %s \n",bytes);
/*Primero quitamos el 0 y 1 y guardamos el nuevo arreglo en p*/
bytes[strlen(bytes)-1]='\0';
char p[strlen(bytes)];
int i=0;
while(bytes[i+1]!='\0'){
p[i]=bytes[i+1];
i++;
}
/*esto simula la cambiada a base10 de base64*/
char *result=malloc(512);
char *p2=malloc(sizeof(p)+1);
strcpy(p2,p);
cambiarAChars(p2,result);
strcat(result,"\n\0");
printf("TAMANO: %d \n",strlen(result));
char *output = unbase64(result, strlen(result));
printf("Unbase64: %s\n", output);
msg[0]='%';
strcat(msg,output);
int f=strlen(msg);
msg[f]='%';
msg[f+1]='\0';
printf("Voy a mandar: %s \n",msg);
sendDataToServerXX(&udpServer,udpSocket);
free(output);
}
}
close(thisServerSocket);
close(udpSocket);
}
int createSocket()
{
/* create a socket */
int Socket;
Socket = socket(AF_INET, SOCK_DGRAM, 0);
if (Socket == -1)
{
if(*useStdrr)
{
fprintf(stderr, "Could not create a socket!\n");
}
exit(1);
}
else {
printf("Socket created.\n");
}
return Socket;
}
void loadConfig(struct sockaddr_in *udpServer,struct sockaddr_in *thisServer, unsigned char *file)
{
char line[256];
int linenum=0;
FILE* f = fopen(file, "r");
while(fgets(line, 256, f) != NULL)
{
char atribute[256], value[256];
linenum++;
if(line[0] == '#'||line[0] == ' ') {
continue;
}
else{
if(sscanf(line, "%s %s", atribute, value) != 2)
{
fprintf(stderr, "Syntax error, line %d\n", linenum);
continue;
}
if(!strcmp(atribute,"server_address" ))
{
if(!strcmp(value,""))
{
udpServer->sin_addr.s_addr = htonl(INADDR_ANY);
}
else{
udpServer->sin_addr.s_addr = inet_addr(value);
}
}
else if(!strcmp(atribute,"server_port"))
{
udpServer->sin_port = htons(atoi(value));
}
else if(!strcmp(atribute,"print_message_details"))
{
if(!strcmp(value,"ON"))
{
*useStdrr=1;
}
else
{
*useStdrr=0;
}
}
else if(!strcmp(atribute,"request_count"))
{
*maxRequests=5;
}
else if(!strcmp(atribute,"valor_que_viene_del_cohete_simulado"))
{
}
else if(!strcmp(atribute,"this_server_address"))
{
if(!strcmp(value,""))
{
thisServer->sin_addr.s_addr = htonl(INADDR_ANY);
}
else{
thisServer->sin_addr.s_addr = inet_addr(value);
}
}
else if(!strcmp(atribute,"this_server_port"))
{
thisServer->sin_port = htons(atoi(value));
}
}
}
}
int sendDataToServerXX(struct sockaddr_in *udpServer, int udpSocket)
{
udpServer->sin_family = AF_INET;
int in=0;
int boolv=0;
while(in<*maxRequests)
{
in++;
returnStatus = sendto(udpSocket,(char*) &msg, sizeof(msg), 0,
(struct sockaddr*)udpServer, sizeof(*udpServer));
if (returnStatus == -1) {
if(*useStdrr)
{
fprintf(stderr, "Could not send message!\n");
}
}
else {
printf("Datos enviados al servidor xx.\n");
memset(msg, 0, strlen(msg));
in=*maxRequests;
boolv=1;
}
}
if(!boolv)
{
if(*useStdrr)
{
fprintf(stderr, "fixed number of requests finished.. no reply.\n");
}
}
return 0;
}
char *unbase64(unsigned char *input, int length)
{
BIO *b64, *bmem;
char *buffer = (char *)malloc(length);
memset(buffer, 0, length);
b64 = BIO_new(BIO_f_base64());
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
bmem = BIO_new_mem_buf(input, length);
bmem = BIO_push(b64, bmem);
BIO_read(bmem, buffer, length);
BIO_free_all(bmem);
return buffer;
}
Ok so i made a simulator that sends data to this server... basically a UDP client that sends bytes as i want them. And the connection and the whole thing works very nice :). Now im trying to connect to the real tester, which is a java jar that sends data as my server wants it through UDP. The only problem is that i dont have the java source code, because its not mine... But the program seems to run smoothly (the java jar) But when i check my server no connections where recived. And yeah im waiting in the right port and both programs the C and Java are running in the same machine (UBUNTU).
I post my client simulator made in C that works very nice with this server.
Sorry its a bit long cos i load from a config file:
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define MAXBUF 1024
#define SENDING 0x52
#define RESIVING 0xB4
#define TYPE 0xA3F0
int createSocket();
char msg[MAXBUF];
void loadConfig(struct sockaddr_in *udpServer, char *file);
int *useStdrr;
int *maxRequests;
int *timeOut;
int main(int argc, char* argv[])
{
int returnStatus;
int addrlen;
struct sockaddr_in udpClient, udpServer;
char buf[MAXBUF];
useStdrr=malloc(sizeof(int));
maxRequests=malloc(sizeof(int));
timeOut=malloc(sizeof(int));
/*ms.timezone="AES";*/
if (argc < 2)
{
fprintf(stderr, "Usage: %s <file.config adress>\n", argv[0]);
exit(1);
}
int udpSocket=createSocket();
udpServer.sin_family = AF_INET;
loadConfig(&udpServer, argv[1]);
/*how to send a struct here?*/
int in=0;
int boolv=0;
printf("Request number %i\n",*maxRequests);
while(in<*maxRequests)
{
in++;
printf("Request number %i\n",in);
printf("Adresss::: %d\n",udpServer.sin_addr.s_addr);
printf("PORT:::: %i\n",udpServer.sin_port);
returnStatus = sendto(udpSocket,(char*) &msg, sizeof(msg), 0,
(struct sockaddr*)&udpServer, sizeof(udpServer));
if (returnStatus == -1) {
if(*useStdrr)
{
fprintf(stderr, "Could not send message!\n");
}
}
else {
printf("Message sent.\n");
/* message sent: look for confirmation */
/*
addrlen = sizeof(udpServer);
returnStatus = recvfrom(udpSocket, (char*) &msg, sizeof(msg), 0,
(struct sockaddr*)&udpServer, &addrlen);
if (returnStatus == -1) {
if(*useStdrr)
{
fprintf(stderr, "Did not receive confirmation!\n");
}
}
else {
printf("Second: %s\n", msg);
*/
in=*maxRequests;
boolv=1;
/*
}*/
}
}
if(!boolv)
{
if(*useStdrr)
{
fprintf(stderr, "fixed number of requests finished.. no reply.\n");
}
}
close(udpSocket);
return 0;
}
int createSocket()
{
/* create a socket */
int Socket;
Socket = socket(AF_INET, SOCK_DGRAM, 0);
if (Socket == -1)
{
if(*useStdrr)
{
fprintf(stderr, "Could not create a socket!\n");
}
exit(1);
}
else {
printf("Socket created.\n");
}
return Socket;
}
void loadConfig(struct sockaddr_in *udpServer, char *file)
{
char line[256];
int linenum=0;
FILE* f = fopen(file, "r");
while(fgets(line, 256, f) != NULL)
{
char atribute[256], value[256];
linenum++;
if(line[0] == '#'||line[0] == ' ') {
continue;
}
else{
if(sscanf(line, "%s %s", atribute, value) != 2)
{
fprintf(stderr, "Syntax error, line %d\n", linenum);
continue;
}
printf("Atribute: %s\n",atribute);
printf("Value: %s\n",value);
if(!strcmp(atribute,"server_address" ))
{
if(!strcmp(value,""))
{
udpServer->sin_addr.s_addr = htonl(INADDR_ANY);
}
else{
udpServer->sin_addr.s_addr = inet_addr(value);
}
}
else if(!strcmp(atribute,"server_port"))
{
udpServer->sin_port = htons(atoi(value));
}
else if(!strcmp(atribute,"print_message_details"))
{
if(!strcmp(value,"ON"))
{
*useStdrr=1;
}
else
{
*useStdrr=0;
}
}
else if(!strcmp(atribute,"request_count"))
{
*maxRequests=atoi(value);
}
else if(!strcmp(atribute,"request_*timeOut"))
{
*timeOut=atoi(value);
}
}
}
}
Now the real QUESTION: Do i have to do something different to connect froma java client to a C from the C server than what i do to connect to another C client? If the answer is no then the problem is in the java project? they tell me its working fine but I think they have tested it with a JAVA server.. Is there any diference? If the problem is in the java project what should i tell them to change for it to work with my C server?
Many thx !!!
Alejandro Casas
There is no such thing as a UDP connection. In UDP, a program just tosses packets at a given port at a given IP. If there is nothing listening at that IP/port, or the receiving program decides to ignore the UDP packets, it gets dropped. If you want an actual connection, you would use TCP.
In addition, some ISP block some types of UDP packets by default
In Java, a TCP socket is called a Socket and a UDP socket is called a DatagramSocket. Make sure you are sending from a DatagramSocket on your Java client.
I haven't done socket programming in C though.
Finally, it would help if you posted some of your Java code.
This is a great example on how to start developing a Java client/server.
Notice it comes from "Computer Networking: A Top Down Approach", by Kurose and Ross
The book has both UDP/TCP examples in JAVA, which are great and I recommend you.
The UDP server/client:
http://systembash.com/content/a-simple-java-udp-server-and-udp-client/
The TCP server/client:
http://systembash.com/content/a-simple-java-tcp-server-and-tcp-client/

env->FindClass("java.lang.Math");

env->FindClass("java.lang.Math"); fails. Why?
gcc -I/System/Library/Frameworks/JavaVM.framework/Headers test.cpp -framework JavaVM -o test && ./test
http://developer.apple.com/library/mac/#samplecode/simpleJavaLauncher/Listings/utils_h.html#//apple_ref/doc/uid/DTS10000688-utils_h-DontLinkElementID_7
http://developer.apple.com/library/mac/#technotes/tn2147/_index.html
#include <jni.h>
#include <stdlib.h>
int main() {
printf("START.\n");
JavaVM* jvm = NULL;
JNIEnv *env;
JavaVMInitArgs vm_args;
JNI_GetDefaultJavaVMInitArgs(&vm_args);
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 0;
int ret = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
if(ret < 0) {
printf("Unable to Launch JVM\n");
return 1;
}
jclass mathClass = env->FindClass("java.lang.Math");
if (mathClass == NULL) {
printf("Unable to find java.lang.Math\n");
return 1;
}
jmethodID cosMethod = env->GetStaticMethodID(mathClass, "cos", "(D)D");
if (cosMethod == NULL) {
printf("Unable to find java.lang.Math.cos()\n");
return 1;
}
printf("call\n");
jdouble jIn = 0.1;
jdouble jOut = env->CallStaticIntMethod(mathClass, cosMethod, jIn);
printf("jOut: %f", jOut);
printf("DestroyJavaVM.\n");
jvm->DestroyJavaVM();
printf("END.\n");
return 0;
}
You should be calling:
jclass mathClass = env->FindClass("java/lang/Math");
From the documentation:
name: fully-qualified class name (that is, a package name, delimited by “/”, followed by the class name). If the name begins with “[“ (the array signature character), it returns an array class.
Try:
env->FindClass("java/lang/Math")

Categories