You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@apache.org on 2001/12/01 23:37:29 UTC
cvs commit: jakarta-tomcat-connectors/jk/native2/common jk_ajp14_worker.c jk_jni_worker.c jk_lb_worker.c
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 <ap...@apache.org>. *
* *
* 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 <hg...@slib.fr>
* Author: Costin <co...@costin.dnt.ro>
* Author: Gal Shachor <sh...@il.ibm.com>
*/
#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 <ap...@apache.org>. *
* *
* 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 <sh...@il.ibm.com> *
* 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 <ap...@apache.org>. *
* *
* 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 <sh...@il.ibm.com> *
* 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 <pf...@dchain.com>
*/
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: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>