summaryrefslogtreecommitdiffstats
path: root/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.c
diff options
context:
space:
mode:
Diffstat (limited to 'rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.c')
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.c1267
1 files changed, 1267 insertions, 0 deletions
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 <shachor@il.ibm.com> *
+ * Based on: *
+ * Version: $Revision: 750428 $ *
+ ***************************************************************************/
+
+#if !defined(WIN32) && !defined(NETWARE) && !defined(AS400)
+#include <dlfcn.h>
+#endif
+
+#include <jni.h>
+
+#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 <pthread.h>
+#include <signal.h>
+#include <bits/signum.h>
+#endif
+
+#ifdef NETWARE
+#ifdef __NOVELL_LIBC__
+#include <dlfcn.h>
+#else
+#include <nwthread.h>
+#include <nwadv.h>
+#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, "<init>"), /* 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 */