From 9401f816dd0d9d550fe98a8507224bde51c4b847 Mon Sep 17 00:00:00 2001 From: hongbotian Date: Mon, 30 Nov 2015 02:41:33 -0500 Subject: upload tomcat JIRA: BOTTLENECK-7 Change-Id: I875d474869efd76ca203c30b60ebc0c3ee606d0e Signed-off-by: hongbotian --- .../native/common/jk_jni_worker.c | 1267 ++++++++++++++++++++ 1 file changed, 1267 insertions(+) create mode 100644 rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.c (limited to 'rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.c') diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.c new file mode 100644 index 00000000..048f4435 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.c @@ -0,0 +1,1267 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: In process JNI worker * + * Author: Gal Shachor * + * Based on: * + * Version: $Revision: 750428 $ * + ***************************************************************************/ + +#if !defined(WIN32) && !defined(NETWARE) && !defined(AS400) +#include +#endif + +#include + +#include "jk_pool.h" +#include "jk_jni_worker.h" +#include "jk_util.h" + +#if !defined(JNI_VERSION_1_6) +#if defined LINUX && defined APACHE2_SIGHACK +#include +#include +#include +#endif + +#ifdef NETWARE +#ifdef __NOVELL_LIBC__ +#include +#else +#include +#include +#endif +#endif + +#ifndef JNI_VERSION_1_1 +#define JNI_VERSION_1_1 0x00010001 +#endif + +/* probably on an older system that doesn't support RTLD_NOW or RTLD_LAZY. + * The below define is a lie since we are really doing RTLD_LAZY since the + * system doesn't support RTLD_NOW. + */ +#ifndef RTLD_NOW +#define RTLD_NOW 1 +#endif + +#ifndef RTLD_GLOBAL +#define RTLD_GLOBAL 0 +#endif + +#define null_check(e) if ((e) == 0) return JK_FALSE + +jint(JNICALL * jni_get_default_java_vm_init_args) (void *) = NULL; +jint(JNICALL * jni_create_java_vm) (JavaVM **, JNIEnv **, void *) = NULL; +#ifdef AS400 +jint(JNICALL * jni_get_created_java_vms) (JavaVM **, long, long *) = NULL; +#else +jint(JNICALL * jni_get_created_java_vms) (JavaVM **, int, int *) = NULL; +#endif + +#define TC33_JAVA_BRIDGE_CLASS_NAME ("org/apache/tomcat/modules/server/JNIEndpoint") +#define TC32_JAVA_BRIDGE_CLASS_NAME ("org/apache/tomcat/service/JNIEndpoint") + +static jk_worker_t *the_singleton_jni_worker = NULL; + +struct jni_worker +{ + + int was_verified; + int was_initialized; + + jk_pool_t p; + jk_pool_atom_t buf[TINY_POOL_SIZE]; + + /* + * JVM Object pointer. + */ + JavaVM *jvm; + + /* + * [V] JNIEnv used for boostraping from validate -> init w/o an attach + */ + JNIEnv *tmp_env; + + /* + * Web Server to Java bridge, instance and class. + */ + jobject jk_java_bridge_object; + jclass jk_java_bridge_class; + + /* + * Java methods ids, to jump into the JVM + */ + jmethodID jk_startup_method; + jmethodID jk_service_method; + jmethodID jk_shutdown_method; + + /* + * Command line for tomcat startup + */ + char *tomcat_cmd_line; + + /* + * Bridge Type, Tomcat 32/33/40/41/5 + */ + unsigned bridge_type; + + /* + * Classpath + */ + char *tomcat_classpath; + + /* + * Full path to the jni javai/jvm dll + */ + char *jvm_dll_path; + + /* + * Initial Java heap size + */ + unsigned tomcat_ms; + + /* + * Max Java heap size + */ + unsigned tomcat_mx; + + /* + * Java system properties + */ + char **sysprops; + +#ifdef JNI_VERSION_1_2 + /* + * Java 2 initialization options (-X... , -verbose etc.) + */ + char **java2opts; + + /* + * Java 2 lax/strict option checking (bool) + */ + int java2lax; +#endif + + /* + * stdout and stderr file names for Java + */ + char *stdout_name; + char *stderr_name; + + char *name; + jk_worker_t worker; +}; +typedef struct jni_worker jni_worker_t; + +struct jni_endpoint +{ + int attached; + JNIEnv *env; + jni_worker_t *worker; + + jk_endpoint_t endpoint; +}; +typedef struct jni_endpoint jni_endpoint_t; + + +static int load_jvm_dll(jni_worker_t * p, jk_logger_t *l); + +static int open_jvm(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l); + +static int open_jvm1(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l); + +#ifdef JNI_VERSION_1_2 +static int detect_jvm_version(jk_logger_t *l); + +static int open_jvm2(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l); +#endif + + +static int get_bridge_object(jni_worker_t * p, JNIEnv * env, jk_logger_t *l); + +static int get_method_ids(jni_worker_t * p, JNIEnv * env, jk_logger_t *l); + +static JNIEnv *attach_to_jvm(jni_worker_t * p, jk_logger_t *l); + +static void detach_from_jvm(jni_worker_t * p, jk_logger_t *l); + + +/* + Duplicate string and convert it to ASCII on EBDIC based systems + Needed for at least AS/400 (before V5R4 ?) and BS2000 but what about other EBDIC systems ? +*/ +static void *strdup_ascii(jk_pool_t *p, char *s) +{ + char *rc; + rc = jk_pool_strdup(p, s); + +#if defined(AS400) || defined(_OSD_POSIX) + jk_xlate_to_ascii(rc, strlen(rc)); +#endif + + return rc; +} + +#if defined LINUX && defined APACHE2_SIGHACK +static void linux_signal_hack() +{ + sigset_t newM; + sigset_t old; + + sigemptyset(&newM); + pthread_sigmask(SIG_SETMASK, &newM, &old); + + sigdelset(&old, SIGUSR1); + sigdelset(&old, SIGUSR2); + sigdelset(&old, SIGUNUSED); + sigdelset(&old, SIGRTMIN); + sigdelset(&old, SIGRTMIN + 1); + sigdelset(&old, SIGRTMIN + 2); + pthread_sigmask(SIG_SETMASK, &old, NULL); +} + +static void print_signals(sigset_t * sset) +{ + int sig; + for (sig = 1; sig < 20; sig++) { + if (sigismember(sset, sig)) { + printf(" %d", sig); + } + } + printf("\n"); +} +#endif + +/* + * Return values of service() method for jni worker: + * return value is_error reason + * JK_FALSE JK_HTTP_SERVER_ERROR Invalid parameters (null values) + * Error during attach to the JNI backend + * Error during JNI call + * JK_TRUE JK_HTTP_OK All other cases + */ +static int JK_METHOD service(jk_endpoint_t *e, + jk_ws_service_t *s, + jk_logger_t *l, int *is_error) +{ + jni_endpoint_t *p; + jint rc; + + JK_TRACE_ENTER(l); + + if (!e || !e->endpoint_private || !s || !is_error) { + JK_LOG_NULL_PARAMS(l); + if (is_error) + *is_error = JK_HTTP_SERVER_ERROR; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p = e->endpoint_private; + + /* Set returned error to OK */ + *is_error = JK_HTTP_OK; + + if (!p->attached) { + /* Try to attach */ + if (!(p->env = attach_to_jvm(p->worker, l))) { + jk_log(l, JK_LOG_EMERG, "Attach failed"); + *is_error = JK_HTTP_SERVER_ERROR; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + p->attached = JK_TRUE; + } + + /* we are attached now */ + + /* + * When we call the JVM we cannot know what happens + * So we can not recover !!! + */ + jk_log(l, JK_LOG_DEBUG, "In service, calling Tomcat..."); + + rc = (*(p->env))->CallIntMethod(p->env, + p->worker->jk_java_bridge_object, + p->worker->jk_service_method, + /* [V] For some reason gcc likes this pointer -> int -> jlong conversion, */ + /* but not the direct pointer -> jlong conversion. I hope it's okay. */ +#ifdef AS400 + s, l +#else + (jlong) (int)s, (jlong) (int)l +#endif + ); + + /* [V] Righ now JNIEndpoint::service() only returns 1 or 0 */ + if (rc) { + jk_log(l, JK_LOG_DEBUG, "Tomcat returned OK, done"); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + else { + jk_log(l, JK_LOG_ERROR, "Tomcat FAILED!"); + *is_error = JK_HTTP_SERVER_ERROR; + JK_TRACE_EXIT(l); + return JK_FALSE; + } +} + +static int JK_METHOD done(jk_endpoint_t **e, jk_logger_t *l) +{ + jni_endpoint_t *p; + + JK_TRACE_ENTER(l); + if (!e || !*e || !(*e)->endpoint_private) { + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p = (*e)->endpoint_private; + + if (p->attached) { + detach_from_jvm(p->worker, l); + } + + free(p); + *e = NULL; + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +static int JK_METHOD validate(jk_worker_t *pThis, + jk_map_t *props, + jk_worker_env_t *we, jk_logger_t *l) +{ + jni_worker_t *p; + int mem_config = 0; + int btype = 0; + const char *str_config = NULL; + JNIEnv *env; + + JK_TRACE_ENTER(l); + + if (!pThis || !pThis->worker_private) { + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p = pThis->worker_private; + + if (p->was_verified) { + jk_log(l, JK_LOG_DEBUG, "been here before, done"); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + + if (jk_get_worker_mx(props, p->name, (unsigned int *)&mem_config)) { + p->tomcat_mx = mem_config; + } + + if (jk_get_worker_ms(props, p->name, (unsigned int *)&mem_config)) { + p->tomcat_ms = mem_config; + } + + if (jk_get_worker_classpath(props, p->name, &str_config)) { + p->tomcat_classpath = jk_pool_strdup(&p->p, str_config); + } + + if (!p->tomcat_classpath) { + jk_log(l, JK_LOG_EMERG, "no classpath"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (jk_get_worker_bridge_type(props, p->name, (unsigned int *)&btype)) { + p->bridge_type = btype; + } + + if (jk_get_worker_jvm_path(props, p->name, &str_config)) { + p->jvm_dll_path = jk_pool_strdup(&p->p, str_config); + } + + if (!p->jvm_dll_path || !jk_file_exists(p->jvm_dll_path)) { + jk_log(l, JK_LOG_EMERG, "no jvm_dll_path"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (jk_get_worker_cmd_line(props, p->name, &str_config)) { + p->tomcat_cmd_line = jk_pool_strdup(&p->p, str_config); + } + + if (jk_get_worker_stdout(props, p->name, &str_config)) { + p->stdout_name = jk_pool_strdup(&p->p, str_config); + } + + if (jk_get_worker_stderr(props, p->name, &str_config)) { + p->stderr_name = jk_pool_strdup(&p->p, str_config); + } + + if (jk_get_worker_sysprops(props, p->name, &str_config)) { + p->sysprops = jk_parse_sysprops(&p->p, str_config); + } + +#ifdef JNI_VERSION_1_2 + if (jk_get_worker_str_prop(props, p->name, "java2opts", &str_config)) { + /* jk_log(l, JK_LOG_DEBUG, "Got opts: %s", str_config); */ + p->java2opts = jk_parse_sysprops(&p->p, str_config); + } + if (jk_get_worker_int_prop(props, p->name, "java2lax", &mem_config)) { + p->java2lax = mem_config ? JK_TRUE : JK_FALSE; + } +#endif + + if (jk_get_worker_libpath(props, p->name, &str_config)) { + jk_append_libpath(&p->p, str_config); + } + + if (!load_jvm_dll(p, l)) { + jk_log(l, JK_LOG_EMERG, "can't load jvm dll"); + /* [V] no detach needed here */ + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (!open_jvm(p, &env, l)) { + jk_log(l, JK_LOG_EMERG, "can't open jvm"); + /* [V] no detach needed here */ + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (!get_bridge_object(p, env, l)) { + jk_log(l, JK_LOG_EMERG, "can't get bridge object"); + /* [V] the detach here may segfault on 1.1 JVM... */ + detach_from_jvm(p, l); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (!get_method_ids(p, env, l)) { + jk_log(l, JK_LOG_EMERG, "can't get method ids"); + /* [V] the detach here may segfault on 1.1 JVM... */ + detach_from_jvm(p, l); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p->was_verified = JK_TRUE; + p->tmp_env = env; + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +static int JK_METHOD init(jk_worker_t *pThis, + jk_map_t *props, + jk_worker_env_t *we, jk_logger_t *l) +{ + jni_worker_t *p; + JNIEnv *env; + + JK_TRACE_ENTER(l); + + if (!pThis || !pThis->worker_private) { + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p = pThis->worker_private; + + if (p->was_initialized) { + jk_log(l, JK_LOG_DEBUG, "done (been here!)"); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + + if (!p->jvm || + !p->jk_java_bridge_object || + !p->jk_service_method || + !p->jk_startup_method || !p->jk_shutdown_method) { + jk_log(l, JK_LOG_EMERG, "worker not set completely"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + /* [V] init is called from the same thread that called validate */ + /* there is no need to attach to the JVM, just get the env */ + + /* if(env = attach_to_jvm(p,l)) { */ + if ((env = p->tmp_env)) { + jstring cmd_line = (jstring) NULL; + jstring stdout_name = (jstring) NULL; + jstring stderr_name = (jstring) NULL; + jint rc = 0; + + /* AS400/BS2000 need EBCDIC to ASCII conversion for JNI */ + + if (p->tomcat_cmd_line) { + cmd_line = + (*env)->NewStringUTF(env, + strdup_ascii(&p->p, p->tomcat_cmd_line)); + } + if (p->stdout_name) { + stdout_name = + (*env)->NewStringUTF(env, + strdup_ascii(&p->p, p->stdout_name)); + } + if (p->stderr_name) { + stderr_name = + (*env)->NewStringUTF(env, + strdup_ascii(&p->p, p->stderr_name)); + } + + jk_log(l, JK_LOG_DEBUG, + "calling Tomcat to intialize itself..."); + rc = (*env)->CallIntMethod(env, p->jk_java_bridge_object, + p->jk_startup_method, cmd_line, + stdout_name, stderr_name); + + detach_from_jvm(p, l); + + if (rc) { + p->was_initialized = JK_TRUE; + jk_log(l, JK_LOG_DEBUG, "Tomcat initialized OK, done"); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + else { + jk_log(l, JK_LOG_EMERG, "could not initialize Tomcat"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + else { + jk_log(l, JK_LOG_ERROR, + "In init, FIXME: init didn't gen env from validate!"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } +} + +static int JK_METHOD get_endpoint(jk_worker_t *pThis, + jk_endpoint_t **pend, jk_logger_t *l) +{ + /* [V] This slow, needs replacement */ + jni_endpoint_t *p; + + JK_TRACE_ENTER(l); + + if (!pThis || !pThis->worker_private || !pend) { + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p = (jni_endpoint_t *) calloc(1, sizeof(jni_endpoint_t)); + if (p) { + p->attached = JK_FALSE; + p->env = NULL; + p->worker = pThis->worker_private; + p->endpoint.endpoint_private = p; + p->endpoint.service = service; + p->endpoint.done = done; + *pend = &p->endpoint; + + JK_TRACE_EXIT(l); + return JK_TRUE; + } + else { + jk_log(l, JK_LOG_ERROR, + "could not allocate endpoint"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } +} + +static int JK_METHOD destroy(jk_worker_t **pThis, jk_logger_t *l) +{ + jni_worker_t *p; + JNIEnv *env; + + JK_TRACE_ENTER(l); + + if (!pThis || !*pThis || !(*pThis)->worker_private) { + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p = (*pThis)->worker_private; + + if (!p->jvm) { + jk_log(l, JK_LOG_DEBUG, "JVM not intantiated"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (!p->jk_java_bridge_object || !p->jk_shutdown_method) { + jk_log(l, JK_LOG_DEBUG, "Tomcat not intantiated"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if ((env = attach_to_jvm(p, l))) { + jk_log(l, JK_LOG_DEBUG, "shutting down Tomcat..."); + (*env)->CallVoidMethod(env, + p->jk_java_bridge_object, + p->jk_shutdown_method); + detach_from_jvm(p, l); + } + + jk_close_pool(&p->p); + free(p); + + jk_log(l, JK_LOG_DEBUG, "destroyed"); + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +int JK_METHOD jni_worker_factory(jk_worker_t **w, + const char *name, jk_logger_t *l) +{ + jni_worker_t *private_data; + + JK_TRACE_ENTER(l); + + jk_log(l, JK_LOG_WARNING, + "Worker '%s' is of type jni, which is deprecated " + "and will be removed in a future release.", + name ? name : "(null)"); + + if (!name || !w) { + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return 0; + } + + if (the_singleton_jni_worker) { + jk_log(l, JK_LOG_DEBUG, + "instance already created"); + *w = the_singleton_jni_worker; + JK_TRACE_EXIT(l); + return JK_JNI_WORKER_TYPE; + } + + private_data = (jni_worker_t *) malloc(sizeof(jni_worker_t)); + + if (!private_data) { + jk_log(l, JK_LOG_ERROR, + "memory allocation error"); + JK_TRACE_EXIT(l); + return 0; + } + + jk_open_pool(&private_data->p, + private_data->buf, sizeof(jk_pool_atom_t) * TINY_POOL_SIZE); + + private_data->name = jk_pool_strdup(&private_data->p, name); + + if (!private_data->name) { + jk_log(l, JK_LOG_ERROR, + "memory allocation error"); + jk_close_pool(&private_data->p); + free(private_data); + JK_TRACE_EXIT(l); + return 0; + } + + private_data->was_verified = JK_FALSE; + private_data->was_initialized = JK_FALSE; + private_data->jvm = NULL; + private_data->tmp_env = NULL; + private_data->jk_java_bridge_object = (jobject) NULL; + private_data->jk_java_bridge_class = (jclass) NULL; + private_data->jk_startup_method = (jmethodID) NULL; + private_data->jk_service_method = (jmethodID) NULL; + private_data->jk_shutdown_method = (jmethodID) NULL; + private_data->tomcat_cmd_line = NULL; + private_data->tomcat_classpath = NULL; + private_data->bridge_type = TC33_BRIDGE_TYPE; + private_data->jvm_dll_path = NULL; + private_data->tomcat_ms = 0; + private_data->tomcat_mx = 0; + private_data->sysprops = NULL; +#ifdef JNI_VERSION_1_2 + private_data->java2opts = NULL; + private_data->java2lax = JK_TRUE; +#endif + private_data->stdout_name = NULL; + private_data->stderr_name = NULL; + + private_data->worker.worker_private = private_data; + private_data->worker.validate = validate; + private_data->worker.init = init; + private_data->worker.get_endpoint = get_endpoint; + private_data->worker.destroy = destroy; + + *w = &private_data->worker; + the_singleton_jni_worker = &private_data->worker; + + JK_TRACE_EXIT(l); + return JK_JNI_WORKER_TYPE; +} + +static int load_jvm_dll(jni_worker_t * p, jk_logger_t *l) +{ +#ifdef WIN32 + HINSTANCE hInst = LoadLibrary(p->jvm_dll_path); + if (hInst) { + (FARPROC) jni_create_java_vm = + GetProcAddress(hInst, "JNI_CreateJavaVM"); + + (FARPROC) jni_get_created_java_vms = + GetProcAddress(hInst, "JNI_GetCreatedJavaVMs"); + + (FARPROC) jni_get_default_java_vm_init_args = + GetProcAddress(hInst, "JNI_GetDefaultJavaVMInitArgs"); + + jk_log(l, JK_LOG_DEBUG, "Loaded all JNI procs"); + + if (jni_create_java_vm && jni_get_default_java_vm_init_args + && jni_get_created_java_vms) { + return JK_TRUE; + } + + FreeLibrary(hInst); + } +#elif defined(NETWARE) && !defined(__NOVELL_LIBC__) + int javaNlmHandle = FindNLMHandle("JVM"); + if (0 == javaNlmHandle) { + /* if we didn't get a handle, try to load java and retry getting the */ + /* handle */ + spawnlp(P_NOWAIT, "JVM.NLM", NULL); + ThreadSwitchWithDelay(); + javaNlmHandle = FindNLMHandle("JVM"); + if (0 == javaNlmHandle) + printf("Error loading Java."); + + } + if (0 != javaNlmHandle) { + jni_create_java_vm = ImportSymbol(GetNLMHandle(), "JNI_CreateJavaVM"); + jni_get_created_java_vms = + ImportSymbol(GetNLMHandle(), "JNI_GetCreatedJavaVMs"); + jni_get_default_java_vm_init_args = + ImportSymbol(GetNLMHandle(), "JNI_GetDefaultJavaVMInitArgs"); + } + if (jni_create_java_vm && jni_get_default_java_vm_init_args + && jni_get_created_java_vms) { + return JK_TRUE; + } +#elif defined(AS400) + jk_log(l, JK_LOG_DEBUG, + "Direct reference to JNI entry points (no SRVPGM)"); + jni_create_java_vm = &JNI_CreateJavaVM; + jni_get_default_java_vm_init_args = &JNI_GetDefaultJavaVMInitArgs; + jni_get_created_java_vms = &JNI_GetCreatedJavaVMs; +#else + void *handle; + jk_log(l, JK_LOG_DEBUG, "loading JVM %s", p->jvm_dll_path); + + handle = dlopen(p->jvm_dll_path, RTLD_NOW | RTLD_GLOBAL); + + if (!handle) { + jk_log(l, JK_LOG_EMERG, + "Can't load native library %s : %s", p->jvm_dll_path, + dlerror()); + } + else { + jni_create_java_vm = dlsym(handle, "JNI_CreateJavaVM"); + jni_get_default_java_vm_init_args = + dlsym(handle, "JNI_GetDefaultJavaVMInitArgs"); + jni_get_created_java_vms = dlsym(handle, "JNI_GetCreatedJavaVMs"); + + if (jni_create_java_vm && jni_get_default_java_vm_init_args && + jni_get_created_java_vms) { + jk_log(l, JK_LOG_DEBUG, + "In load_jvm_dll, symbols resolved, done"); + return JK_TRUE; + } + jk_log(l, JK_LOG_EMERG, + "Can't resolve JNI_CreateJavaVM or JNI_GetDefaultJavaVMInitArgs"); + dlclose(handle); + } +#endif + return JK_FALSE; +} + +static int open_jvm(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l) +{ +#ifdef JNI_VERSION_1_2 + int jvm_version = detect_jvm_version(l); + + switch (jvm_version) { + case JNI_VERSION_1_1: + return open_jvm1(p, env, l); + case JNI_VERSION_1_2: + return open_jvm2(p, env, l); + default: + return JK_FALSE; + } +#else + /* [V] Make sure this is _really_ visible */ +#warning ------------------------------------------------------- +#warning NO JAVA 2 HEADERS! SUPPORT FOR JAVA 2 FEATURES DISABLED +#warning ------------------------------------------------------- + return open_jvm1(p, env, l); +#endif +} + +static int open_jvm1(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l) +{ + JDK1_1InitArgs vm_args; + JNIEnv *penv; + int err; + *env = NULL; + + JK_TRACE_ENTER(l); + + vm_args.version = JNI_VERSION_1_1; + + if (0 != jni_get_default_java_vm_init_args(&vm_args)) { + jk_log(l, JK_LOG_EMERG, "can't get default vm init args"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + jk_log(l, JK_LOG_DEBUG, "got default jvm args"); + + if (vm_args.classpath) { + size_t len = strlen(vm_args.classpath) + + strlen(p->tomcat_classpath) + 3; + char *tmp = jk_pool_alloc(&p->p, len); + if (tmp) { + sprintf(tmp, "%s%c%s", + strdup_ascii(&p->p, p->tomcat_classpath), + PATH_SEPERATOR, vm_args.classpath); + p->tomcat_classpath = tmp; + } + else { + jk_log(l, JK_LOG_EMERG, + "allocation error for classpath"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + vm_args.classpath = p->tomcat_classpath; + + if (p->tomcat_mx) { + vm_args.maxHeapSize = p->tomcat_mx; + } + + if (p->tomcat_ms) { + vm_args.minHeapSize = p->tomcat_ms; + } + + if (p->sysprops) { + /* No EBCDIC to ASCII conversion here for AS/400 - later */ + vm_args.properties = p->sysprops; + } + + jk_log(l, JK_LOG_DEBUG, "In open_jvm1, about to create JVM..."); + if ((err = jni_create_java_vm(&(p->jvm), &penv, &vm_args)) != 0) { + jk_log(l, JK_LOG_EMERG, + "could not create JVM, code: %d ", err); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + jk_log(l, JK_LOG_DEBUG, "JVM created, done"); + + *env = penv; + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +#ifdef JNI_VERSION_1_2 +static int detect_jvm_version(jk_logger_t *l) +{ + JNIEnv *env = NULL; + JDK1_1InitArgs vm_args; + + JK_TRACE_ENTER(l); + + /* [V] Idea: ask for 1.2. If the JVM is 1.1 it will return 1.1 instead */ + /* Note: asking for 1.1 won't work, 'cause 1.2 JVMs will return 1.1 */ + vm_args.version = JNI_VERSION_1_2; + + if (0 != jni_get_default_java_vm_init_args(&vm_args)) { + jk_log(l, JK_LOG_EMERG, "can't get default vm init args"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + jk_log(l, JK_LOG_DEBUG, + "found version: %X, done", vm_args.version); + + JK_TRACE_EXIT(l); + return vm_args.version; +} + +static char *build_opt_str(jk_pool_t *p, + char *opt_name, char *opt_value, jk_logger_t *l) +{ + size_t len = strlen(opt_name) + strlen(opt_value) + 2; + + /* [V] IMHO, these should not be deallocated as long as the JVM runs */ + char *tmp = jk_pool_alloc(p, len); + + if (tmp) { + sprintf(tmp, "%s%s", opt_name, opt_value); + return tmp; + } + else { + jk_log(l, JK_LOG_EMERG, + "allocation error for %s", opt_name); + return NULL; + } +} + +static char *build_opt_int(jk_pool_t *p, + char *opt_name, int opt_value, jk_logger_t *l) +{ + /* [V] this should suffice even for 64-bit int */ + size_t len = strlen(opt_name) + 20 + 2; + /* [V] IMHO, these should not be deallocated as long as the JVM runs */ + char *tmp = jk_pool_alloc(p, len); + + if (tmp) { + sprintf(tmp, "%s%d", opt_name, opt_value); + return tmp; + } + else { + jk_log(l, JK_LOG_EMERG, + "allocation error for %s", opt_name); + return NULL; + } +} + +static int open_jvm2(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l) +{ + JavaVMInitArgs vm_args; + JNIEnv *penv = NULL; + JavaVMOption options[100]; + int optn = 0, err; + char *tmp; + + *env = NULL; + + JK_TRACE_ENTER(l); + + vm_args.version = JNI_VERSION_1_2; + vm_args.options = options; + +/* AS/400 need EBCDIC to ASCII conversion to parameters passed to JNI */ +/* No conversion for ASCII based systems (what about BS2000 ?) */ + + if (p->tomcat_classpath) { + jk_log(l, JK_LOG_DEBUG, "setting classpath to %s", + p->tomcat_classpath); + tmp = + build_opt_str(&p->p, "-Djava.class.path=", p->tomcat_classpath, + l); + null_check(tmp); + options[optn++].optionString = strdup_ascii(&p->p, tmp); + } + + if (p->tomcat_mx) { + jk_log(l, JK_LOG_DEBUG, "setting max heap to %d", + p->tomcat_mx); + tmp = build_opt_int(&p->p, "-Xmx", p->tomcat_mx, l); + null_check(tmp); + options[optn++].optionString = strdup_ascii(&p->p, tmp); + } + + if (p->tomcat_ms) { + jk_log(l, JK_LOG_DEBUG, "setting start heap to %d", + p->tomcat_ms); + tmp = build_opt_int(&p->p, "-Xms", p->tomcat_ms, l); + null_check(tmp); + options[optn++].optionString = strdup_ascii(&p->p, tmp); + } + + if (p->sysprops) { + int i = 0; + while (p->sysprops[i]) { + jk_log(l, JK_LOG_DEBUG, "setting %s", + p->sysprops[i]); + tmp = build_opt_str(&p->p, "-D", p->sysprops[i], l); + null_check(tmp); + options[optn++].optionString = strdup_ascii(&p->p, tmp); + i++; + } + } + + if (p->java2opts) { + int i = 0; + + while (p->java2opts[i]) { + jk_log(l, JK_LOG_DEBUG, "using option: %s", + p->java2opts[i]); + /* Pass it "as is" */ + options[optn++].optionString = + strdup_ascii(&p->p, p->java2opts[i++]); + } + } + + vm_args.nOptions = optn; + + if (p->java2lax) { + jk_log(l, JK_LOG_DEBUG, + "the JVM will ignore unknown options"); + vm_args.ignoreUnrecognized = JNI_TRUE; + } + else { + jk_log(l, JK_LOG_DEBUG, + "the JVM will FAIL if it finds unknown options"); + vm_args.ignoreUnrecognized = JNI_FALSE; + } + + jk_log(l, JK_LOG_DEBUG, "about to create JVM..."); + + err = jni_create_java_vm(&(p->jvm), &penv, &vm_args); + + if (JNI_EEXIST == err) { +#ifdef AS400 + long vmCount; +#else + int vmCount; +#endif + jk_log(l, JK_LOG_DEBUG, "JVM alread instantiated." + "Trying to attach instead."); + + jni_get_created_java_vms(&(p->jvm), 1, &vmCount); + if (NULL != p->jvm) + penv = attach_to_jvm(p, l); + + if (NULL != penv) + err = 0; + } + + if (err != 0) { + jk_log(l, JK_LOG_EMERG, "Fail-> could not create JVM, code: %d ", + err); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + *env = penv; + jk_log(l, JK_LOG_DEBUG, "JVM created"); + + JK_TRACE_EXIT(l); + return JK_TRUE; +} +#endif + +static int get_bridge_object(jni_worker_t * p, JNIEnv * env, jk_logger_t *l) +{ + char *btype; + char *ctype; + + jmethodID constructor_method_id; + + JK_TRACE_ENTER(l); + + switch (p->bridge_type) { + case TC32_BRIDGE_TYPE: + btype = TC32_JAVA_BRIDGE_CLASS_NAME; + break; + + case TC33_BRIDGE_TYPE: + btype = TC33_JAVA_BRIDGE_CLASS_NAME; + break; + + case TC40_BRIDGE_TYPE: + case TC41_BRIDGE_TYPE: + case TC50_BRIDGE_TYPE: + jk_log(l, JK_LOG_EMERG, "Bridge type %d not supported", + p->bridge_type); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + +/* AS400/BS2000 need conversion from EBCDIC to ASCII before passing to JNI */ +/* for others, strdup_ascii is just jk_pool_strdup */ + + ctype = strdup_ascii(&p->p, btype); + + p->jk_java_bridge_class = (*env)->FindClass(env, ctype); + + if (!p->jk_java_bridge_class) { + jk_log(l, JK_LOG_EMERG, "Can't find class %s", btype); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + jk_log(l, JK_LOG_DEBUG, + "In get_bridge_object, loaded %s bridge class", btype); + + constructor_method_id = (*env)->GetMethodID(env, p->jk_java_bridge_class, strdup_ascii(&p->p, ""), /* method name */ + strdup_ascii(&p->p, "()V")); /* method sign */ + + if (!constructor_method_id) { + p->jk_java_bridge_class = (jclass) NULL; + jk_log(l, JK_LOG_EMERG, "Can't find constructor"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p->jk_java_bridge_object = (*env)->NewObject(env, + p->jk_java_bridge_class, + constructor_method_id); + if (!p->jk_java_bridge_object) { + p->jk_java_bridge_class = (jclass) NULL; + jk_log(l, JK_LOG_EMERG, "Can't create new bridge object"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p->jk_java_bridge_object = + (jobject) (*env)->NewGlobalRef(env, p->jk_java_bridge_object); + if (!p->jk_java_bridge_object) { + jk_log(l, JK_LOG_EMERG, "Can't create global ref to bridge object"); + p->jk_java_bridge_class = (jclass) NULL; + p->jk_java_bridge_object = (jobject) NULL; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +static int get_method_ids(jni_worker_t * p, JNIEnv * env, jk_logger_t *l) +{ + +/* AS400/BS2000 need conversion from EBCDIC to ASCII before passing to JNI */ + + p->jk_startup_method = (*env)->GetMethodID(env, + p->jk_java_bridge_class, + strdup_ascii(&p->p, "startup"), + strdup_ascii(&p->p, + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I")); + + if (!p->jk_startup_method) { + jk_log(l, JK_LOG_EMERG, "Can't find startup()"); + return JK_FALSE; + } + + p->jk_service_method = (*env)->GetMethodID(env, + p->jk_java_bridge_class, + strdup_ascii(&p->p, "service"), + strdup_ascii(&p->p, "(JJ)I")); + + if (!p->jk_service_method) { + jk_log(l, JK_LOG_EMERG, "Can't find service()"); + return JK_FALSE; + } + + p->jk_shutdown_method = (*env)->GetMethodID(env, + p->jk_java_bridge_class, + strdup_ascii(&p->p, + "shutdown"), + strdup_ascii(&p->p, "()V")); + + if (!p->jk_shutdown_method) { + jk_log(l, JK_LOG_EMERG, "Can't find shutdown()"); + return JK_FALSE; + } + + return JK_TRUE; +} + +static JNIEnv *attach_to_jvm(jni_worker_t * p, jk_logger_t *l) +{ + JNIEnv *rc = NULL; + /* [V] This message is important. If there are signal mask issues, * + * the JVM usually hangs when a new thread tries to attach to it */ + JK_TRACE_ENTER(l); + +#if defined LINUX && defined APACHE2_SIGHACK + linux_signal_hack(); +#endif + + if (0 == (*(p->jvm))->AttachCurrentThread(p->jvm, +#ifdef JNI_VERSION_1_2 + (void **) +#endif + &rc, NULL)) { + jk_log(l, JK_LOG_DEBUG, "In attach_to_jvm, attached ok"); + JK_TRACE_EXIT(l); + return rc; + } + jk_log(l, JK_LOG_ERROR, + "In attach_to_jvm, cannot attach thread to JVM."); + JK_TRACE_EXIT(l); + return NULL; +} + +/* +static JNIEnv *attach_to_jvm(jni_worker_t *p) +{ + JNIEnv *rc = NULL; + +#ifdef LINUX + linux_signal_hack(); +#endif + + if(0 == (*(p->jvm))->AttachCurrentThread(p->jvm, +#ifdef JNI_VERSION_1_2 + (void **) +#endif + &rc, + NULL)) { + return rc; + } + + return NULL; +} +*/ +static void detach_from_jvm(jni_worker_t * p, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + if (!p->jvm || !(*(p->jvm))) { + jk_log(l, JK_LOG_ERROR, + "cannot detach from NULL JVM."); + } + + if (0 == (*(p->jvm))->DetachCurrentThread(p->jvm)) { + jk_log(l, JK_LOG_DEBUG, "detached ok"); + } + else { + jk_log(l, JK_LOG_ERROR, + "cannot detach from JVM."); + } + JK_TRACE_EXIT(l); +} +#else +int JK_METHOD jni_worker_factory(jk_worker_t **w, + const char *name, jk_logger_t *l) +{ + jk_log(l, JK_LOG_WARNING, + "Worker '%s' is of type jni, which is deprecated " + "and will be removed in a future release.", + name ? name : "(null)"); + if (w) + *w = NULL; + return 0; +} +#endif /* JNI_VERSION_1_6 */ -- cgit 1.2.3-korg