src/server/plugins/java/jvm.c

Wed, 27 Nov 2024 23:00:07 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Wed, 27 Nov 2024 23:00:07 +0100
changeset 563
6ca97c99173e
parent 415
d938228c382e
permissions
-rw-r--r--

add TODO to use a future ucx feature

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2013 Olaf Wintermann. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h> 

#include <cx/map.h>

#include "jvm.h"
#include "daemon/request.h"

#ifdef __i386
#define LIBJVM "/usr/java/jre/lib/i386/server/libjvm.so"
#else

#endif

static JNIEnv *env = NULL;
static JavaVM *jvm = NULL;

static jobject plugin_instance = NULL;
static jmethodID load_jmodules_method = NULL;
static jmethodID exec_method = NULL;

int jvm_init(pblock *pb, Session *sn, Request *rq) {
    // load lib
    void *lib = dlopen(LIBJVM, RTLD_GLOBAL | RTLD_NOW);
    if(!lib) {
        log_ereport(LOG_FAILURE, "Cannot load libjvm.so");
        return REQ_ABORTED;
    }
    
    // get symbol
    void *sym = dlsym(lib, "JNI_CreateJavaVM");
    if(sym == NULL) {
        log_ereport(
                LOG_FAILURE,
                "Cannot get symbol JNI_CreateJavaVM from lib");
        return REQ_ABORTED;
    }
    
    // create JVM
    JavaVMInitArgs vm_args;
    JavaVMOption options[2];
    options[0].optionString = "-Djava.class.path=lib/wsrt.jar";
    options[1].optionString = "-Djava.library.path=lib/";
    vm_args.version = JNI_VERSION_1_6;
    vm_args.options = options;
    vm_args.nOptions = 2;
    vm_args.ignoreUnrecognized = JNI_TRUE;
    
    CreateJVMFunc create_jvm = (CreateJVMFunc)sym;
    if(create_jvm(&jvm, (void**)&env, &vm_args)) {
        dlclose(lib);
        log_ereport(LOG_FAILURE, "Cannot create JVM");
    }
    
    // load classes and methods
    jclass cls = (*env)->FindClass(env, "webserver/ServerPlugin");
    if(!cls) {
        log_ereport(
                LOG_FAILURE,
                "jvm-init: missing or broken wsrt.jar");
        log_ereport(
                LOG_FAILURE,
                "jvm-init: missing class webserver.ServerPlugin");
        return REQ_ABORTED;
    }
    
    jmethodID constr = (*env)->GetMethodID(env, cls, "<init>", "()V");
    if(!constr) {
        log_ereport(
                LOG_FAILURE,
                "jvm-init: missing or broken wsrt.jar");
        log_ereport(
                LOG_FAILURE,
                "jvm-init: missing constructor");
        return REQ_ABORTED;
    }
    plugin_instance = (*env)->NewObject(env, cls, constr);
    if(!plugin_instance) {
        log_ereport(
                LOG_FAILURE,
                "jvm-init: cannot create ServerPlugin instance");
        return REQ_ABORTED;
    }
    
    // methods
    load_jmodules_method = (*env)->GetMethodID(
            env,
            cls,
            "loadModule",
            "(Ljava/lang/String;Ljava/lang/String;)I");
    if(!load_jmodules_method) {
        log_ereport(LOG_FAILURE, "jvm-init: missing or broken wsrt.jar");
        log_ereport(LOG_FAILURE, "jvm-init: missing method (loadModule)");
        return REQ_ABORTED;
    }
    
    exec_method = (*env)->GetMethodID(
            env,
            cls,
            "exec",
            "(I)I");
    if(!exec_method) {
        log_ereport(LOG_FAILURE, "jvm-init: missing or broken wsrt.jar");
        log_ereport(LOG_FAILURE, "jvm-init: missing method (exec)");
        return REQ_ABORTED;
    }
    
    
    return REQ_PROCEED;
}

int load_jmodules(pblock *pb, Session *sn, Request *rq) {
    char *jar = pblock_findval("jar", pb);
    char *classes = pblock_findval("classes", pb);
    
    if(!jar || !classes) {
        log_ereport(
                LOG_MISCONFIG,
                "load-jmodule: missing parameters (jar, classes)");
        return REQ_ABORTED;
    }
       
    // check jvm 
    if(!plugin_instance) {
        log_ereport(
                LOG_FAILURE,
                "load-jmodules: java plugin not properly loaded");
        return REQ_ABORTED;
    }
    if(!load_jmodules_method) {
        log_ereport(
                LOG_FAILURE,
                "load-jmodules: java plugin not properly loaded");
        return REQ_ABORTED;
    }
    
    // load java module
    jstring jar_param = (*env)->NewStringUTF(env, jar);
    jstring classes_param = (*env)->NewStringUTF(env, classes);
    
    jint ret = (*env)->CallIntMethod(
            env,
            plugin_instance,
            load_jmodules_method,
            jar_param,
            classes_param);
    
    // free stuff
    (*env)->DeleteLocalRef(env, jar_param);
    (*env)->DeleteLocalRef(env, classes_param);
    
    return ret;
}

int jexec(pblock *pb, Session *sn, Request *rq) {
    return REQ_NOACTION;
}

int jvm_method_exec(FuncStruct *func, pblock *pb, Session *sn, Request *rq) {
    printf("jvm_method_exec: %d\n", func);
    NSAPIRequest *nrq = (NSAPIRequest*)rq;
    
    JNIEnv *e = NULL;
    int r = (*jvm)->AttachCurrentThread(jvm, (void**)&e, NULL);
    
    jint index = (jint)func->exec_data;
    printf("(C) exec: %d\n", index);
    
    jint ret = (*env)->CallIntMethod(
            env,
            plugin_instance,
            exec_method,
            index);
    
    return ret;
}

mercurial