costin 01/12/01 14:37:29 Added: jk/native2/common jk_ajp14_worker.c jk_jni_worker.c jk_lb_worker.c Log: Workers - updated to use the new factory style. Revision Changes Path 1.1 jakarta-tomcat-connectors/jk/native2/common/jk_ajp14_worker.c Index: jk_ajp14_worker.c =================================================================== /* ========================================================================= * * * * The Apache Software License, Version 1.1 * * * * Copyright (c) 1999-2001 The Apache Software Foundation. * * All rights reserved. * * * * ========================================================================= * * * * Redistribution and use in source and binary forms, with or without modi- * * fication, are permitted provided that the following conditions are met: * * * * 1. Redistributions of source code must retain the above copyright notice * * 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. * * * * 3. The end-user documentation included with the redistribution, if any, * * must include the following acknowlegement: * * * * "This product includes software developed by the Apache Software * * Foundation <http://www.apache.org/>." * * * * Alternately, this acknowlegement may appear in the software itself, if * * and wherever such third-party acknowlegements normally appear. * * * * 4. The names "The Jakarta Project", "Jk", and "Apache Software * * Foundation" must not be used to endorse or promote products derived * * from this software without prior written permission. For written * * permission, please contact <[EMAIL PROTECTED]>. * * * * 5. Products derived from this software may not be called "Apache" nor may * * "Apache" appear in their names without prior written permission of the * * Apache Software Foundation. * * * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR ITS 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. * * * * ========================================================================= * * * * This software consists of voluntary contributions made by many indivi- * * duals on behalf of the Apache Software Foundation. For more information * * on the Apache Software Foundation, please see <http://www.apache.org/>. * * * * ========================================================================= */ /** * Description: AJP14 next generation Bi-directional protocol. * Backward compatible with Ajp13 * Author: Henri Gomez <[EMAIL PROTECTED]> * Author: Costin <[EMAIL PROTECTED]> * Author: Gal Shachor <[EMAIL PROTECTED]> */ #include "jk_global.h" #include "jk_context.h" #include "jk_pool.h" #include "jk_util.h" #include "jk_msg_buff.h" #include "jk_ajp_common.h" #include "jk_ajp14.h" #include "jk_logger.h" #include "jk_service.h" #include "jk_env.h" /* Ajp14 methods - XXX move to handler abstraction */ int logon(ajp_endpoint_t *ae, jk_logger_t *l); int discovery(ajp_endpoint_t *ae, jk_workerEnv_t *we, jk_logger_t *l); /* -------------------- Method -------------------- */ static int JK_METHOD validate(jk_worker_t *pThis, jk_map_t *props, jk_workerEnv_t *we, jk_logger_t *l) { ajp_worker_t *aw; char * secret_key; int proto=AJP14_PROTO; aw = pThis->worker_private; secret_key = jk_get_worker_secret_key(props, aw->name); if ((!secret_key) || (!strlen(secret_key))) { jk_log(l, JK_LOG_ERROR, "No secretkey, defaulting to unauthenticated AJP13\n"); proto=AJP13_PROTO; aw->proto= AJP13_PROTO; aw->logon= NULL; } if (ajp_validate(pThis, props, we, l, proto) == JK_FALSE) return JK_FALSE; /* jk_log(l, JK_LOG_DEBUG, "Into ajp14:validate - secret_key=%s\n", secret_key); */ return JK_TRUE; } static int JK_METHOD get_endpoint(jk_worker_t *pThis, jk_endpoint_t **pend, jk_logger_t *l) { ajp_worker_t *aw=pThis->worker_private; if( aw->login->secret_key ==NULL ) { return (ajp_get_endpoint(pThis, pend, l, AJP13_PROTO)); } else { return (ajp_get_endpoint(pThis, pend, l, AJP14_PROTO)); } } static int JK_METHOD init(jk_worker_t *pThis, jk_map_t *props, jk_workerEnv_t *we, jk_logger_t *l) { ajp_worker_t *aw=pThis->worker_private; ajp_endpoint_t *ae; jk_endpoint_t *je; int rc; char * secret_key; int proto=AJP14_PROTO; secret_key = jk_get_worker_secret_key(props, aw->name); if( secret_key==NULL ) { proto=AJP13_PROTO; aw->proto= AJP13_PROTO; aw->logon= NULL; } else { /* Set Secret Key (used at logon time) */ aw->login->secret_key = strdup(secret_key); } if (ajp_init(pThis, props, we, l, proto) == JK_FALSE) return JK_FALSE; if (aw->login->secret_key == NULL) { /* No extra initialization for AJP13 */ return JK_TRUE; } /* -------------------- Ajp14 discovery -------------------- */ /* Set WebServerName (used at logon time) */ aw->login->web_server_name = strdup(we->server_name); if (aw->login->web_server_name == NULL) { jk_log(l, JK_LOG_ERROR, "can't malloc web_server_name\n"); return JK_FALSE; } if (get_endpoint(pThis, &je, l) == JK_FALSE) return JK_FALSE; ae = je->endpoint_private; if (ajp_connect_to_endpoint(ae, l) == JK_TRUE) { /* connection stage passed - try to get context info * this is the long awaited autoconf feature :) */ rc = discovery(ae, we, l); ajp_close_endpoint(ae, l); return rc; } return JK_TRUE; } static int JK_METHOD destroy(jk_worker_t **pThis, jk_logger_t *l) { ajp_worker_t *aw = (*pThis)->worker_private; if (aw->login != NULL && aw->login->secret_key != NULL ) { /* Ajp14-specific initialization */ if (aw->login->web_server_name) { free(aw->login->web_server_name); aw->login->web_server_name = NULL; } if (aw->login->secret_key) { free(aw->login->secret_key); aw->login->secret_key = NULL; } free(aw->login); aw->login = NULL; return (ajp_destroy(pThis, l, AJP14_PROTO)); } else { return (ajp_destroy(pThis, l, AJP13_PROTO)); } } int JK_METHOD jk_worker_ajp14_factory( jk_env_t *env, void **result, char *type, char *name) { jk_logger_t *l=env->logger; jk_worker_t **w=result; ajp_worker_t *aw = (ajp_worker_t *)malloc(sizeof(ajp_worker_t)); jk_log(l, JK_LOG_DEBUG, "Into ajp14_worker_factory\n"); if (name == NULL || w == NULL) { jk_log(l, JK_LOG_ERROR, "In ajp14_worker_factory, NULL parameters\n"); return JK_FALSE; } if (! aw) { jk_log(l, JK_LOG_ERROR, "In ajp14_worker_factory, malloc of private data failed\n"); return JK_FALSE; } aw->name = strdup(name); if (! aw->name) { free(aw); jk_log(l, JK_LOG_ERROR, "In ajp14_worker_factory, malloc failed for name\n"); return JK_FALSE; } aw->proto= AJP14_PROTO; aw->login= (jk_login_service_t *)malloc(sizeof(jk_login_service_t)); if (aw->login == NULL) { jk_log(l, JK_LOG_ERROR, "In ajp14_worker_factory, malloc failed for login area\n"); return JK_FALSE; } memset(aw->login, 0, sizeof(jk_login_service_t)); aw->login->negociation= (AJP14_CONTEXT_INFO_NEG | AJP14_PROTO_SUPPORT_AJP14_NEG); aw->login->web_server_name=NULL; /* must be set in init */ aw->ep_cache_sz= 0; aw->ep_cache= NULL; aw->connect_retry_attempts= AJP_DEF_RETRY_ATTEMPTS; aw->worker.worker_private= aw; aw->worker.validate= validate; aw->worker.init= init; aw->worker.get_endpoint= get_endpoint; aw->worker.destroy=destroy; aw->logon= logon; *w = &aw->worker; return JK_TRUE; } 1.1 jakarta-tomcat-connectors/jk/native2/common/jk_jni_worker.c Index: jk_jni_worker.c =================================================================== /* ========================================================================= * * * * The Apache Software License, Version 1.1 * * * * Copyright (c) 1999-2001 The Apache Software Foundation. * * All rights reserved. * * * * ========================================================================= * * * * Redistribution and use in source and binary forms, with or without modi- * * fication, are permitted provided that the following conditions are met: * * * * 1. Redistributions of source code must retain the above copyright notice * * 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. * * * * 3. The end-user documentation included with the redistribution, if any, * * must include the following acknowlegement: * * * * "This product includes software developed by the Apache Software * * Foundation <http://www.apache.org/>." * * * * Alternately, this acknowlegement may appear in the software itself, if * * and wherever such third-party acknowlegements normally appear. * * * * 4. The names "The Jakarta Project", "Jk", and "Apache Software * * Foundation" must not be used to endorse or promote products derived * * from this software without prior written permission. For written * * permission, please contact <[EMAIL PROTECTED]>. * * * * 5. Products derived from this software may not be called "Apache" nor may * * "Apache" appear in their names without prior written permission of the * * Apache Software Foundation. * * * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR ITS 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. * * * * ========================================================================= * * * * This software consists of voluntary contributions made by many indivi- * * duals on behalf of the Apache Software Foundation. For more information * * on the Apache Software Foundation, please see <http://www.apache.org/>. * * * * ========================================================================= */ /*************************************************************************** * Description: In process JNI worker * * Author: Gal Shachor <[EMAIL PROTECTED]> * * Based on: * * Version: $Revision: 1.1 $ * ***************************************************************************/ #if !defined(WIN32) && !defined(NETWARE) #include <dlfcn.h> #endif #include <jni.h> #include "jk_pool.h" #include "jk_util.h" #include "jk_env.h" #if defined LINUX && defined APACHE2_SIGHACK #include <pthread.h> #include <signal.h> #include <bits/signum.h> #endif #ifdef NETWARE #include <nwthread.h> #include <nwadv.h> #endif #include "jk_logger.h" #include "jk_service.h" #ifndef JNI_VERSION_1_1 #define JNI_VERSION_1_1 0x00010001 #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; jint (JNICALL *jni_get_created_java_vms)(JavaVM **, int, int *) = NULL; #define JAVA_BRIDGE_CLASS_NAME ("org/apache/tomcat/modules/server/JNIEndpoint") /* #define 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; /* * 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); #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 static int JK_METHOD service(jk_endpoint_t *e, jk_ws_service_t *s, jk_logger_t *l, int *is_recoverable_error) { jni_endpoint_t *p; jint rc; jk_log(l, JK_LOG_DEBUG, "Into service\n"); if(!e || !e->endpoint_private || !s) { jk_log(l, JK_LOG_EMERG, "In service, assert failed - invalid parameters\n"); return JK_FALSE; } p = e->endpoint_private; if(!is_recoverable_error) { return JK_FALSE; } if(!p->attached) { /* Try to attach */ if(!(p->env = attach_to_jvm(p->worker, l))) { jk_log(l, JK_LOG_EMERG, "Attach failed\n"); /* Is it recoverable ?? */ *is_recoverable_error = JK_TRUE; 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 !!! */ *is_recoverable_error = JK_FALSE; jk_log(l, JK_LOG_DEBUG, "In service, calling Tomcat...\n"); 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. */ (jlong)(int)s, (jlong)(int)l); /* [V] Righ now JNIEndpoint::service() only returns 1 or 0 */ if(rc) { jk_log(l, JK_LOG_DEBUG, "In service, Tomcat returned OK, done\n"); return JK_TRUE; } else { jk_log(l, JK_LOG_ERROR, "In service, Tomcat FAILED!\n"); return JK_FALSE; } } static int JK_METHOD done(jk_endpoint_t **e, jk_logger_t *l) { jni_endpoint_t *p; jk_log(l, JK_LOG_DEBUG, "Into done\n"); if(!e || !*e || !(*e)->endpoint_private) { jk_log(l, JK_LOG_EMERG, "In done, assert failed - invalid parameters\n"); return JK_FALSE; } p = (*e)->endpoint_private; if(p->attached) { detach_from_jvm(p->worker,l); } free(p); *e = NULL; jk_log(l, JK_LOG_DEBUG, "Done ok\n"); return JK_TRUE; } static int JK_METHOD validate(jk_worker_t *pThis, jk_map_t *props, jk_workerEnv_t *we, jk_logger_t *l) { jni_worker_t *p; int mem_config = 0; char *str_config = NULL; JNIEnv *env; jk_log(l, JK_LOG_DEBUG, "Into validate\n"); if(! pThis || ! pThis->worker_private) { jk_log(l, JK_LOG_EMERG, "In validate, assert failed - invalid parameters\n"); return JK_FALSE; } p = pThis->worker_private; if(p->was_verified) { jk_log(l, JK_LOG_DEBUG, "validate, been here before, done\n"); 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, "Fail-> no classpath\n"); return JK_FALSE; } 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, "Fail-> no jvm_dll_path\n"); 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\n", 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, "Fail-> can't load jvm dll\n"); /* [V] no detach needed here */ return JK_FALSE; } if(!open_jvm(p, &env, l)) { jk_log(l, JK_LOG_EMERG, "Fail-> can't open jvm\n"); /* [V] no detach needed here */ return JK_FALSE; } if(!get_bridge_object(p, env, l)) { jk_log(l, JK_LOG_EMERG, "Fail-> can't get bridge object\n"); /* [V] the detach here may segfault on 1.1 JVM... */ detach_from_jvm(p, l); return JK_FALSE; } if(!get_method_ids(p, env, l)) { jk_log(l, JK_LOG_EMERG, "Fail-> can't get method ids\n"); /* [V] the detach here may segfault on 1.1 JVM... */ detach_from_jvm(p, l); return JK_FALSE; } p->was_verified = JK_TRUE; p->tmp_env = env; jk_log(l, JK_LOG_DEBUG, "Done validate\n"); return JK_TRUE; } static int JK_METHOD init(jk_worker_t *pThis, jk_map_t *props, jk_workerEnv_t *we, jk_logger_t *l) { jni_worker_t *p; JNIEnv *env; jk_log(l, JK_LOG_DEBUG, "Into init\n"); if(! pThis || ! pThis->worker_private) { jk_log(l, JK_LOG_EMERG, "In init, assert failed - invalid parameters\n"); return JK_FALSE; } p = pThis->worker_private; if(p->was_initialized) { jk_log(l, JK_LOG_DEBUG, "init, done (been here!)\n"); 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, "Fail-> worker not set completely\n"); 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 = NULL; jstring stdout_name = NULL; jstring stderr_name = NULL; jint rc = 0; if(p->tomcat_cmd_line) { cmd_line = (*env)->NewStringUTF(env, p->tomcat_cmd_line); } if(p->stdout_name) { stdout_name = (*env)->NewStringUTF(env, p->stdout_name); } if(p->stdout_name) { stderr_name = (*env)->NewStringUTF(env, p->stderr_name); } jk_log(l, JK_LOG_DEBUG, "In init, calling Tomcat to intialize itself...\n"); 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, "In init, Tomcat initialized OK, done\n"); return JK_TRUE; } else { jk_log(l, JK_LOG_EMERG, "Fail-> could not initialize Tomcat\n"); return JK_FALSE; } } else { jk_log(l, JK_LOG_ERROR, "In init, FIXME: init didn't gen env from validate!\n"); 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 = (jni_endpoint_t *)malloc(sizeof(jni_endpoint_t)); jk_log(l, JK_LOG_DEBUG, "Into get_endpoint\n"); if(!pThis || ! pThis->worker_private || !pend) { jk_log(l, JK_LOG_EMERG, "In get_endpoint, assert failed - invalid parameters\n"); return JK_FALSE; } 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; p->endpoint.channelData = NULL; *pend = &p->endpoint; return JK_TRUE; } else { jk_log(l, JK_LOG_ERROR, "In get_endpoint, could not allocate endpoint\n"); return JK_FALSE; } } static int JK_METHOD destroy(jk_worker_t **pThis, jk_logger_t *l) { jni_worker_t *p; JNIEnv *env; jk_log(l, JK_LOG_DEBUG, "Into destroy\n"); if(!pThis || !*pThis || ! (*pThis)->worker_private) { jk_log(l, JK_LOG_EMERG, "In destroy, assert failed - invalid parameters\n"); return JK_FALSE; } p = (*pThis)->worker_private; if(!p->jvm) { jk_log(l, JK_LOG_DEBUG, "In destroy, JVM not intantiated\n"); return JK_FALSE; } if(!p->jk_java_bridge_object || ! p->jk_shutdown_method) { jk_log(l, JK_LOG_DEBUG, "In destroy, Tomcat not intantiated\n"); return JK_FALSE; } if((env = attach_to_jvm(p,l))) { jk_log(l, JK_LOG_DEBUG, "In destroy, shutting down Tomcat...\n"); (*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, "Done destroy\n"); return JK_TRUE; } int JK_METHOD jk_worker_jni_factory(jk_env_t *env, void **result, char *type, char *name) { jk_logger_t *l=env->logger; jk_worker_t **w=result; jni_worker_t *private_data; jk_log(l, JK_LOG_DEBUG, "Into jni_worker_factory\n"); if(!name || !w) { jk_log(l, JK_LOG_EMERG, "In jni_worker_factory, assert failed - invalid parameters\n"); return JK_FALSE; } if(the_singleton_jni_worker) { jk_log(l, JK_LOG_DEBUG, "In jni_worker_factory, instance already created\n"); *w = the_singleton_jni_worker; return JK_TRUE; } private_data = (jni_worker_t *)malloc(sizeof(jni_worker_t )); if(!private_data) { jk_log(l, JK_LOG_ERROR, "In jni_worker_factory, memory allocation error\n"); return JK_FALSE; } 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, "In jni_worker_factory, memory allocation error\n"); jk_close_pool(&private_data->p); free(private_data); return JK_FALSE; } 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 = NULL; private_data->jk_java_bridge_class = NULL; private_data->jk_startup_method = NULL; private_data->jk_service_method = NULL; private_data->jk_shutdown_method = NULL; private_data->tomcat_cmd_line = NULL; private_data->tomcat_classpath = NULL; 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_log(l, JK_LOG_DEBUG, "Done jni_worker_factory\n"); return JK_TRUE; } 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\n"); 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) 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; } #else void *handle; jk_log(l, JK_LOG_DEBUG, "Into load_jvm_dll, load %s\n", 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\n", 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"); if(jni_create_java_vm && jni_get_default_java_vm_init_args) { jk_log(l, JK_LOG_DEBUG, "In load_jvm_dll, symbols resolved, done\n"); return JK_TRUE; } jk_log(l, JK_LOG_EMERG, "Can't resolve JNI_CreateJavaVM or JNI_GetDefaultJavaVMInitArgs\n"); 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_log(l, JK_LOG_DEBUG, "Into open_jvm1\n"); vm_args.version = JNI_VERSION_1_1; if(0 != jni_get_default_java_vm_init_args(&vm_args)) { jk_log(l, JK_LOG_EMERG, "Fail-> can't get default vm init args\n"); return JK_FALSE; } jk_log(l, JK_LOG_DEBUG, "In open_jvm_dll, got default jvm args\n"); if(vm_args.classpath) { unsigned 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", p->tomcat_classpath, PATH_SEPERATOR, vm_args.classpath); p->tomcat_classpath = tmp; } else { jk_log(l, JK_LOG_EMERG, "Fail-> allocation error for classpath\n"); 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) { vm_args.properties = p->sysprops; } jk_log(l, JK_LOG_DEBUG, "In open_jvm1, about to create JVM...\n"); if((err=jni_create_java_vm(&(p->jvm), &penv, &vm_args)) != 0) { jk_log(l, JK_LOG_EMERG, "Fail-> could not create JVM, code: %d \n", err); return JK_FALSE; } jk_log(l, JK_LOG_DEBUG, "In open_jvm1, JVM created, done\n"); *env = penv; 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_log(l, JK_LOG_DEBUG, "Into detect_jvm_version\n"); /* [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, "Fail-> can't get default vm init args\n"); return JK_FALSE; } jk_log(l, JK_LOG_DEBUG, "In detect_jvm_version, found: %X, done\n", vm_args.version); return vm_args.version; } static char* build_opt_str(jk_pool_t *p, char* opt_name, char* opt_value, jk_logger_t *l) { unsigned 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, "Fail-> build_opt_str allocation error for %s\n", 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 */ unsigned 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, "Fail-> build_opt_int allocation error for %s\n", opt_name); return NULL; } } static int open_jvm2(jni_worker_t *p, JNIEnv **env, jk_logger_t *l) { JavaVMInitArgs vm_args; JNIEnv *penv; JavaVMOption options[100]; int optn = 0, err; char* tmp; *env = NULL; jk_log(l, JK_LOG_DEBUG, "Into open_jvm2\n"); vm_args.version = JNI_VERSION_1_2; vm_args.options = options; if(p->tomcat_classpath) { jk_log(l, JK_LOG_DEBUG, "In open_jvm2, setting classpath to %s\n", p->tomcat_classpath); tmp = build_opt_str(&p->p, "-Djava.class.path=", p->tomcat_classpath, l); null_check(tmp); options[optn++].optionString = tmp; } if(p->tomcat_mx) { jk_log(l, JK_LOG_DEBUG, "In open_jvm2, setting max heap to %d\n", p->tomcat_mx); tmp = build_opt_int(&p->p, "-Xmx", p->tomcat_mx, l); null_check(tmp); options[optn++].optionString = tmp; } if(p->tomcat_ms) { jk_log(l, JK_LOG_DEBUG, "In open_jvm2, setting start heap to %d\n", p->tomcat_ms); tmp = build_opt_int(&p->p, "-Xms", p->tomcat_ms, l); null_check(tmp); options[optn++].optionString = tmp; } if(p->sysprops) { int i = 0; while(p->sysprops[i]) { jk_log(l, JK_LOG_DEBUG, "In open_jvm2, setting %s\n", p->sysprops[i]); tmp = build_opt_str(&p->p, "-D", p->sysprops[i], l); null_check(tmp); options[optn++].optionString = tmp; i++; } } if(p->java2opts) { int i=0; while(p->java2opts[i]) { jk_log(l, JK_LOG_DEBUG, "In open_jvm2, using option: %s\n", p->java2opts[i]); /* Pass it "as is" */ options[optn++].optionString = p->java2opts[i++]; } } vm_args.nOptions = optn; if(p->java2lax) { jk_log(l, JK_LOG_DEBUG, "In open_jvm2, the JVM will ignore unknown options\n"); vm_args.ignoreUnrecognized = JNI_TRUE; } else { jk_log(l, JK_LOG_DEBUG, "In open_jvm2, the JVM will FAIL if it finds unknown options\n"); vm_args.ignoreUnrecognized = JNI_FALSE; } jk_log(l, JK_LOG_DEBUG, "In open_jvm2, about to create JVM...\n"); if((err=jni_create_java_vm(&(p->jvm), &penv, &vm_args)) != 0) { jk_log(l, JK_LOG_EMERG, "Fail-> could not create JVM, code: %d \n", err); return JK_FALSE; } jk_log(l, JK_LOG_DEBUG, "In open_jvm2, JVM created, done\n"); *env = penv; return JK_TRUE; } #endif static int get_bridge_object(jni_worker_t *p, JNIEnv *env, jk_logger_t *l) { jmethodID constructor_method_id; jk_log(l, JK_LOG_DEBUG, "Into get_bridge_object\n"); p->jk_java_bridge_class = (*env)->FindClass(env, JAVA_BRIDGE_CLASS_NAME); if(!p->jk_java_bridge_class) { jk_log(l, JK_LOG_EMERG, "Can't find class %s\n", JAVA_BRIDGE_CLASS_NAME); return JK_FALSE; } jk_log(l, JK_LOG_DEBUG, "In get_bridge_object, loaded %s bridge class\n", JAVA_BRIDGE_CLASS_NAME); constructor_method_id = (*env)->GetMethodID(env, p->jk_java_bridge_class, "<init>", /* method name */ "()V"); /* method sign */ if(!constructor_method_id) { p->jk_java_bridge_class = NULL; jk_log(l, JK_LOG_EMERG, "Can't find constructor\n"); 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 = NULL; jk_log(l, JK_LOG_EMERG, "Can't create new bridge object\n"); 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\n"); p->jk_java_bridge_class = NULL; p->jk_java_bridge_object = NULL; return JK_FALSE; } jk_log(l, JK_LOG_DEBUG, "In get_bridge_object, bridge built, done\n"); return JK_TRUE; } static int get_method_ids(jni_worker_t *p, JNIEnv *env, jk_logger_t *l) { p->jk_startup_method = (*env)->GetMethodID(env, p->jk_java_bridge_class, "startup", "(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()\n"); return JK_FALSE; } p->jk_service_method = (*env)->GetMethodID(env, p->jk_java_bridge_class, "service", "(JJ)I"); if(!p->jk_service_method) { jk_log(l, JK_LOG_EMERG, "Can't find service()\n"); return JK_FALSE; } p->jk_shutdown_method = (*env)->GetMethodID(env, p->jk_java_bridge_class, "shutdown", "()V"); if(!p->jk_shutdown_method) { jk_log(l, JK_LOG_EMERG, "Can't find shutdown()\n"); 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_log(l, JK_LOG_DEBUG, "Into attach_to_jvm\n"); #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\n"); return rc; } jk_log(l, JK_LOG_ERROR, "In attach_to_jvm, cannot attach thread to JVM.\n"); 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) { if(!p->jvm || !(*(p->jvm))) { jk_log(l, JK_LOG_ERROR, "In detach_from_jvm, cannot detach from NULL JVM.\n"); } if(0 == (*(p->jvm))->DetachCurrentThread(p->jvm)) { jk_log(l, JK_LOG_DEBUG, "In detach_from_jvm, detached ok\n"); } else { jk_log(l, JK_LOG_ERROR, "In detach_from_jvm, cannot detach from JVM.\n"); } } 1.1 jakarta-tomcat-connectors/jk/native2/common/jk_lb_worker.c Index: jk_lb_worker.c =================================================================== /* ========================================================================= * * * * The Apache Software License, Version 1.1 * * * * Copyright (c) 1999-2001 The Apache Software Foundation. * * All rights reserved. * * * * ========================================================================= * * * * Redistribution and use in source and binary forms, with or without modi- * * fication, are permitted provided that the following conditions are met: * * * * 1. Redistributions of source code must retain the above copyright notice * * 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. * * * * 3. The end-user documentation included with the redistribution, if any, * * must include the following acknowlegement: * * * * "This product includes software developed by the Apache Software * * Foundation <http://www.apache.org/>." * * * * Alternately, this acknowlegement may appear in the software itself, if * * and wherever such third-party acknowlegements normally appear. * * * * 4. The names "The Jakarta Project", "Jk", and "Apache Software * * Foundation" must not be used to endorse or promote products derived * * from this software without prior written permission. For written * * permission, please contact <[EMAIL PROTECTED]>. * * * * 5. Products derived from this software may not be called "Apache" nor may * * "Apache" appear in their names without prior written permission of the * * Apache Software Foundation. * * * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR ITS 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. * * * * ========================================================================= * * * * This software consists of voluntary contributions made by many indivi- * * duals on behalf of the Apache Software Foundation. For more information * * on the Apache Software Foundation, please see <http://www.apache.org/>. * * * * ========================================================================= */ /*************************************************************************** * Description: Load balancer worker, knows how to load balance among * * several workers. * * Author: Gal Shachor <[EMAIL PROTECTED]> * * Based on: * * Version: $Revision: 1.1 $ * ***************************************************************************/ #include "jk_pool.h" #include "jk_service.h" #include "jk_util.h" #include "jk_worker.h" #include "jk_logger.h" #include "jk_env.h" int JK_METHOD lb_worker_factory(jk_worker_t **w, const char *name, jk_logger_t *l); /* * The load balancing code in this */ /* * Time to wait before retry... */ #define WAIT_BEFORE_RECOVER (60*1) #define ADDITINAL_WAIT_LOAD (20) struct worker_record { char *name; double lb_factor; double lb_value; int in_error_state; int in_recovering; time_t error_time; jk_worker_t *w; }; typedef struct worker_record worker_record_t; struct lb_worker { worker_record_t *lb_workers; unsigned num_of_workers; jk_pool_t p; jk_pool_atom_t buf[TINY_POOL_SIZE]; char *name; jk_worker_t worker; }; typedef struct lb_worker lb_worker_t; struct lb_endpoint { jk_endpoint_t *e; lb_worker_t *worker; jk_endpoint_t endpoint; }; typedef struct lb_endpoint lb_endpoint_t; /* ========================================================================= */ /* Retrieve the parameter with the given name */ static char *get_path_param(jk_ws_service_t *s, const char *name) { char *id_start = NULL; for(id_start = strstr(s->req_uri, name) ; id_start ; id_start = strstr(id_start + 1, name)) { if('=' == id_start[strlen(name)]) { /* * Session path-cookie was found, get it's value */ id_start += (1 + strlen(name)); if(strlen(id_start)) { char *id_end; id_start = jk_pool_strdup(s->pool, id_start); /* * The query string is not part of req_uri, however * to be on the safe side lets remove the trailing query * string if appended... */ if(id_end = strchr(id_start, '?')) { *id_end = '\0'; } return id_start; } } } return NULL; } /* ========================================================================= */ /* Retrieve the cookie with the given name */ static char *get_cookie(jk_ws_service_t *s, const char *name) { unsigned i; for(i = 0 ; i < s->num_headers ; i++) { if(0 == strcasecmp(s->headers_names[i], "cookie")) { char *id_start; for(id_start = strstr(s->headers_values[i], name) ; id_start ; id_start = strstr(id_start + 1, name)) { if('=' == id_start[strlen(name)]) { /* * Session cookie was found, get it's value */ id_start += (1 + strlen(name)); if(strlen(id_start)) { char *id_end; id_start = jk_pool_strdup(s->pool, id_start); if(id_end = strchr(id_start, ';')) { *id_end = '\0'; } return id_start; } } } } } return NULL; } /* ========================================================================= */ /* Retrieve session id from the cookie or the parameter */ /* (parameter first) */ static char *get_sessionid(jk_ws_service_t *s) { char *val; val = get_path_param(s, JK_PATH_SESSION_IDENTIFIER); if(!val) { val = get_cookie(s, JK_SESSION_IDENTIFIER); } return val; } static char *get_session_route(jk_ws_service_t *s) { char *sessionid = get_sessionid(s); char *ch; if(!sessionid) { return NULL; } /* * Balance parameter is appended to the end */ ch = strrchr(sessionid, '.'); if(!ch) { return 0; } ch++; if(*ch == '\0') { return NULL; } return ch; } static void close_workers(lb_worker_t *p, int num_of_workers, jk_logger_t *l) { int i = 0; for(i = 0 ; i < num_of_workers ; i++) { p->lb_workers[i].w->destroy(&(p->lb_workers[i].w), l); } } static double get_max_lb(lb_worker_t *p) { unsigned i; double rc = 0.0; for(i = 0 ; i < p->num_of_workers ; i++) { if(!p->lb_workers[i].in_error_state) { if(p->lb_workers[i].lb_value > rc) { rc = p->lb_workers[i].lb_value; } } } return rc; } static worker_record_t *get_most_suitable_worker(lb_worker_t *p, jk_ws_service_t *s) { worker_record_t *rc = NULL; double lb_min = 0.0; unsigned i; char *session_route = get_session_route(s); if(session_route) { for(i = 0 ; i < p->num_of_workers ; i++) { if(0 == strcmp(session_route, p->lb_workers[i].name)) { if(p->lb_workers[i].in_error_state) { break; } else { return &(p->lb_workers[i]); } } } } for(i = 0 ; i < p->num_of_workers ; i++) { if(p->lb_workers[i].in_error_state) { if(!p->lb_workers[i].in_recovering) { time_t now = time(0); if((now - p->lb_workers[i].error_time) > WAIT_BEFORE_RECOVER) { p->lb_workers[i].in_recovering = JK_TRUE; p->lb_workers[i].error_time = now; rc = &(p->lb_workers[i]); break; } } } else { if(p->lb_workers[i].lb_value < lb_min || !rc) { lb_min = p->lb_workers[i].lb_value; rc = &(p->lb_workers[i]); } } } if(rc) { rc->lb_value += rc->lb_factor; } return rc; } static int JK_METHOD service(jk_endpoint_t *e, jk_ws_service_t *s, jk_logger_t *l, int *is_recoverable_error) { jk_log(l, JK_LOG_DEBUG, "Into jk_endpoint_t::service\n"); if(e && e->endpoint_private && s && is_recoverable_error) { lb_endpoint_t *p = e->endpoint_private; jk_endpoint_t *end = NULL; /* you can not recover on another load balancer */ *is_recoverable_error = JK_FALSE; while(1) { worker_record_t *rec = get_most_suitable_worker(p->worker, s); int rc; if(rec) { int is_recoverable = JK_FALSE; s->jvm_route = jk_pool_strdup(s->pool, rec->name); rc = rec->w->get_endpoint(rec->w, &end, l); if(rc && end) { int src = end->service(end, s, l, &is_recoverable); end->done(&end, l); if(src) { if(rec->in_recovering) { rec->lb_value = get_max_lb(p->worker) + ADDITINAL_WAIT_LOAD; } rec->in_error_state = JK_FALSE; rec->in_recovering = JK_FALSE; rec->error_time = 0; return JK_TRUE; } } /* * Service failed !!! * * Time for fault tolerance (if possible)... */ rec->in_error_state = JK_TRUE; rec->in_recovering = JK_FALSE; rec->error_time = time(0); if(!is_recoverable) { /* * Error is not recoverable - break with an error. */ jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::service, none recoverable error...\n"); break; } /* * Error is recoverable by submitting the request to * another worker... Lets try to do that. */ jk_log(l, JK_LOG_DEBUG, "In jk_endpoint_t::service, recoverable error... will try to recover on other host\n"); } else { /* NULL record, no more workers left ... */ jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::service, No more workers left, can not submit the request\n"); break; } } } jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::service: NULL Parameters\n"); return JK_FALSE; } static int JK_METHOD done(jk_endpoint_t **e, jk_logger_t *l) { jk_log(l, JK_LOG_DEBUG, "Into jk_endpoint_t::done\n"); if(e && *e && (*e)->endpoint_private) { lb_endpoint_t *p = (*e)->endpoint_private; if(p->e) { p->e->done(&p->e, l); } free(p); *e = NULL; return JK_TRUE; } jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::done: NULL Parameters\n"); return JK_FALSE; } static int JK_METHOD validate(jk_worker_t *pThis, jk_map_t *props, jk_workerEnv_t *we, jk_logger_t *l) { int err; jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::validate\n"); if(pThis && pThis->worker_private) { lb_worker_t *p = pThis->worker_private; char **worker_names; unsigned num_of_workers; if(jk_get_lb_worker_list(props, p->name, &worker_names, &num_of_workers) && num_of_workers) { unsigned i = 0; p->lb_workers = jk_pool_alloc(&p->p, num_of_workers * sizeof(worker_record_t)); if(!p->lb_workers) { return JK_FALSE; } for(i = 0 ; i < num_of_workers ; i++) { p->lb_workers[i].name = jk_pool_strdup(&p->p, worker_names[i]); p->lb_workers[i].lb_factor = jk_get_lb_factor(props, worker_names[i]); p->lb_workers[i].lb_factor = 1/p->lb_workers[i].lb_factor; /* * Allow using lb in fault-tolerant mode. * Just set lbfactor in worker.properties to 0 to have * a worker used only when principal is down or session route * point to it. Provided by Paul Frieden <[EMAIL PROTECTED]> */ p->lb_workers[i].lb_value = p->lb_workers[i].lb_factor; p->lb_workers[i].in_error_state = JK_FALSE; p->lb_workers[i].in_recovering = JK_FALSE; p->lb_workers[i].w= pThis->workerEnv->createWorker( pThis->workerEnv, p->lb_workers[i].name, props ); if( p->lb_workers[i].w == NULL ) { break; } } if(i != num_of_workers) { close_workers(p, i, l); jk_log(l, JK_LOG_ERROR, "In jk_worker_t::validate: Failed to create worker %s\n", p->lb_workers[i].name); } else { p->num_of_workers = num_of_workers; return JK_TRUE; } } } jk_log(l, JK_LOG_ERROR, "In jk_worker_t::validate: NULL Parameters\n"); return JK_FALSE; } static int JK_METHOD init(jk_worker_t *pThis, jk_map_t *props, jk_workerEnv_t *we, jk_logger_t *log) { /* Nothing to do for now */ return JK_TRUE; } static int JK_METHOD get_endpoint(jk_worker_t *pThis, jk_endpoint_t **pend, jk_logger_t *l) { jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::get_endpoint\n"); if(pThis && pThis->worker_private && pend) { lb_endpoint_t *p = (lb_endpoint_t *)malloc(sizeof(lb_endpoint_t)); if(p) { p->e = NULL; p->worker = pThis->worker_private; p->endpoint.endpoint_private = p; p->endpoint.service = service; p->endpoint.done = done; p->endpoint.channelData = NULL; *pend = &p->endpoint; return JK_TRUE; } jk_log(l, JK_LOG_ERROR, "In jk_worker_t::get_endpoint, malloc failed\n"); } else { jk_log(l, JK_LOG_ERROR, "In jk_worker_t::get_endpoint, NULL parameters\n"); } return JK_FALSE; } static int JK_METHOD destroy(jk_worker_t **pThis, jk_logger_t *l) { jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::destroy\n"); if(pThis && *pThis && (*pThis)->worker_private) { lb_worker_t *private_data = (*pThis)->worker_private; close_workers(private_data, private_data->num_of_workers, l); jk_close_pool(&private_data->p); free(private_data); return JK_TRUE; } jk_log(l, JK_LOG_ERROR, "In jk_worker_t::destroy, NULL parameters\n"); return JK_FALSE; } int JK_METHOD jk_worker_lb_factory(jk_env_t *env, void **result, char *type, char *name) { jk_logger_t *l=env->logger; jk_worker_t **w=result; lb_worker_t *private_data; jk_log(l, JK_LOG_DEBUG, "Into lb_worker_factory\n"); if(NULL != name && NULL != w) { jk_log(l, JK_LOG_ERROR,"In lb_worker_factory, NULL parameters\n"); return JK_FALSE; } private_data = (lb_worker_t *)malloc(sizeof(lb_worker_t)); if(!private_data) { jk_log(l, JK_LOG_ERROR,"In lb_worker_factory, malloc failed\n"); return JK_FALSE; } 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,"In lb_worker_factory, malloc failed\n"); jk_close_pool(&private_data->p); free(private_data); return JK_FALSE; } private_data->lb_workers = NULL; private_data->num_of_workers = 0; 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; return JK_TRUE; }
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>