diff options
Diffstat (limited to 'rubbos/app/tomcat-connectors-1.2.32-src/native/common')
125 files changed, 28552 insertions, 0 deletions
diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.indent.pro b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.indent.pro new file mode 100644 index 00000000..87ca4192 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.indent.pro @@ -0,0 +1,18 @@ +-i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1 -nut -ncs +-Tjk_env_t +-Tjk_worker_t +-Tjk_worker_env_t +-Tjk_endpoint_t +-Tjk_channel_t +-Tjk_sockbuf_t +-Tjk_msg_t +-Tjk_msg_buf_t +-Tjk_map_t +-Tjk_uri_worker_map_t +-Tjk_pool_t +-Tjk_pool_atom_t +-Tjk_logger_t +-Tjk_ws_service_t +-Tjk_context_item_t +-Tjk_context_t +-Tjk_login_service_t diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp12_worker.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp12_worker.o Binary files differnew file mode 100644 index 00000000..43f069c5 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp12_worker.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp13.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp13.o Binary files differnew file mode 100644 index 00000000..65a3b17c --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp13.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp13_worker.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp13_worker.o Binary files differnew file mode 100644 index 00000000..6964abbf --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp13_worker.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp14.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp14.o Binary files differnew file mode 100644 index 00000000..052f3ef2 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp14.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp14_worker.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp14_worker.o Binary files differnew file mode 100644 index 00000000..87fafdbf --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp14_worker.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp_common.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp_common.o Binary files differnew file mode 100644 index 00000000..a20eca35 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp_common.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_connect.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_connect.o Binary files differnew file mode 100644 index 00000000..007bd0d3 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_connect.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_context.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_context.o Binary files differnew file mode 100644 index 00000000..48f29a7d --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_context.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_jni_worker.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_jni_worker.o Binary files differnew file mode 100644 index 00000000..01dc3d23 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_jni_worker.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_lb_worker.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_lb_worker.o Binary files differnew file mode 100644 index 00000000..ed0cc246 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_lb_worker.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_map.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_map.o Binary files differnew file mode 100644 index 00000000..4ccd1aac --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_map.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_md5.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_md5.o Binary files differnew file mode 100644 index 00000000..b9780541 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_md5.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_msg_buff.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_msg_buff.o Binary files differnew file mode 100644 index 00000000..7b0c05b4 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_msg_buff.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_pool.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_pool.o Binary files differnew file mode 100644 index 00000000..52c12aa9 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_pool.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_shm.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_shm.o Binary files differnew file mode 100644 index 00000000..96025d9f --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_shm.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_sockbuf.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_sockbuf.o Binary files differnew file mode 100644 index 00000000..248f7d0c --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_sockbuf.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_status.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_status.o Binary files differnew file mode 100644 index 00000000..763f6b40 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_status.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_uri_worker_map.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_uri_worker_map.o Binary files differnew file mode 100644 index 00000000..3d1c5b53 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_uri_worker_map.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_url.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_url.o Binary files differnew file mode 100644 index 00000000..c0d52ee0 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_url.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_util.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_util.o Binary files differnew file mode 100644 index 00000000..0bfdc8b4 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_util.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_worker.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_worker.o Binary files differnew file mode 100644 index 00000000..e6530d0d --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_worker.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/Makefile b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/Makefile new file mode 100644 index 00000000..880168d8 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/Makefile @@ -0,0 +1,49 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#### XXXX DO we need this Makefile ???? +srcdir = . +top_srcdir = .. + +prefix = /usr/local +exec_prefix = ${prefix} +APXSLDFLAGS= +APXSCFLAGS= -g -O2 -pthread -DHAVE_APR -I/bottlenecks/rubbos/app/httpd-2.0.64/srclib/apr/include -I/bottlenecks/rubbos/app/httpd-2.0.64/srclib/apr-util/include -DHAVE_CONFIG_H -DHAVE_JNI +APXSCPPFLAGS=-D_REENTRANT -D_GNU_SOURCE + +top_builddir = .. + +LIBTOOL = /bin/bash /bottlenecks/rubbos/app/apache2/build/libtool --silent +CC = gcc + +OEXT=.lo +include list.mk + +JAVA_INCL=-I /bottlenecks/rubbos/app/jdk1.6.0_27/include -I /bottlenecks/rubbos/app/jdk1.6.0_27/include/linux +CFLAGS=-I/bottlenecks/rubbos/app/apache2/include -DHAVE_CONFIG_H -DHAVE_JNI ${APXSCFLAGS} ${APXSCPPFLAGS} ${JAVA_INCL} + +include ../scripts/build/rules.mk + +JK=./ + +all: ${APACHE_OBJECTS} + +install: + +clean: + rm -f *.o *.lo *.a *.la *.so *.so.* *.slo + rm -rf .libs + +maintainer-clean: clean diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/Makefile.in b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/Makefile.in new file mode 100644 index 00000000..4304ae5f --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/Makefile.in @@ -0,0 +1,49 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#### XXXX DO we need this Makefile ???? +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +APXSLDFLAGS=@APXSLDFLAGS@ +APXSCFLAGS=@APXSCFLAGS@ +APXSCPPFLAGS=@APXSCPPFLAGS@ + +top_builddir = .. + +LIBTOOL = @LIBTOOL@ +CC = @CC@ + +OEXT=.lo +include list.mk + +JAVA_INCL=-I @JAVA_HOME@/include -I @JAVA_HOME@/include/@OS@ +CFLAGS=@apache_include@ @CFLAGS@ ${APXSCFLAGS} ${APXSCPPFLAGS} ${JAVA_INCL} + +include @top_srcdir@/scripts/build/rules.mk + +JK=./ + +all: ${APACHE_OBJECTS} + +install: + +clean: + rm -f *.o *.lo *.a *.la *.so *.so.* *.slo + rm -rf .libs + +maintainer-clean: clean diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/ap_snprintf.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/ap_snprintf.c new file mode 100644 index 00000000..18b539de --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/ap_snprintf.c @@ -0,0 +1,1178 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This code is based on, and used with the permission of, the + * SIO stdio-replacement strx_* functions by Panos Tsirigotis + * <panos@alumni.cs.colorado.edu> for xinetd. + */ +#define BUILD_STANDALONE + +#ifndef BUILD_STANDALONE +#include "httpd.h" +#else +#include "ap_snprintf.h" +#endif + +#include <stdio.h> +#include <ctype.h> +#ifndef NETWARE +#include <sys/types.h> +#endif +#include <stdarg.h> +#include <string.h> +#include <stdlib.h> +#include <math.h> +#ifdef WIN32 +#include <float.h> +#endif + +typedef enum { + NO = 0, YES = 1 +} boolean_e; + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef AP_LONGEST_LONG +#define AP_LONGEST_LONG long +#endif +#define NUL '\0' +#define WIDE_INT long +#define WIDEST_INT AP_LONGEST_LONG + +typedef WIDE_INT wide_int; +typedef unsigned WIDE_INT u_wide_int; +typedef WIDEST_INT widest_int; +#ifdef __TANDEM +/* Although Tandem supports "long long" there is no unsigned variant. */ +typedef unsigned long u_widest_int; +#else +typedef unsigned WIDEST_INT u_widest_int; +#endif +typedef int bool_int; + +#define S_NULL "(null)" +#define S_NULL_LEN 6 + +#define FLOAT_DIGITS 6 +#define EXPONENT_LENGTH 10 + +/* + * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions + * + * XXX: this is a magic number; do not decrease it + */ +#define NUM_BUF_SIZE 512 + +/* + * cvt - IEEE floating point formatting routines. + * Derived from UNIX V7, Copyright(C) Caldera International Inc. + */ + +/* + * ap_ecvt converts to decimal + * the number of digits is specified by ndigit + * decpt is set to the position of the decimal point + * sign is set to 0 for positive, 1 for negative + */ + +#define NDIG 80 + +/* buf must have at least NDIG bytes */ +static char *ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag, char *buf) +{ + register int r2; + double fi, fj; + register char *p, *p1; + + if (ndigits >= NDIG - 1) + ndigits = NDIG - 2; + r2 = 0; + *sign = 0; + p = &buf[0]; + if (arg < 0) { + *sign = 1; + arg = -arg; + } + arg = modf(arg, &fi); + p1 = &buf[NDIG]; + /* + * Do integer part + */ + if (fi != 0) { + p1 = &buf[NDIG]; + while (p1 > &buf[0] && fi != 0) { + fj = modf(fi / 10, &fi); + *--p1 = (int) ((fj + .03) * 10) + '0'; + r2++; + } + while (p1 < &buf[NDIG]) + *p++ = *p1++; + } + else if (arg > 0) { + while ((fj = arg * 10) < 1) { + arg = fj; + r2--; + } + } + p1 = &buf[ndigits]; + if (eflag == 0) + p1 += r2; + *decpt = r2; + if (p1 < &buf[0]) { + buf[0] = '\0'; + return (buf); + } + while (p <= p1 && p < &buf[NDIG]) { + arg *= 10; + arg = modf(arg, &fj); + *p++ = (int) fj + '0'; + } + if (p1 >= &buf[NDIG]) { + buf[NDIG - 1] = '\0'; + return (buf); + } + p = p1; + *p1 += 5; + while (*p1 > '9') { + *p1 = '0'; + if (p1 > buf) + ++ * --p1; + else { + *p1 = '1'; + (*decpt)++; + if (eflag == 0) { + if (p > buf) + *p = '0'; + p++; + } + } + } + *p = '\0'; + return (buf); +} + +static char *ap_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return (ap_cvt(arg, ndigits, decpt, sign, 1, buf)); +} + +static char *ap_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return (ap_cvt(arg, ndigits, decpt, sign, 0, buf)); +} + +/* + * ap_gcvt - Floating output conversion to + * minimal length string + */ + +static char *ap_gcvt(double number, int ndigit, char *buf, boolean_e altform) +{ + int sign, decpt; + register char *p1, *p2; + register int i; + char buf1[NDIG]; + + p1 = ap_ecvt(number, ndigit, &decpt, &sign, buf1); + p2 = buf; + if (sign) + *p2++ = '-'; + for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--) + ndigit--; + if ((decpt >= 0 && decpt - ndigit > 4) + || (decpt < 0 && decpt < -3)) { /* use E-style */ + decpt--; + *p2++ = *p1++; + *p2++ = '.'; + for (i = 1; i < ndigit; i++) + *p2++ = *p1++; + *p2++ = 'e'; + if (decpt < 0) { + decpt = -decpt; + *p2++ = '-'; + } + else + *p2++ = '+'; + if (decpt / 100 > 0) + *p2++ = decpt / 100 + '0'; + if (decpt / 10 > 0) + *p2++ = (decpt % 100) / 10 + '0'; + *p2++ = decpt % 10 + '0'; + } + else { + if (decpt <= 0) { + if (*p1 != '0') + *p2++ = '.'; + while (decpt < 0) { + decpt++; + *p2++ = '0'; + } + } + for (i = 1; i <= ndigit; i++) { + *p2++ = *p1++; + if (i == decpt) + *p2++ = '.'; + } + if (ndigit < decpt) { + while (ndigit++ < decpt) + *p2++ = '0'; + *p2++ = '.'; + } + } + if (p2[-1] == '.' && !altform) + p2--; + *p2 = '\0'; + return (buf); +} + +/* + * The INS_CHAR macro inserts a character in the buffer and writes + * the buffer back to disk if necessary + * It uses the char pointers sp and bep: + * sp points to the next available character in the buffer + * bep points to the end-of-buffer+1 + * While using this macro, note that the nextb pointer is NOT updated. + * + * NOTE: Evaluation of the c argument should not have any side-effects + */ +#define INS_CHAR(c, sp, bep, cc) \ + { \ + if (sp >= bep) { \ + vbuff->curpos = sp; \ + if (flush_func(vbuff)) \ + return -1; \ + sp = vbuff->curpos; \ + bep = vbuff->endpos; \ + } \ + *sp++ = (c); \ + cc++; \ + } + +#define NUM( c ) ( c - '0' ) + +#define STR_TO_DEC( str, num ) \ + num = NUM( *str++ ) ; \ + while ( ap_isdigit( *str ) ) \ + { \ + num *= 10 ; \ + num += NUM( *str++ ) ; \ + } + +/* + * This macro does zero padding so that the precision + * requirement is satisfied. The padding is done by + * adding '0's to the left of the string that is going + * to be printed. We don't allow precision to be large + * enough that we continue past the start of s. + * + * NOTE: this makes use of the magic info that s is + * always based on num_buf with a size of NUM_BUF_SIZE. + */ +#define FIX_PRECISION( adjust, precision, s, s_len ) \ + if ( adjust ) { \ + int p = precision < NUM_BUF_SIZE - 1 ? precision : NUM_BUF_SIZE - 1; \ + while ( s_len < p ) \ + { \ + *--s = '0' ; \ + s_len++ ; \ + } \ + } + +/* + * Macro that does padding. The padding is done by printing + * the character ch. + */ +#define PAD( width, len, ch ) do \ + { \ + INS_CHAR( ch, sp, bep, cc ) ; \ + width-- ; \ + } \ + while ( width > len ) + +/* + * Prefix the character ch to the string str + * Increase length + * Set the has_prefix flag + */ +#define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YES + + +/* + * Convert num to its decimal format. + * Return value: + * - a pointer to a string containing the number (no sign) + * - len contains the length of the string + * - is_negative is set to TRUE or FALSE depending on the sign + * of the number (always set to FALSE if is_unsigned is TRUE) + * + * The caller provides a buffer for the string: that is the buf_end argument + * which is a pointer to the END of the buffer + 1 (i.e. if the buffer + * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) + * + * Note: we have 2 versions. One is used when we need to use quads + * (conv_10_quad), the other when we don't (conv_10). We're assuming the + * latter is faster. + */ +static char *conv_10(register wide_int num, register bool_int is_unsigned, + register bool_int *is_negative, char *buf_end, + register int *len) +{ + register char *p = buf_end; + register u_wide_int magnitude; + + if (is_unsigned) { + magnitude = (u_wide_int) num; + *is_negative = FALSE; + } + else { + *is_negative = (num < 0); + + /* + * On a 2's complement machine, negating the most negative integer + * results in a number that cannot be represented as a signed integer. + * Here is what we do to obtain the number's magnitude: + * a. add 1 to the number + * b. negate it (becomes positive) + * c. convert it to unsigned + * d. add 1 + */ + if (*is_negative) { + wide_int t = num + 1; + + magnitude = ((u_wide_int) -t) + 1; + } + else + magnitude = (u_wide_int) num; + } + + /* + * We use a do-while loop so that we write at least 1 digit + */ + do { + register u_wide_int new_magnitude = magnitude / 10; + + *--p = (char) (magnitude - new_magnitude * 10 + '0'); + magnitude = new_magnitude; + } + while (magnitude); + + *len = buf_end - p; + return (p); +} + +static char *conv_10_quad(widest_int num, register bool_int is_unsigned, + register bool_int *is_negative, char *buf_end, + register int *len) +{ + register char *p = buf_end; + u_widest_int magnitude; + + /* + * We see if we can use the faster non-quad version by checking the + * number against the largest long value it can be. If <=, we + * punt to the quicker version. + */ + if ((num <= ULONG_MAX && is_unsigned) || (num <= LONG_MAX && !is_unsigned)) + return(conv_10( (wide_int)num, is_unsigned, is_negative, + buf_end, len)); + + if (is_unsigned) { + magnitude = (u_widest_int) num; + *is_negative = FALSE; + } + else { + *is_negative = (num < 0); + + /* + * On a 2's complement machine, negating the most negative integer + * results in a number that cannot be represented as a signed integer. + * Here is what we do to obtain the number's magnitude: + * a. add 1 to the number + * b. negate it (becomes positive) + * c. convert it to unsigned + * d. add 1 + */ + if (*is_negative) { + widest_int t = num + 1; + + magnitude = ((u_widest_int) -t) + 1; + } + else + magnitude = (u_widest_int) num; + } + + /* + * We use a do-while loop so that we write at least 1 digit + */ + do { + u_widest_int new_magnitude = magnitude / 10; + + *--p = (char) (magnitude - new_magnitude * 10 + '0'); + magnitude = new_magnitude; + } + while (magnitude); + + *len = buf_end - p; + return (p); +} + + + +#ifndef BUILD_STANDALONE +static char *conv_in_addr(struct in_addr *ia, char *buf_end, int *len) +{ + unsigned addr = ntohl(ia->s_addr); + char *p = buf_end; + bool_int is_negative; + int sub_len; + + p = conv_10((addr & 0x000000FF) , TRUE, &is_negative, p, &sub_len); + *--p = '.'; + p = conv_10((addr & 0x0000FF00) >> 8, TRUE, &is_negative, p, &sub_len); + *--p = '.'; + p = conv_10((addr & 0x00FF0000) >> 16, TRUE, &is_negative, p, &sub_len); + *--p = '.'; + p = conv_10((addr & 0xFF000000) >> 24, TRUE, &is_negative, p, &sub_len); + + *len = buf_end - p; + return (p); +} + + + +static char *conv_sockaddr_in(struct sockaddr_in *si, char *buf_end, int *len) +{ + char *p = buf_end; + bool_int is_negative; + int sub_len; + + p = conv_10(ntohs(si->sin_port), TRUE, &is_negative, p, &sub_len); + *--p = ':'; + p = conv_in_addr(&si->sin_addr, p, &sub_len); + + *len = buf_end - p; + return (p); +} +#endif + + +/* + * Convert a floating point number to a string formats 'f', 'e' or 'E'. + * The result is placed in buf, and len denotes the length of the string + * The sign is returned in the is_negative argument (and is not placed + * in buf). + */ +static char *conv_fp(register char format, register double num, + boolean_e add_dp, int precision, bool_int *is_negative, + char *buf, int *len) +{ + register char *s = buf; + register char *p; + int decimal_point; + char buf1[NDIG]; + + if (format == 'f') + p = ap_fcvt(num, precision, &decimal_point, is_negative, buf1); + else /* either e or E format */ + p = ap_ecvt(num, precision + 1, &decimal_point, is_negative, buf1); + + /* + * Check for Infinity and NaN + */ + if (ap_isalpha(*p)) { + *len = strlen(strcpy(buf, p)); + *is_negative = FALSE; + return (buf); + } + + if (format == 'f') { + if (decimal_point <= 0) { + *s++ = '0'; + if (precision > 0) { + *s++ = '.'; + while (decimal_point++ < 0) + *s++ = '0'; + } + else if (add_dp) + *s++ = '.'; + } + else { + while (decimal_point-- > 0) + *s++ = *p++; + if (precision > 0 || add_dp) + *s++ = '.'; + } + } + else { + *s++ = *p++; + if (precision > 0 || add_dp) + *s++ = '.'; + } + + /* + * copy the rest of p, the NUL is NOT copied + */ + while (*p) + *s++ = *p++; + + if (format != 'f') { + char temp[EXPONENT_LENGTH]; /* for exponent conversion */ + int t_len; + bool_int exponent_is_negative; + + *s++ = format; /* either e or E */ + decimal_point--; + if (decimal_point != 0) { + p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative, + &temp[EXPONENT_LENGTH], &t_len); + *s++ = exponent_is_negative ? '-' : '+'; + + /* + * Make sure the exponent has at least 2 digits + */ + if (t_len == 1) + *s++ = '0'; + while (t_len--) + *s++ = *p++; + } + else { + *s++ = '+'; + *s++ = '0'; + *s++ = '0'; + } + } + + *len = s - buf; + return (buf); +} + + +/* + * Convert num to a base X number where X is a power of 2. nbits determines X. + * For example, if nbits is 3, we do base 8 conversion + * Return value: + * a pointer to a string containing the number + * + * The caller provides a buffer for the string: that is the buf_end argument + * which is a pointer to the END of the buffer + 1 (i.e. if the buffer + * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) + * + * As with conv_10, we have a faster version which is used when + * the number isn't quad size. + */ +static char *conv_p2(register u_wide_int num, register int nbits, + char format, char *buf_end, register int *len) +{ + register int mask = (1 << nbits) - 1; + register char *p = buf_end; + static const char low_digits[] = "0123456789abcdef"; + static const char upper_digits[] = "0123456789ABCDEF"; + register const char *digits = (format == 'X') ? upper_digits : low_digits; + + do { + *--p = digits[num & mask]; + num >>= nbits; + } + while (num); + + *len = buf_end - p; + return (p); +} + +static char *conv_p2_quad(u_widest_int num, register int nbits, + char format, char *buf_end, register int *len) +{ + register int mask = (1 << nbits) - 1; + register char *p = buf_end; + static const char low_digits[] = "0123456789abcdef"; + static const char upper_digits[] = "0123456789ABCDEF"; + register const char *digits = (format == 'X') ? upper_digits : low_digits; + + if (num <= ULONG_MAX) + return(conv_p2( (u_wide_int)num, nbits, format, buf_end, len)); + + do { + *--p = digits[num & mask]; + num >>= nbits; + } + while (num); + + *len = buf_end - p; + return (p); +} + + +/* + * Do format conversion placing the output in buffer + */ +API_EXPORT(int) ap_vformatter(int (*flush_func)(ap_vformatter_buff *), + ap_vformatter_buff *vbuff, const char *fmt, va_list ap) +{ + register char *sp; + register char *bep; + register int cc = 0; + register int i; + + register char *s = NULL; + char *q; + int s_len; + + register int min_width = 0; + int precision = 0; + enum { + LEFT, RIGHT + } adjust; + char pad_char; + char prefix_char; + + double fp_num; + widest_int i_quad = (widest_int) 0; + u_widest_int ui_quad; + wide_int i_num = (wide_int) 0; + u_wide_int ui_num; + + char num_buf[NUM_BUF_SIZE]; + char char_buf[2]; /* for printing %% and %<unknown> */ + + enum var_type_enum { + IS_QUAD, IS_LONG, IS_SHORT, IS_INT + }; + enum var_type_enum var_type = IS_INT; + + /* + * Flag variables + */ + boolean_e alternate_form; + boolean_e print_sign; + boolean_e print_blank; + boolean_e adjust_precision; + boolean_e adjust_width; + bool_int is_negative; + + sp = vbuff->curpos; + bep = vbuff->endpos; + + while (*fmt) { + if (*fmt != '%') { + INS_CHAR(*fmt, sp, bep, cc); + } + else { + /* + * Default variable settings + */ + adjust = RIGHT; + alternate_form = print_sign = print_blank = NO; + pad_char = ' '; + prefix_char = NUL; + + fmt++; + + /* + * Try to avoid checking for flags, width or precision + */ + if (!ap_islower(*fmt)) { + /* + * Recognize flags: -, #, BLANK, + + */ + for (;; fmt++) { + if (*fmt == '-') + adjust = LEFT; + else if (*fmt == '+') + print_sign = YES; + else if (*fmt == '#') + alternate_form = YES; + else if (*fmt == ' ') + print_blank = YES; + else if (*fmt == '0') + pad_char = '0'; + else + break; + } + + /* + * Check if a width was specified + */ + if (ap_isdigit(*fmt)) { + STR_TO_DEC(fmt, min_width); + adjust_width = YES; + } + else if (*fmt == '*') { + min_width = va_arg(ap, int); + fmt++; + adjust_width = YES; + if (min_width < 0) { + adjust = LEFT; + min_width = -min_width; + } + } + else + adjust_width = NO; + + /* + * Check if a precision was specified + */ + if (*fmt == '.') { + adjust_precision = YES; + fmt++; + if (ap_isdigit(*fmt)) { + STR_TO_DEC(fmt, precision); + } + else if (*fmt == '*') { + precision = va_arg(ap, int); + fmt++; + if (precision < 0) + precision = 0; + } + else + precision = 0; + } + else + adjust_precision = NO; + } + else + adjust_precision = adjust_width = NO; + + /* + * Modifier check + */ + if (*fmt == 'q') { + var_type = IS_QUAD; + fmt++; + } + else if (*fmt == 'l') { + var_type = IS_LONG; + fmt++; + } + else if (*fmt == 'h') { + var_type = IS_SHORT; + fmt++; + } + else { + var_type = IS_INT; + } + + /* + * Argument extraction and printing. + * First we determine the argument type. + * Then, we convert the argument to a string. + * On exit from the switch, s points to the string that + * must be printed, s_len has the length of the string + * The precision requirements, if any, are reflected in s_len. + * + * NOTE: pad_char may be set to '0' because of the 0 flag. + * It is reset to ' ' by non-numeric formats + */ + switch (*fmt) { + case 'u': + if (var_type == IS_QUAD) { + i_quad = va_arg(ap, u_widest_int); + s = conv_10_quad(i_quad, 1, &is_negative, + &num_buf[NUM_BUF_SIZE], &s_len); + } + else { + if (var_type == IS_LONG) + i_num = (wide_int) va_arg(ap, u_wide_int); + else if (var_type == IS_SHORT) + i_num = (wide_int) (unsigned short) va_arg(ap, unsigned int); + else + i_num = (wide_int) va_arg(ap, unsigned int); + s = conv_10(i_num, 1, &is_negative, + &num_buf[NUM_BUF_SIZE], &s_len); + } + FIX_PRECISION(adjust_precision, precision, s, s_len); + break; + + case 'd': + case 'i': + if (var_type == IS_QUAD) { + i_quad = va_arg(ap, widest_int); + s = conv_10_quad(i_quad, 0, &is_negative, + &num_buf[NUM_BUF_SIZE], &s_len); + } + else { + if (var_type == IS_LONG) + i_num = (wide_int) va_arg(ap, wide_int); + else if (var_type == IS_SHORT) + i_num = (wide_int) (short) va_arg(ap, int); + else + i_num = (wide_int) va_arg(ap, int); + s = conv_10(i_num, 0, &is_negative, + &num_buf[NUM_BUF_SIZE], &s_len); + } + FIX_PRECISION(adjust_precision, precision, s, s_len); + + if (is_negative) + prefix_char = '-'; + else if (print_sign) + prefix_char = '+'; + else if (print_blank) + prefix_char = ' '; + break; + + + case 'o': + if (var_type == IS_QUAD) { + ui_quad = va_arg(ap, u_widest_int); + s = conv_p2_quad(ui_quad, 3, *fmt, + &num_buf[NUM_BUF_SIZE], &s_len); + } + else { + if (var_type == IS_LONG) + ui_num = (u_wide_int) va_arg(ap, u_wide_int); + else if (var_type == IS_SHORT) + ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int); + else + ui_num = (u_wide_int) va_arg(ap, unsigned int); + s = conv_p2(ui_num, 3, *fmt, + &num_buf[NUM_BUF_SIZE], &s_len); + } + FIX_PRECISION(adjust_precision, precision, s, s_len); + if (alternate_form && *s != '0') { + *--s = '0'; + s_len++; + } + break; + + + case 'x': + case 'X': + if (var_type == IS_QUAD) { + ui_quad = va_arg(ap, u_widest_int); + s = conv_p2_quad(ui_quad, 4, *fmt, + &num_buf[NUM_BUF_SIZE], &s_len); + } + else { + if (var_type == IS_LONG) + ui_num = (u_wide_int) va_arg(ap, u_wide_int); + else if (var_type == IS_SHORT) + ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int); + else + ui_num = (u_wide_int) va_arg(ap, unsigned int); + s = conv_p2(ui_num, 4, *fmt, + &num_buf[NUM_BUF_SIZE], &s_len); + } + FIX_PRECISION(adjust_precision, precision, s, s_len); + if (alternate_form && i_num != 0) { + *--s = *fmt; /* 'x' or 'X' */ + *--s = '0'; + s_len += 2; + } + break; + + + case 's': + s = va_arg(ap, char *); + if (s != NULL) { + s_len = strlen(s); + if (adjust_precision && precision < s_len) + s_len = precision; + } + else { + s = S_NULL; + s_len = S_NULL_LEN; + } + pad_char = ' '; + break; + + + case 'f': + case 'e': + case 'E': + fp_num = va_arg(ap, double); + /* + * * We use &num_buf[ 1 ], so that we have room for the sign + */ +#ifdef HAVE_ISNAN + if (isnan(fp_num)) { + s = "nan"; + s_len = 3; + } + else +#endif +#ifdef HAVE_ISINF + if (isinf(fp_num)) { + s = "inf"; + s_len = 3; + } + else +#endif + { + s = conv_fp(*fmt, fp_num, alternate_form, + (adjust_precision == NO) ? FLOAT_DIGITS : precision, + &is_negative, &num_buf[1], &s_len); + if (is_negative) + prefix_char = '-'; + else if (print_sign) + prefix_char = '+'; + else if (print_blank) + prefix_char = ' '; + } + break; + + + case 'g': + case 'G': + if (adjust_precision == NO) + precision = FLOAT_DIGITS; + else if (precision == 0) + precision = 1; + /* + * * We use &num_buf[ 1 ], so that we have room for the sign + */ + s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1], + alternate_form); + if (*s == '-') + prefix_char = *s++; + else if (print_sign) + prefix_char = '+'; + else if (print_blank) + prefix_char = ' '; + + s_len = strlen(s); + + if (alternate_form && (q = strchr(s, '.')) == NULL) { + s[s_len++] = '.'; + s[s_len] = '\0'; /* delimit for following strchr() */ + } + if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL) + *q = 'E'; + break; + + + case 'c': + char_buf[0] = (char) (va_arg(ap, int)); + s = &char_buf[0]; + s_len = 1; + pad_char = ' '; + break; + + + case '%': + char_buf[0] = '%'; + s = &char_buf[0]; + s_len = 1; + pad_char = ' '; + break; + + + case 'n': + if (var_type == IS_QUAD) + *(va_arg(ap, widest_int *)) = cc; + else if (var_type == IS_LONG) + *(va_arg(ap, long *)) = cc; + else if (var_type == IS_SHORT) + *(va_arg(ap, short *)) = cc; + else + *(va_arg(ap, int *)) = cc; + break; + + /* + * This is where we extend the printf format, with a second + * type specifier + */ + case 'p': + switch(*++fmt) { + /* + * If the pointer size is equal to or smaller than the size + * of the largest unsigned int, we convert the pointer to a + * hex number, otherwise we print "%p" to indicate that we + * don't handle "%p". + */ + case 'p': +#ifdef AP_VOID_P_IS_QUAD + if (sizeof(void *) <= sizeof(u_widest_int)) { + ui_quad = (u_widest_int) va_arg(ap, void *); + s = conv_p2_quad(ui_quad, 4, 'x', + &num_buf[NUM_BUF_SIZE], &s_len); + } +#else + if (sizeof(void *) <= sizeof(u_wide_int)) { + ui_num = (u_wide_int) va_arg(ap, void *); + s = conv_p2(ui_num, 4, 'x', + &num_buf[NUM_BUF_SIZE], &s_len); + } +#endif + else { + s = "%p"; + s_len = 2; + prefix_char = NUL; + } + pad_char = ' '; + break; + +#ifndef BUILD_STANDALONE + /* print a struct sockaddr_in as a.b.c.d:port */ + case 'I': + { + struct sockaddr_in *si; + + si = va_arg(ap, struct sockaddr_in *); + if (si != NULL) { + s = conv_sockaddr_in(si, &num_buf[NUM_BUF_SIZE], &s_len); + if (adjust_precision && precision < s_len) + s_len = precision; + } + else { + s = S_NULL; + s_len = S_NULL_LEN; + } + pad_char = ' '; + } + break; + + /* print a struct in_addr as a.b.c.d */ + case 'A': + { + struct in_addr *ia; + + ia = va_arg(ap, struct in_addr *); + if (ia != NULL) { + s = conv_in_addr(ia, &num_buf[NUM_BUF_SIZE], &s_len); + if (adjust_precision && precision < s_len) + s_len = precision; + } + else { + s = S_NULL; + s_len = S_NULL_LEN; + } + pad_char = ' '; + } + break; +#endif + + case NUL: + /* if %p ends the string, oh well ignore it */ + continue; + + default: + s = "bogus %p"; + s_len = 8; + prefix_char = NUL; + break; + } + break; + + case NUL: + /* + * The last character of the format string was %. + * We ignore it. + */ + continue; + + + /* + * The default case is for unrecognized %'s. + * We print %<char> to help the user identify what + * option is not understood. + * This is also useful in case the user wants to pass + * the output of format_converter to another function + * that understands some other %<char> (like syslog). + * Note that we can't point s inside fmt because the + * unknown <char> could be preceded by width etc. + */ + default: + char_buf[0] = '%'; + char_buf[1] = *fmt; + s = char_buf; + s_len = 2; + pad_char = ' '; + break; + } + + if (prefix_char != NUL && s != S_NULL && s != char_buf) { + *--s = prefix_char; + s_len++; + } + + if (adjust_width && adjust == RIGHT && min_width > s_len) { + if (pad_char == '0' && prefix_char != NUL) { + INS_CHAR(*s, sp, bep, cc); + s++; + s_len--; + min_width--; + } + PAD(min_width, s_len, pad_char); + } + + /* + * Print the string s. + */ + for (i = s_len; i != 0; i--) { + INS_CHAR(*s, sp, bep, cc); + s++; + } + + if (adjust_width && adjust == LEFT && min_width > s_len) + PAD(min_width, s_len, pad_char); + } + fmt++; + } + vbuff->curpos = sp; + + return cc; +} + + +static int snprintf_flush(ap_vformatter_buff *vbuff) +{ + /* if the buffer fills we have to abort immediately, there is no way + * to "flush" an ap_snprintf... there's nowhere to flush it to. + */ + return -1; +} + + +API_EXPORT_NONSTD(int) ap_snprintf(char *buf, size_t len, const char *format,...) +{ + int cc; + va_list ap; + ap_vformatter_buff vbuff; + + if (len == 0) + return 0; + + /* save one byte for nul terminator */ + vbuff.curpos = buf; + vbuff.endpos = buf + len - 1; + va_start(ap, format); + cc = ap_vformatter(snprintf_flush, &vbuff, format, ap); + va_end(ap); + *vbuff.curpos = '\0'; + return (cc == -1) ? len : cc; +} + + +API_EXPORT(int) ap_vsnprintf(char *buf, size_t len, const char *format, + va_list ap) +{ + int cc; + ap_vformatter_buff vbuff; + + if (len == 0) + return 0; + + /* save one byte for nul terminator */ + vbuff.curpos = buf; + vbuff.endpos = buf + len - 1; + cc = ap_vformatter(snprintf_flush, &vbuff, format, ap); + *vbuff.curpos = '\0'; + return (cc == -1) ? len : cc; +} diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/ap_snprintf.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/ap_snprintf.h new file mode 100644 index 00000000..73b3c6e5 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/ap_snprintf.h @@ -0,0 +1,150 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * The ap_vsnprintf/ap_snprintf functions are based on, and used with the + * permission of, the SIO stdio-replacement strx_* functions by Panos + * Tsirigotis <panos@alumni.cs.colorado.edu> for xinetd. + */ + +#ifndef APACHE_AP_SNPRINTF_H +#define APACHE_AP_SNPRINTF_H + +#include <stdio.h> +#include <stdarg.h> +#include <limits.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* stuff marked API_EXPORT is part of the API, and intended for use + * by modules + */ +#ifndef API_EXPORT +#define API_EXPORT(type) type +#endif + +/* Stuff marked API_EXPORT_NONSTD is part of the API, and intended for + * use by modules. The difference between API_EXPORT and + * API_EXPORT_NONSTD is that the latter is required for any functions + * which use varargs or are used via indirect function call. This + * is to accomodate the two calling conventions in windows dlls. + */ +#ifndef API_EXPORT_NONSTD +#define API_EXPORT_NONSTD(type) type +#endif + +#if !defined(__GNUC__) || __GNUC__ < 2 || \ + (__GNUC__ == 2 && __GNUC_MINOR__ < 7) ||\ + defined(NEXT) +#define __attribute__(__x) +#endif + +/* These macros allow correct support of 8-bit characters on systems which + * support 8-bit characters. Pretty dumb how the cast is required, but + * that's legacy libc for ya. These new macros do not support EOF like + * the standard macros do. Tough. + */ +#define ap_isalpha(c) (isalpha(((unsigned char)(c)))) +#define ap_isdigit(c) (isdigit(((unsigned char)(c)))) +#define ap_islower(c) (islower(((unsigned char)(c)))) + + +/* ap_vformatter() is a generic printf-style formatting routine + * with some extensions. The extensions are: + * + * %pA takes a struct in_addr *, and prints it as a.b.c.d + * %pI takes a struct sockaddr_in * and prints it as a.b.c.d:port + * %pp takes a void * and outputs it in hex + * + * The %p hacks are to force gcc's printf warning code to skip + * over a pointer argument without complaining. This does + * mean that the ANSI-style %p (output a void * in hex format) won't + * work as expected at all, but that seems to be a fair trade-off + * for the increased robustness of having printf-warnings work. + * + * Additionally, ap_vformatter allows for arbitrary output methods + * using the ap_vformatter_buff and flush_func. + * + * The ap_vformatter_buff has two elements curpos and endpos. + * curpos is where ap_vformatter will write the next byte of output. + * It proceeds writing output to curpos, and updating curpos, until + * either the end of output is reached, or curpos == endpos (i.e. the + * buffer is full). + * + * If the end of output is reached, ap_vformatter returns the + * number of bytes written. + * + * When the buffer is full, the flush_func is called. The flush_func + * can return -1 to indicate that no further output should be attempted, + * and ap_vformatter will return immediately with -1. Otherwise + * the flush_func should flush the buffer in whatever manner is + * appropriate, re-initialize curpos and endpos, and return 0. + * + * Note that flush_func is only invoked as a result of attempting to + * write another byte at curpos when curpos >= endpos. So for + * example, it's possible when the output exactly matches the buffer + * space available that curpos == endpos will be true when + * ap_vformatter returns. + * + * ap_vformatter does not call out to any other code, it is entirely + * self-contained. This allows the callers to do things which are + * otherwise "unsafe". For example, ap_psprintf uses the "scratch" + * space at the unallocated end of a block, and doesn't actually + * complete the allocation until ap_vformatter returns. ap_psprintf + * would be completely broken if ap_vformatter were to call anything + * that used a pool. Similarly http_bprintf() uses the "scratch" + * space at the end of its output buffer, and doesn't actually note + * that the space is in use until it either has to flush the buffer + * or until ap_vformatter returns. + */ + +typedef struct { + char *curpos; + char *endpos; +} ap_vformatter_buff; + +API_EXPORT(int) ap_vformatter(int (*flush_func)(ap_vformatter_buff *), + ap_vformatter_buff *, const char *fmt, va_list ap); + +/* These are snprintf implementations based on ap_vformatter(). + * + * Note that various standards and implementations disagree on the return + * value of snprintf, and side-effects due to %n in the formatting string. + * ap_snprintf behaves as follows: + * + * Process the format string until the entire string is exhausted, or + * the buffer fills. If the buffer fills then stop processing immediately + * (so no further %n arguments are processed), and return the buffer + * length. In all cases the buffer is NUL terminated. The return value + * is the number of characters placed in the buffer, excluding the + * terminating NUL. All this implies that, at most, (len-1) characters + * will be copied over; if the return value is >= len, then truncation + * occured. + * + * In no event does ap_snprintf return a negative number. + */ +API_EXPORT_NONSTD(int) ap_snprintf(char *buf, size_t len, const char *format,...) + __attribute__((format(printf,3,4))); +API_EXPORT(int) ap_vsnprintf(char *buf, size_t len, const char *format, + va_list ap); + +#ifdef __cplusplus +} +#endif + +#endif /* !APACHE_AP_SNPRINTF_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/config.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/config.h new file mode 100644 index 00000000..e92dec8d --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/config.h @@ -0,0 +1,110 @@ +/* common/config.h. Generated by configure. */ +/* common/config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the <dlfcn.h> header file. */ +#define HAVE_DLFCN_H 1 + +/* Have flock() */ +#define HAVE_FLOCK 1 + +/* Define to 1 if you have the <inttypes.h> header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the <memory.h> header file. */ +#define HAVE_MEMORY_H 1 + +/* Have poll() */ +#define HAVE_POLL 1 + +/* Define to 1 if you have the <poll.h> header file. */ +#define HAVE_POLL_H 1 + +/* Have snprintf() */ +#define HAVE_SNPRINTF 1 + +/* Define to 1 if you have the <stdint.h> header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the <strings.h> header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the <sys/filio.h> header file. */ +/* #undef HAVE_SYS_FILIO_H */ + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* Have vsnprintf() */ +#define HAVE_VSNPRINTF 1 + +/* Name of package */ +#define PACKAGE "mod_jk" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "" + +/* The size of a `char', as computed by sizeof. */ +#define SIZEOF_CHAR 1 + +/* The size of a `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of a `long', as computed by sizeof. */ +#define SIZEOF_LONG 8 + +/* The size of a `longlong', as computed by sizeof. */ +#define SIZEOF_LONGLONG 0 + +/* The size of a `long double', as computed by sizeof. */ +#define SIZEOF_LONG_DOUBLE 16 + +/* The size of a `long long', as computed by sizeof. */ +#define SIZEOF_LONG_LONG 8 + +/* The size of pid_t */ +#define SIZEOF_PID_T 4 + +/* The size of pthread_t */ +#define SIZEOF_PTHREAD_T 8 + +/* The size of a `short', as computed by sizeof. */ +#define SIZEOF_SHORT 2 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to use SOCK_CLOEXEC with socket() */ +#define USE_SOCK_CLOEXEC 1 + +/* Define to use SO_RCVTIMEO with setsockopt() */ +#define USE_SO_RCVTIMEO 1 + +/* Define to use SO_SNDTIMEO with setsockopt() */ +#define USE_SO_SNDTIMEO 1 + +/* Version number of package */ +#define VERSION "1.2.32" diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/config.h.in b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/config.h.in new file mode 100644 index 00000000..7426f4f6 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/config.h.in @@ -0,0 +1,109 @@ +/* common/config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the <dlfcn.h> header file. */ +#undef HAVE_DLFCN_H + +/* Have flock() */ +#undef HAVE_FLOCK + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Have poll() */ +#undef HAVE_POLL + +/* Define to 1 if you have the <poll.h> header file. */ +#undef HAVE_POLL_H + +/* Have snprintf() */ +#undef HAVE_SNPRINTF + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the <sys/filio.h> header file. */ +#undef HAVE_SYS_FILIO_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Have vsnprintf() */ +#undef HAVE_VSNPRINTF + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* The size of a `char', as computed by sizeof. */ +#undef SIZEOF_CHAR + +/* The size of a `int', as computed by sizeof. */ +#undef SIZEOF_INT + +/* The size of a `long', as computed by sizeof. */ +#undef SIZEOF_LONG + +/* The size of a `longlong', as computed by sizeof. */ +#undef SIZEOF_LONGLONG + +/* The size of a `long double', as computed by sizeof. */ +#undef SIZEOF_LONG_DOUBLE + +/* The size of a `long long', as computed by sizeof. */ +#undef SIZEOF_LONG_LONG + +/* The size of pid_t */ +#undef SIZEOF_PID_T + +/* The size of pthread_t */ +#undef SIZEOF_PTHREAD_T + +/* The size of a `short', as computed by sizeof. */ +#undef SIZEOF_SHORT + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to use SOCK_CLOEXEC with socket() */ +#undef USE_SOCK_CLOEXEC + +/* Define to use SO_RCVTIMEO with setsockopt() */ +#undef USE_SO_RCVTIMEO + +/* Define to use SO_SNDTIMEO with setsockopt() */ +#undef USE_SO_SNDTIMEO + +/* Version number of package */ +#undef VERSION diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk.rc b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk.rc new file mode 100644 index 00000000..e0eae360 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk.rc @@ -0,0 +1,74 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <windows.h> +#include "jk_version.h" + +#define ASF_COPYRIGHT "Licensed to the Apache Software Foundation " \ + "(ASF) under one or more contributor license " \ + "agreements. See the NOTICE file distributed " \ + "with this work for additional information " \ + "regarding copyright ownership." + +#define ASF_LICENSE "The ASF licenses this file to You under the " \ + "Apache License, Version 2.0 (the ""License""); " \ + "you may not use this file except in compliance " \ + "with the License. You may obtain a copy of " \ + "the License at\r\n\r\n" \ + "http://www.apache.org/licenses/LICENSE-2.0\r\n\r\n" \ + "Unless required by applicable law or agreed to in " \ + "writing, software distributed under the License is " \ + "distributed on an ""AS IS"" BASIS, WITHOUT " \ + "WARRANTIES OR CONDITIONS OF ANY KIND, either " \ + "express or implied. See the License for the " \ + "specific language governing permissions and " \ + "limitations under the License." + + +1 VERSIONINFO + FILEVERSION JK_VERSIONCSV + PRODUCTVERSION JK_VERSIONCSV + FILEFLAGSMASK 0x3fL +#if defined(_DEBUG) + FILEFLAGS 0x01L +#else + FILEFLAGS 0x00L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", ASF_LICENSE "\0" + VALUE "CompanyName", "Apache Software Foundation\0" + VALUE "FileDescription", "Apache Tomcat Connector\0" + VALUE "FileVersion", JK_VERSTRING "\0" + VALUE "InternalName", PACKAGE "\0" + VALUE "LegalCopyright", ASF_COPYRIGHT "\0" + VALUE "OriginalFilename", PACKAGE "." JK_DLL_SUFFIX "\0" + VALUE "ProductName", "Apache Tomcat " PACKAGE " Connector\0" + VALUE "ProductVersion", JK_VERSTRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp12_worker.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp12_worker.c new file mode 100644 index 00000000..c10ef0b4 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp12_worker.c @@ -0,0 +1,682 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: ajpv1.2 worker, used to call local or remote jserv hosts * + * This worker is deprecated * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Based on: jserv_ajpv12.c from Jserv * + * Version: $Revision: 747878 $ * + ***************************************************************************/ + +#include "jk_ajp12_worker.h" +#include "jk_pool.h" +#include "jk_connect.h" +#include "jk_util.h" +#include "jk_sockbuf.h" +#if defined(AS400) && !defined(AS400_UTF8) +#include "util_ebcdic.h" +#include <string.h> +#endif + +#define AJP_DEF_HOST ("localhost") +#define AJP_DEF_PORT (8007) +#define READ_BUF_SIZE (8*1024) +#define DEF_RETRY_ATTEMPTS (1) + +struct ajp12_worker +{ + struct sockaddr_in worker_inet_addr; + unsigned connect_retry_attempts; + char *name; + jk_worker_t worker; +}; + +typedef struct ajp12_worker ajp12_worker_t; + +struct ajp12_endpoint +{ + ajp12_worker_t *worker; + + jk_sock_t sd; + jk_sockbuf_t sb; + + jk_endpoint_t endpoint; +}; +typedef struct ajp12_endpoint ajp12_endpoint_t; + +static int ajpv12_mark(ajp12_endpoint_t * p, unsigned char type); + +#if defined(AS400) && !defined(AS400_UTF8) +static int ajpv12_sendasciistring(ajp12_endpoint_t * p, char *buffer); +#endif + +#if defined(AS400) && !defined(AS400_UTF8) +static int ajpv12_sendstring(ajp12_endpoint_t * p, char *buffer); +#else +static int ajpv12_sendstring(ajp12_endpoint_t * p, const char *buffer); +#endif + +static int ajpv12_sendint(ajp12_endpoint_t * p, int d); + +static int ajpv12_sendnbytes(ajp12_endpoint_t * p, + const void *buffer, int bufferlen); + +static int ajpv12_flush(ajp12_endpoint_t * p); + +static int ajpv12_handle_response(ajp12_endpoint_t * p, + jk_ws_service_t *s, jk_logger_t *l); + +static int ajpv12_handle_request(ajp12_endpoint_t * p, + jk_ws_service_t *s, jk_logger_t *l); + +/* + * Return values of service() method for ajp12 worker: + * return value is_error reason + * JK_FALSE JK_HTTP_SERVER_ERROR Invalid parameters (null values) + * Error during connect to the backend + * ajpv12_handle_request() returns false: + * Any error during reading a request body from the client or + * sending the request to the backend + * JK_FALSE JK_HTTP_OK ajpv12_handle_response() returns false: + * Any error during reading parts of response from backend or + * sending to client + * JK_TRUE JK_HTTP_OK All other cases + */ +static int JK_METHOD service(jk_endpoint_t *e, + jk_ws_service_t *s, + jk_logger_t *l, int *is_error) +{ + ajp12_endpoint_t *p; + unsigned int attempt; + int rc = -1; + /* + * AJP12 protocol is not recoverable. + */ + + JK_TRACE_ENTER(l); + + if (!e || !e->endpoint_private || !s || !is_error) { + JK_LOG_NULL_PARAMS(l); + if (is_error) + *is_error = JK_HTTP_SERVER_ERROR; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p = e->endpoint_private; + + /* Set returned error to OK */ + *is_error = JK_HTTP_OK; + + for (attempt = 0; attempt < p->worker->connect_retry_attempts; + attempt++) { + p->sd = + jk_open_socket(&p->worker->worker_inet_addr, + JK_FALSE, 0, 0, 0, l); + + jk_log(l, JK_LOG_DEBUG, "In jk_endpoint_t::service, sd = %d", + p->sd); + if (IS_VALID_SOCKET(p->sd)) { + break; + } + } + if (IS_VALID_SOCKET(p->sd)) { + + jk_sb_open(&p->sb, p->sd); + if (ajpv12_handle_request(p, s, l)) { + jk_log(l, JK_LOG_DEBUG, + "In jk_endpoint_t::service, sent request"); + rc = ajpv12_handle_response(p, s, l); + JK_TRACE_EXIT(l); + return rc; + } + } + jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::service, Error sd = %d", + p->sd); + *is_error = JK_HTTP_SERVER_ERROR; + + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +static int JK_METHOD done(jk_endpoint_t **e, jk_logger_t *l) +{ + jk_log(l, JK_LOG_DEBUG, "Into jk_endpoint_t::done"); + if (e && *e && (*e)->endpoint_private) { + ajp12_endpoint_t *p = (*e)->endpoint_private; + if (IS_VALID_SOCKET(p->sd)) { + jk_shutdown_socket(p->sd, l); + } + free(p); + *e = NULL; + return JK_TRUE; + } + + jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::done, NULL parameters"); + return JK_FALSE; +} + +static int JK_METHOD validate(jk_worker_t *pThis, + jk_map_t *props, + jk_worker_env_t *we, jk_logger_t *l) +{ + jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::validate"); + + if (pThis && pThis->worker_private) { + ajp12_worker_t *p = pThis->worker_private; + int port = jk_get_worker_port(props, + p->name, + AJP_DEF_PORT); + + const char *host = jk_get_worker_host(props, + p->name, + AJP_DEF_HOST); + + jk_log(l, JK_LOG_DEBUG, + "In jk_worker_t::validate for worker %s contact is %s:%d", + p->name, host, port); + + if (host) { + if (jk_resolve(host, port, &p->worker_inet_addr, we->pool, l)) { + return JK_TRUE; + } + jk_log(l, JK_LOG_ERROR, + "In jk_worker_t::validate, resolve failed"); + } + jk_log(l, JK_LOG_ERROR, "In jk_worker_t::validate, Error %s %d", + host, port); + } + else { + jk_log(l, JK_LOG_ERROR, + "In jk_worker_t::validate, NULL parameters"); + } + + return JK_FALSE; +} + +static int JK_METHOD init(jk_worker_t *pThis, + jk_map_t *props, + jk_worker_env_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"); + + if (pThis && pThis->worker_private && pend) { + ajp12_endpoint_t *p = + (ajp12_endpoint_t *) malloc(sizeof(ajp12_endpoint_t)); + if (p) { + p->sd = JK_INVALID_SOCKET; + p->worker = pThis->worker_private; + p->endpoint.endpoint_private = p; + p->endpoint.service = service; + p->endpoint.done = done; + *pend = &p->endpoint; + return JK_TRUE; + } + jk_log(l, JK_LOG_ERROR, + "In jk_worker_t::get_endpoint, malloc failed"); + } + else { + jk_log(l, JK_LOG_ERROR, + "In jk_worker_t::get_endpoint, NULL parameters"); + } + + 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"); + if (pThis && *pThis && (*pThis)->worker_private) { + ajp12_worker_t *private_data = (*pThis)->worker_private; + free(private_data->name); + free(private_data); + + return JK_TRUE; + } + + jk_log(l, JK_LOG_ERROR, "In jk_worker_t::destroy, NULL parameters"); + return JK_FALSE; +} + +int JK_METHOD ajp12_worker_factory(jk_worker_t **w, + const char *name, jk_logger_t *l) +{ + jk_log(l, JK_LOG_DEBUG, "Into ajp12_worker_factory"); + if (NULL != name && NULL != w) { + ajp12_worker_t *private_data = + (ajp12_worker_t *) malloc(sizeof(ajp12_worker_t)); + + if (private_data) { + private_data->name = strdup(name); + + if (private_data->name) { + private_data->connect_retry_attempts = DEF_RETRY_ATTEMPTS; + 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; + private_data->worker.maintain = NULL; + + *w = &private_data->worker; + return JK_AJP12_WORKER_TYPE; + } + + free(private_data); + } + jk_log(l, JK_LOG_ERROR, "In ajp12_worker_factory, malloc failed"); + } + else { + jk_log(l, JK_LOG_ERROR, "In ajp12_worker_factory, NULL parameters"); + } + + return 0; +} + +static int ajpv12_sendnbytes(ajp12_endpoint_t * p, + const void *buffer, int bufferlen) +{ + unsigned char bytes[2]; + static const unsigned char null_b[2] = + { (unsigned char)0xff, (unsigned char)0xff }; + + if (buffer) { + bytes[0] = (unsigned char)((bufferlen >> 8) & 0xff); + bytes[1] = (unsigned char)(bufferlen & 0xff); + + if (jk_sb_write(&p->sb, bytes, 2)) { + return jk_sb_write(&p->sb, buffer, bufferlen); + } + else { + return JK_FALSE; + } + } + else { + return jk_sb_write(&p->sb, null_b, 2); + } +} + +#if defined(AS400) && !defined(AS400_UTF8) +static int ajpv12_sendasciistring(ajp12_endpoint_t * p, const char *buffer) +{ + int bufferlen; + + if (buffer && (bufferlen = strlen(buffer))) { + return ajpv12_sendnbytes(p, buffer, bufferlen); + } + else { + return ajpv12_sendnbytes(p, NULL, 0); + } +} +#endif + +static int ajpv12_sendstring(ajp12_endpoint_t * p, const char *buffer) +{ + int bufferlen; + + if (buffer && (bufferlen = (int)strlen(buffer))) { +#if (defined(AS400) && !defined(AS400_UTF8)) || defined(_OSD_POSIX) + char buf[2048]; + if (bufferlen < 2048) { + memcpy(buf, buffer, bufferlen); + jk_xlate_to_ascii(buf, bufferlen); + return ajpv12_sendnbytes(p, buf, bufferlen); + } + else + return -1; +#else + return ajpv12_sendnbytes(p, buffer, bufferlen); +#endif + } + else { + return ajpv12_sendnbytes(p, NULL, 0); + } +} + +static int ajpv12_mark(ajp12_endpoint_t * p, unsigned char type) +{ + if (jk_sb_write(&p->sb, &type, 1)) { + return JK_TRUE; + } + else { + return JK_FALSE; + } +} + +static int ajpv12_sendint(ajp12_endpoint_t * p, int d) +{ + char buf[20]; + sprintf(buf, "%d", d); + return ajpv12_sendstring(p, buf); +} + +static int ajpv12_flush(ajp12_endpoint_t * p) +{ + return jk_sb_flush(&p->sb); +} + +static int ajpv12_handle_request(ajp12_endpoint_t * p, + jk_ws_service_t *s, jk_logger_t *l) +{ + int ret; + + jk_log(l, JK_LOG_DEBUG, "Into ajpv12_handle_request"); + /* + * Start the ajp 12 service sequence + */ + jk_log(l, JK_LOG_DEBUG, + "ajpv12_handle_request, sending the ajp12 start sequence"); + + ret = (ajpv12_mark(p, 1) && ajpv12_sendstring(p, s->method) && ajpv12_sendstring(p, 0) && /* zone */ + ajpv12_sendstring(p, 0) && /* servlet */ + ajpv12_sendstring(p, s->server_name) && ajpv12_sendstring(p, 0) && /* doc root */ + ajpv12_sendstring(p, 0) && /* path info */ + ajpv12_sendstring(p, 0) && /* path translated */ +#if defined(AS400) && !defined(AS400_UTF8) + ajpv12_sendasciistring(p, s->query_string) && +#else + ajpv12_sendstring(p, s->query_string) && +#endif + ajpv12_sendstring(p, s->remote_addr) && + ajpv12_sendstring(p, s->remote_host) && + ajpv12_sendstring(p, s->remote_user) && + ajpv12_sendstring(p, s->auth_type) && + ajpv12_sendint(p, s->server_port) && +#if defined(AS400) && !defined(AS400_UTF8) + ajpv12_sendasciistring(p, s->method) && +#else + ajpv12_sendstring(p, s->method) && +#endif + ajpv12_sendstring(p, s->req_uri) && ajpv12_sendstring(p, 0) && /* */ + ajpv12_sendstring(p, 0) && /* SCRIPT_NAME */ +#if defined(AS400) && !defined(AS400_UTF8) + ajpv12_sendasciistring(p, s->server_name) && +#else + ajpv12_sendstring(p, s->server_name) && +#endif + ajpv12_sendint(p, s->server_port) && ajpv12_sendstring(p, s->protocol) && ajpv12_sendstring(p, 0) && /* SERVER_SIGNATURE */ + ajpv12_sendstring(p, s->server_software) && ajpv12_sendstring(p, s->route) && /* JSERV_ROUTE */ + ajpv12_sendstring(p, "") && /* JSERV ajpv12 compatibility */ + ajpv12_sendstring(p, "")); /* JSERV ajpv12 compatibility */ + + if (!ret) { + jk_log(l, JK_LOG_ERROR, + "In ajpv12_handle_request, failed to send the ajp12 start sequence"); + return JK_FALSE; + } + + if (s->num_attributes > 0) { + unsigned i; + jk_log(l, JK_LOG_DEBUG, + "ajpv12_handle_request, sending the environment variables"); + + for (i = 0; i < s->num_attributes; i++) { + ret = (ajpv12_mark(p, 5) && + ajpv12_sendstring(p, s->attributes_names[i]) && + ajpv12_sendstring(p, s->attributes_values[i])); + if (!ret) { + jk_log(l, JK_LOG_ERROR, + "In ajpv12_handle_request, failed to send environment"); + return JK_FALSE; + } + } + } + + jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request, sending the headers"); + + /* Send the request headers */ + if (s->num_headers) { + unsigned i; + for (i = 0; i < s->num_headers; ++i) { + ret = (ajpv12_mark(p, 3) && + ajpv12_sendstring(p, s->headers_names[i]) && + ajpv12_sendstring(p, s->headers_values[i])); + + if (!ret) { + jk_log(l, JK_LOG_ERROR, + "In ajpv12_handle_request, failed to send headers"); + return JK_FALSE; + } + } + } + + jk_log(l, JK_LOG_DEBUG, + "ajpv12_handle_request, sending the terminating mark"); + + ret = (ajpv12_mark(p, 4) && ajpv12_flush(p)); + if (!ret) { + jk_log(l, JK_LOG_ERROR, + "In ajpv12_handle_request, failed to send the terminating mark"); + return JK_FALSE; + } + + if (s->content_length) { + char buf[READ_BUF_SIZE]; + jk_uint64_t so_far = 0; + + jk_log(l, JK_LOG_DEBUG, + "ajpv12_handle_request, sending the request body"); + + while (so_far < s->content_length) { + unsigned this_time = 0; + unsigned to_read; + if (s->content_length > so_far + READ_BUF_SIZE) { + to_read = READ_BUF_SIZE; + } + else { + to_read = (unsigned int)(s->content_length - so_far); + } + + if (!s->read(s, buf, to_read, &this_time)) { + jk_log(l, JK_LOG_ERROR, + "In ajpv12_handle_request, failed to read from the web server"); + return JK_FALSE; + } + jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request, read %d bytes", + this_time); + if (this_time > 0) { + so_far += this_time; + if ((int)this_time != send(p->sd, buf, this_time, 0)) { + jk_log(l, JK_LOG_ERROR, + "In ajpv12_handle_request, failed to write to the container"); + return JK_FALSE; + } + jk_log(l, JK_LOG_DEBUG, + "ajpv12_handle_request, sent %d bytes", this_time); + } + else if (this_time == 0) { + jk_log(l, JK_LOG_ERROR, + "In ajpv12_handle_request, Error: short read. content length is %" JK_UINT64_T_FMT ", read %" JK_UINT64_T_FMT, + s->content_length, so_far); + return JK_FALSE; + } + } + } + + jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request done"); + return JK_TRUE; +} + +static int ajpv12_handle_response(ajp12_endpoint_t * p, + jk_ws_service_t *s, jk_logger_t *l) +{ + int status = 200; + char *reason = NULL; + char **names = NULL; + char **values = NULL; + int headers_capacity = 0; + int headers_len = 0; + int write_to_ws; + + jk_log(l, JK_LOG_DEBUG, "Into ajpv12_handle_response"); + /* + * Read headers ... + */ + while (1) { + char *line = NULL; + char *name = NULL; + char *value = NULL; +#ifdef _MT_CODE_PTHREAD + char *lasts; +#endif + + if (!jk_sb_gets(&p->sb, &line)) { + jk_log(l, JK_LOG_ERROR, + "ajpv12_handle_response, error reading header line"); + return JK_FALSE; + } +#if (defined(AS400) && !defined(AS400_UTF8)) || defined(_OSD_POSIX) + jk_xlate_from_ascii(line, strlen(line)); +#endif + + jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, read %s", line); + if (0 == strlen(line)) { + jk_log(l, JK_LOG_DEBUG, + "ajpv12_handle_response, headers are done"); + break; /* Empty line -> end of headers */ + } + + name = line; + while (isspace((int)(*name)) && *name) { + name++; /* Skip leading white chars */ + } + if (!*name) { /* Empty header name */ + jk_log(l, JK_LOG_ERROR, + "ajpv12_handle_response, empty header name"); + return JK_FALSE; + } + if (!(value = strchr(name, ':'))) { + jk_log(l, JK_LOG_ERROR, + "ajpv12_handle_response, no value supplied"); + return JK_FALSE; /* No value !!! */ + } + *value = '\0'; + value++; + while (isspace((int)(*value)) && *value) { + value++; /* Skip leading white chars */ + } + if (!*value) { /* Empty header value */ + jk_log(l, JK_LOG_ERROR, + "ajpv12_handle_response, empty header value"); + return JK_FALSE; + } + + jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, read %s=%s", name, + value); + if (0 == strcmp("Status", name)) { +#ifdef _MT_CODE_PTHREAD + char *numeric = strtok_r(value, " \t", &lasts); +#else + char *numeric = strtok(value, " \t"); +#endif + + status = atoi(numeric); + if (status < 100 || status > 999) { + jk_log(l, JK_LOG_ERROR, + "ajpv12_handle_response, invalid status code"); + return JK_FALSE; + } +#ifdef _MT_CODE_PTHREAD + reason = jk_pool_strdup(s->pool, strtok_r(NULL, " \t", &lasts)); +#else + reason = jk_pool_strdup(s->pool, strtok(NULL, " \t")); +#endif + } + else { + if (headers_capacity == headers_len) { + jk_log(l, JK_LOG_DEBUG, + "ajpv12_handle_response, allocating header arrays"); + names = + (char **)jk_pool_realloc(s->pool, + sizeof(char *) * + (headers_capacity + 5), names, + sizeof(char *) * + headers_capacity); + values = + (char **)jk_pool_realloc(s->pool, + sizeof(char *) * + (headers_capacity + 5), values, + sizeof(char *) * + headers_capacity); + if (!values || !names) { + jk_log(l, JK_LOG_ERROR, + "ajpv12_handle_response, malloc error"); + return JK_FALSE; + } + headers_capacity = headers_capacity + 5; + } + names[headers_len] = jk_pool_strdup(s->pool, name); + values[headers_len] = jk_pool_strdup(s->pool, value); + headers_len++; + } + } + + jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, starting response"); + if (!s->start_response(s, + status, + reason, + (const char *const *)names, + (const char *const *)values, headers_len)) { + jk_log(l, JK_LOG_ERROR, + "ajpv12_handle_response, error starting response"); + return JK_FALSE; + } + + jk_log(l, JK_LOG_DEBUG, + "ajpv12_handle_response, reading response body"); + /* + * Read response body + */ + write_to_ws = JK_TRUE; + while (1) { + unsigned to_read = READ_BUF_SIZE; + unsigned acc = 0; + char *buf = NULL; + + if (!jk_sb_read(&p->sb, &buf, to_read, &acc)) { + jk_log(l, JK_LOG_ERROR, + "ajpv12_handle_response, error reading from "); + return JK_FALSE; + } + + if (!acc) { + jk_log(l, JK_LOG_DEBUG, + "ajpv12_handle_response, response body is done"); + break; + } + + if (write_to_ws) { + if (!s->write(s, buf, acc)) { + jk_log(l, JK_LOG_ERROR, + "ajpv12_handle_response, error writing back to server"); + write_to_ws = JK_FALSE; + } + } + } + + jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response done"); + return JK_TRUE; +} diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp12_worker.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp12_worker.h new file mode 100644 index 00000000..e4e5eaca --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp12_worker.h @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: ajpv1.2 worker header file * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Version: $Revision: 466585 $ * + ***************************************************************************/ + +#ifndef JK_AJP12_WORKER_H +#define JK_AJP12_WORKER_H + +#include "jk_logger.h" +#include "jk_service.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#define JK_AJP12_WORKER_NAME ("ajp12") +#define JK_AJP12_WORKER_TYPE (1) + +int JK_METHOD ajp12_worker_factory(jk_worker_t **w, + const char *name, jk_logger_t *l); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* JK_AJP12_WORKER_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp12_worker.lo b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp12_worker.lo new file mode 100644 index 00000000..9c11bcb9 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp12_worker.lo @@ -0,0 +1,12 @@ +# jk_ajp12_worker.lo - a libtool object file +# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/jk_ajp12_worker.o' + +# Name of the non-PIC object. +non_pic_object='jk_ajp12_worker.o' + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp12_worker.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp12_worker.o Binary files differnew file mode 100644 index 00000000..3ab1134b --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp12_worker.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13.c new file mode 100644 index 00000000..4c16a023 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13.c @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Experimental bi-directionl protocol handler. * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Author: Henri Gomez <hgomez@apache.org> * + * Version: $Revision: 466585 $ * + ***************************************************************************/ + + +#include "jk_global.h" +#include "jk_util.h" +#include "jk_ajp_common.h" +#include "jk_ajp13.h" + +int ajp13_marshal_shutdown_into_msgb(jk_msg_buf_t *msg, + jk_pool_t *p, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + /* To be on the safe side */ + jk_b_reset(msg); + + /* + * Just a single byte with s/d command. + */ + if (jk_b_append_byte(msg, JK_AJP13_SHUTDOWN)) { + jk_log(l, JK_LOG_ERROR, + "failed appending shutdown message"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13.h new file mode 100644 index 00000000..d2a9ab2e --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13.h @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Experimental bi-directionl protocol handler. * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Version: $Revision: 751213 $ * + ***************************************************************************/ +#ifndef JK_AJP13_H +#define JK_AJP13_H + +#include "jk_ajp_common.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#define AJP13_PROTO 13 +#define AJP13_WS_HEADER 0x1234 +#define AJP13_SW_HEADER 0x4142 /* 'AB' */ + +#define AJP13_DEF_HOST ("localhost") +#define AJP13_DEF_PORT (8009) +#define AJP13_READ_BUF_SIZE (8*1024) +#define AJP13_DEF_CACHE_SZ (1) +#define JK_INTERNAL_ERROR (-2) +#define JK_FATAL_ERROR (-3) +#define JK_CLIENT_ERROR (-4) +#define JK_SERVER_ERROR (-5) +#define JK_CLIENT_RD_ERROR (-6) +#define JK_CLIENT_WR_ERROR (-7) +#define JK_STATUS_ERROR (-8) +#define JK_STATUS_FATAL_ERROR (-9) +#define JK_REPLY_TIMEOUT (-10) +#define JK_AJP_PROTOCOL_ERROR (-11) + +#define AJP13_MAX_SEND_BODY_SZ (DEF_BUFFER_SZ - 6) +#define AJP13_DEF_TIMEOUT (0) /* Idle timout for pooled connections */ + +/* + * Message does not have a response (for example, JK_AJP13_END_RESPONSE) + */ +#define JK_AJP13_ERROR -1 +/* + * Message does not have a response (for example, JK_AJP13_END_RESPONSE) + */ +#define JK_AJP13_NO_RESPONSE 0 +/* + * Message have a response. + */ +#define JK_AJP13_HAS_RESPONSE 1 + +/* + * Forward a request from the web server to the servlet container. + */ +#define JK_AJP13_FORWARD_REQUEST (unsigned char)2 + +/* + * Write a body chunk from the servlet container to the web server + */ +#define JK_AJP13_SEND_BODY_CHUNK (unsigned char)3 + +/* + * Send response headers from the servlet container to the web server. + */ +#define JK_AJP13_SEND_HEADERS (unsigned char)4 + +/* + * Marks the end of response. + */ +#define JK_AJP13_END_RESPONSE (unsigned char)5 + +/* + * Marks the end of response. + */ +#define JK_AJP13_GET_BODY_CHUNK (unsigned char)6 + +/* + * Asks the container to shutdown + */ +#define JK_AJP13_SHUTDOWN (unsigned char)7 + +/* + * Told container to take control (secure login phase) + */ +#define AJP13_PING_REQUEST (unsigned char)8 + +/* + * Check if the container is alive + */ +#define AJP13_CPING_REQUEST (unsigned char)10 + +/* + * Reply from the container to alive request + */ +#define AJP13_CPONG_REPLY (unsigned char)9 + + + +/* + * Functions + */ + +int ajp13_marshal_shutdown_into_msgb(jk_msg_buf_t *msg, + jk_pool_t *p, jk_logger_t *l); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* JK_AJP13_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13.lo b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13.lo new file mode 100644 index 00000000..33d31154 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13.lo @@ -0,0 +1,12 @@ +# jk_ajp13.lo - a libtool object file +# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/jk_ajp13.o' + +# Name of the non-PIC object. +non_pic_object='jk_ajp13.o' + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13.o Binary files differnew file mode 100644 index 00000000..872b5f5f --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13_worker.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13_worker.c new file mode 100644 index 00000000..13e140ff --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13_worker.c @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Bi-directional protocol. * + * Author: Costin <costin@costin.dnt.ro> * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Author: Henri Gomez <hgomez@apache.org> * + * Version: $Revision: 611589 $ * + ***************************************************************************/ + +#include "jk_ajp13_worker.h" + + +/* -------------------- Method -------------------- */ +static int JK_METHOD validate(jk_worker_t *pThis, + jk_map_t *props, + jk_worker_env_t *we, jk_logger_t *l) +{ + int rc; + JK_TRACE_ENTER(l); + rc = ajp_validate(pThis, props, we, l, AJP13_PROTO); + JK_TRACE_EXIT(l); + return rc; +} + + +static int JK_METHOD init(jk_worker_t *pThis, + jk_map_t *props, + jk_worker_env_t *we, jk_logger_t *l) +{ + int rc; + JK_TRACE_ENTER(l); + + rc = ajp_init(pThis, props, we, l, AJP13_PROTO); + JK_TRACE_EXIT(l); + return rc; +} + + +static int JK_METHOD destroy(jk_worker_t **pThis, jk_logger_t *l) +{ + int rc; + JK_TRACE_ENTER(l); + rc = ajp_destroy(pThis, l, AJP13_PROTO); + JK_TRACE_EXIT(l); + return rc; +} + + +static int JK_METHOD get_endpoint(jk_worker_t *pThis, + jk_endpoint_t **pend, jk_logger_t *l) +{ + int rc; + JK_TRACE_ENTER(l); + rc = ajp_get_endpoint(pThis, pend, l, AJP13_PROTO); + JK_TRACE_EXIT(l); + return rc; +} + +int JK_METHOD ajp13_worker_factory(jk_worker_t **w, + const char *name, jk_logger_t *l) +{ + ajp_worker_t *aw; + + JK_TRACE_ENTER(l); + if (ajp_worker_factory(w, name, l) == JK_FALSE) + return 0; + + aw = (*w)->worker_private; + aw->proto = AJP13_PROTO; + + aw->worker.validate = validate; + aw->worker.init = init; + aw->worker.get_endpoint = get_endpoint; + aw->worker.destroy = destroy; + + JK_TRACE_EXIT(l); + return JK_AJP13_WORKER_TYPE; +} diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13_worker.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13_worker.h new file mode 100644 index 00000000..b3098d6f --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13_worker.h @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: ajpv1.3 worker header file * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Version: $Revision: 466585 $ * + ***************************************************************************/ + +#ifndef JK_AJP13_WORKER_H +#define JK_AJP13_WORKER_H + +#include "jk_pool.h" +#include "jk_connect.h" +#include "jk_util.h" +#include "jk_msg_buff.h" +#include "jk_ajp_common.h" +#include "jk_ajp13.h" +#include "jk_logger.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#define JK_AJP13_WORKER_NAME ("ajp13") +#define JK_AJP13_WORKER_TYPE (2) + +int JK_METHOD ajp13_worker_factory(jk_worker_t **w, + const char *name, jk_logger_t *l); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* JK_AJP13_WORKER_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13_worker.lo b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13_worker.lo new file mode 100644 index 00000000..415f71ae --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13_worker.lo @@ -0,0 +1,12 @@ +# jk_ajp13_worker.lo - a libtool object file +# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/jk_ajp13_worker.o' + +# Name of the non-PIC object. +non_pic_object='jk_ajp13_worker.o' + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13_worker.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13_worker.o Binary files differnew file mode 100644 index 00000000..b8f3d642 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13_worker.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14.c new file mode 100644 index 00000000..161356ab --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14.c @@ -0,0 +1,695 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Next generation bi-directional protocol handler. * + * Author: Henri Gomez <hgomez@apache.org> * + * Version: $Revision: 466585 $ * + ***************************************************************************/ + + +#include "jk_global.h" +#include "jk_util.h" +#include "jk_map.h" +#include "jk_ajp_common.h" +#include "jk_ajp14.h" +#include "jk_md5.h" + +/* + * Compute the MD5 with ENTROPY / SECRET KEY + */ + +void ajp14_compute_md5(jk_login_service_t *s, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + jk_md5((const unsigned char *)s->entropy, + (const unsigned char *)s->secret_key, s->computed_key); + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, "(%s/%s) -> (%s)", + s->entropy, s->secret_key, s->computed_key); + JK_TRACE_EXIT(l); +} + + +/* + * Build the Login Init Command + * + * +-------------------------+---------------------------+---------------------------+ + * | LOGIN INIT CMD (1 byte) | NEGOCIATION DATA (32bits) | WEB SERVER INFO (CString) | + * +-------------------------+---------------------------+---------------------------+ + * + */ + +int ajp14_marshal_login_init_into_msgb(jk_msg_buf_t *msg, + jk_login_service_t *s, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + /* To be on the safe side */ + jk_b_reset(msg); + + /* + * LOGIN + */ + if (jk_b_append_byte(msg, AJP14_LOGINIT_CMD)) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + /* + * NEGOCIATION FLAGS + */ + if (jk_b_append_long(msg, s->negociation)) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + /* + * WEB-SERVER NAME + */ + if (jk_b_append_string(msg, s->web_server_name)) { + jk_log(l, JK_LOG_ERROR, + "failed appending the web_server_name string"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + + +/* + * Decode the Login Seed Command + * + * +-------------------------+---------------------------+ + * | LOGIN SEED CMD (1 byte) | MD5 of entropy (32 chars) | + * +-------------------------+---------------------------+ + * + */ + +int ajp14_unmarshal_login_seed(jk_msg_buf_t *msg, + jk_login_service_t *s, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + if (jk_b_get_bytes + (msg, (unsigned char *)s->entropy, AJP14_ENTROPY_SEED_LEN) < 0) { + jk_log(l, JK_LOG_ERROR, + "can't get seed"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + s->entropy[AJP14_ENTROPY_SEED_LEN] = 0; /* Just to have a CString */ + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +/* + * Build the Login Computed Command + * + * +-------------------------+---------------------------------------+ + * | LOGIN COMP CMD (1 byte) | MD5 of RANDOM + SECRET KEY (32 chars) | + * +-------------------------+---------------------------------------+ + * + */ + +int ajp14_marshal_login_comp_into_msgb(jk_msg_buf_t *msg, + jk_login_service_t *s, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + /* To be on the safe side */ + jk_b_reset(msg); + + /* + * LOGIN + */ + if (jk_b_append_byte(msg, AJP14_LOGCOMP_CMD)) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + /* + * COMPUTED-SEED + */ + if (jk_b_append_bytes + (msg, (const unsigned char *)s->computed_key, + AJP14_COMPUTED_KEY_LEN)) { + jk_log(l, JK_LOG_ERROR, + "failed appending the COMPUTED MD5 bytes"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + + +/* + * Decode the LogOk Command + * + * +--------------------+------------------------+-------------------------------+ + * | LOGOK CMD (1 byte) | NEGOCIED DATA (32bits) | SERVLET ENGINE INFO (CString) | + * +--------------------+------------------------+-------------------------------+ + * + */ + +int ajp14_unmarshal_log_ok(jk_msg_buf_t *msg, + jk_login_service_t *s, jk_logger_t *l) +{ + unsigned long nego; + char *sname; + + JK_TRACE_ENTER(l); + + nego = jk_b_get_long(msg); + + if (nego == 0xFFFFFFFF) { + jk_log(l, JK_LOG_ERROR, + "can't get negociated data"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + sname = (char *)jk_b_get_string(msg); + + if (!sname) { + jk_log(l, JK_LOG_ERROR, + "can't get servlet engine name"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (s->servlet_engine_name) /* take care of removing previously allocated data */ + free(s->servlet_engine_name); + + s->servlet_engine_name = strdup(sname); + + if (!s->servlet_engine_name) { + jk_log(l, JK_LOG_ERROR, + "can't malloc servlet engine name"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + + +/* + * Decode the Log Nok Command + * + * +---------------------+-----------------------+ + * | LOGNOK CMD (1 byte) | FAILURE CODE (32bits) | + * +---------------------+-----------------------+ + * + */ + +int ajp14_unmarshal_log_nok(jk_msg_buf_t *msg, jk_logger_t *l) +{ + unsigned long status; + + JK_TRACE_ENTER(l); + + status = jk_b_get_long(msg); + + if (status == 0xFFFFFFFF) { + jk_log(l, JK_LOG_ERROR, + "can't get failure code"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + jk_log(l, JK_LOG_INFO, "Can't Log with servlet engine - code %08lx", + status); + JK_TRACE_EXIT(l); + return JK_TRUE; +} + + +/* + * Build the Shutdown Cmd + * + * +-----------------------+---------------------------------------+ + * | SHUTDOWN CMD (1 byte) | MD5 of RANDOM + SECRET KEY (32 chars) | + * +-----------------------+---------------------------------------+ + * + */ + +int ajp14_marshal_shutdown_into_msgb(jk_msg_buf_t *msg, + jk_login_service_t *s, jk_logger_t *l) +{ + + JK_TRACE_ENTER(l); + + /* To be on the safe side */ + jk_b_reset(msg); + + /* + * SHUTDOWN CMD + */ + if (jk_b_append_byte(msg, AJP14_SHUTDOWN_CMD)) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + /* + * COMPUTED-SEED + */ + if (jk_b_append_bytes + (msg, (const unsigned char *)s->computed_key, + AJP14_COMPUTED_KEY_LEN)) { + jk_log(l, JK_LOG_ERROR, + "failed appending the COMPUTED MD5 bytes"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +/* + * Decode the Shutdown Nok Command + * + * +----------------------+-----------------------+ + * | SHUTNOK CMD (1 byte) | FAILURE CODE (32bits) | + * +----------------------+-----------------------+ + * + */ +int ajp14_unmarshal_shutdown_nok(jk_msg_buf_t *msg, jk_logger_t *l) +{ + unsigned long status; + + JK_TRACE_ENTER(l); + status = jk_b_get_long(msg); + + if (status == 0xFFFFFFFF) { + jk_log(l, JK_LOG_ERROR, + "can't get failure code"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + jk_log(l, JK_LOG_INFO, "Can't shutdown servlet engine - code %08lx", + status); + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +/* + * Build the Unknown Packet + * + * +-----------------------------+---------------------------------+------------------------------+ + * | UNKNOWN PACKET CMD (1 byte) | UNHANDLED MESSAGE SIZE (16bits) | UNHANDLED MESSAGE (bytes...) | + * +-----------------------------+---------------------------------+------------------------------+ + * + */ + +int ajp14_marshal_unknown_packet_into_msgb(jk_msg_buf_t *msg, + jk_msg_buf_t *unk, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + /* To be on the safe side */ + jk_b_reset(msg); + + /* + * UNKNOWN PACKET CMD + */ + if (jk_b_append_byte(msg, AJP14_UNKNOW_PACKET_CMD)) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + /* + * UNHANDLED MESSAGE SIZE + */ + if (jk_b_append_int(msg, (unsigned short)unk->len)) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + /* + * UNHANDLED MESSAGE (Question : Did we have to send all the message or only part of) + * ( ie: only 1k max ) + */ + if (jk_b_append_bytes(msg, unk->buf, unk->len)) { + jk_log(l, JK_LOG_ERROR, + "failed appending the UNHANDLED MESSAGE"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +/* + * Build the Context Query Cmd (autoconf) + * + * +--------------------------+---------------------------------+ + * | CONTEXT QRY CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | + * +--------------------------+---------------------------------+ + * + */ + +int ajp14_marshal_context_query_into_msgb(jk_msg_buf_t *msg, + char *virtual, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + /* To be on the safe side */ + jk_b_reset(msg); + + /* + * CONTEXT QUERY CMD + */ + if (jk_b_append_byte(msg, AJP14_CONTEXT_QRY_CMD)) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + /* + * VIRTUAL HOST CSTRING + */ + if (jk_b_append_string(msg, virtual)) { + jk_log(l, JK_LOG_ERROR, + "failed appending the virtual host string"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + + +/* + * Decode the Context Info Cmd (Autoconf) + * + * The Autoconf feature of AJP14, let us know which URL/URI could + * be handled by the servlet-engine + * + * +---------------------------+---------------------------------+----------------------------+-------------------------------+-----------+ + * | CONTEXT INFO CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | CONTEXT NAME (CString (*)) | URL1 [\n] URL2 [\n] URL3 [\n] | NEXT CTX. | + * +---------------------------+---------------------------------+----------------------------+-------------------------------+-----------+ + */ + +int ajp14_unmarshal_context_info(jk_msg_buf_t *msg, + jk_context_t *c, jk_logger_t *l) +{ + char *vname; + char *cname; + char *uri; + + vname = (char *)jk_b_get_string(msg); + + JK_TRACE_ENTER(l); + jk_log(l, JK_LOG_DEBUG, + "get virtual %s for virtual %s", + vname, c->virt); + + if (!vname) { + jk_log(l, JK_LOG_ERROR, + "can't get virtual hostname"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + /* Check if we get the correct virtual host */ + if (c->virt != NULL && vname != NULL && strcmp(c->virt, vname)) { + /* set the virtual name, better to add to a virtual list ? */ + + if (context_set_virtual(c, vname) == JK_FALSE) { + jk_log(l, JK_LOG_ERROR, + "can't malloc virtual hostname"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + + for (;;) { + + cname = (char *)jk_b_get_string(msg); + + if (!cname) { + jk_log(l, JK_LOG_ERROR, + "can't get context"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + jk_log(l, JK_LOG_DEBUG, + "get context %s for virtual %s", + cname, vname); + + /* grab all contexts up to empty one which indicate end of contexts */ + if (!strlen(cname)) + break; + + /* create new context base (if needed) */ + + if (context_add_base(c, cname) == JK_FALSE) { + jk_log(l, JK_LOG_ERROR, + "can't add/set context %s", + cname); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + for (;;) { + + uri = (char *)jk_b_get_string(msg); + + if (!uri) { + jk_log(l, JK_LOG_ERROR, + "can't get URI"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (!strlen(uri)) { + jk_log(l, JK_LOG_DEBUG, "No more URI for context %s", cname); + break; + } + + jk_log(l, JK_LOG_INFO, + "Got URI (%s) for virtualhost %s and context %s", uri, + vname, cname); + + if (context_add_uri(c, cname, uri) == JK_FALSE) { + jk_log(l, JK_LOG_ERROR, + "can't add/set uri (%s) for context %s", + uri, cname); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + + +/* + * Build the Context State Query Cmd + * + * We send the list of contexts where we want to know state, empty string end context list* + * If cname is set, only ask about THIS context + * + * +----------------------------+----------------------------------+----------------------------+----+ + * | CONTEXT STATE CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | CONTEXT NAME (CString (*)) | .. | + * +----------------------------+----------------------------------+----------------------------+----+ + * + */ + +int ajp14_marshal_context_state_into_msgb(jk_msg_buf_t *msg, + jk_context_t *c, + char *cname, jk_logger_t *l) +{ + jk_context_item_t *ci; + int i; + + JK_TRACE_ENTER(l); + + /* To be on the safe side */ + jk_b_reset(msg); + + /* + * CONTEXT STATE CMD + */ + if (jk_b_append_byte(msg, AJP14_CONTEXT_STATE_CMD)) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + /* + * VIRTUAL HOST CSTRING + */ + if (jk_b_append_string(msg, c->virt)) { + jk_log(l, JK_LOG_ERROR, + "failed appending the virtual host string"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (cname) { + + ci = context_find_base(c, cname); + + if (!ci) { + jk_log(l, JK_LOG_ERROR, + "unknown context %s", + cname); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + /* + * CONTEXT CSTRING + */ + + if (jk_b_append_string(msg, cname)) { + jk_log(l, JK_LOG_ERROR, + "failed appending the context string %s", + cname); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + else { /* Grab all contexts name */ + + for (i = 0; i < c->size; i++) { + + /* + * CONTEXT CSTRING + */ + if (jk_b_append_string(msg, c->contexts[i]->cbase)) { + jk_log(l, JK_LOG_ERROR, + "failed appending the context string %s", + c->contexts[i]->cbase); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + } + + /* End of context list, an empty string */ + + if (jk_b_append_string(msg, "")) { + jk_log(l, JK_LOG_ERROR, + "failed appending end of contexts"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + + +/* + * Decode the Context State Reply Cmd + * + * We get update of contexts list, empty string end context list* + * + * +----------------------------------+---------------------------------+----------------------------+------------------+----+ + * | CONTEXT STATE REPLY CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | CONTEXT NAME (CString (*)) | UP/DOWN (1 byte) | .. | + * +----------------------------------+---------------------------------+----------------------------+------------------+----+ + * + */ + +int ajp14_unmarshal_context_state_reply(jk_msg_buf_t *msg, + jk_context_t *c, jk_logger_t *l) +{ + char *vname; + char *cname; + jk_context_item_t *ci; + + JK_TRACE_ENTER(l); + /* get virtual name */ + vname = (char *)jk_b_get_string(msg); + + if (!vname) { + jk_log(l, JK_LOG_ERROR, + "can't get virtual hostname"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + /* Check if we speak about the correct virtual */ + if (strcmp(c->virt, vname)) { + jk_log(l, JK_LOG_ERROR, + "incorrect virtual %s instead of %s", + vname, c->virt); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + for (;;) { + + /* get context name */ + cname = (char *)jk_b_get_string(msg); + + if (!cname) { + jk_log(l, JK_LOG_ERROR, + "can't get context"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (!strlen(cname)) + break; + + ci = context_find_base(c, cname); + + if (!ci) { + jk_log(l, JK_LOG_ERROR, + "unknow context %s for virtual %s", + cname, vname); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + ci->status = jk_b_get_int(msg); + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "updated context %s to state %d", + cname, ci->status); + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +/* + * Decode the Context Update Cmd + * + * +-----------------------------+---------------------------------+----------------------------+------------------+ + * | CONTEXT UPDATE CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | CONTEXT NAME (CString (*)) | UP/DOWN (1 byte) | + * +-----------------------------+---------------------------------+----------------------------+------------------+ + * + */ + +int ajp14_unmarshal_context_update_cmd(jk_msg_buf_t *msg, + jk_context_t *c, jk_logger_t *l) +{ + int rc; + JK_TRACE_ENTER(l); + rc = ajp14_unmarshal_context_state_reply(msg, c, l); + JK_TRACE_EXIT(l); + return rc; +} diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14.h new file mode 100644 index 00000000..58a5a4de --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14.h @@ -0,0 +1,307 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Next generation bi-directional protocol handler. * + * Author: Henri Gomez <hgomez@apache.org> * + * Version: $Revision: 466585 $ * + ***************************************************************************/ +#ifndef JK_AJP14_H +#define JK_AJP14_H + +#include "jk_ajp_common.h" +#include "jk_context.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#define AJP14_PROTO 14 + +#define AJP14_WS_HEADER 0x1235 +#define AJP14_SW_HEADER 0x1235 /* AJP14 use now the same header in both directions */ + +#define AJP14_DEF_HOST ("localhost") +#define AJP14_DEF_PORT (8011) +#define AJP14_READ_BUF_SIZE (8*1024) +#define AJP14_DEF_RETRY_ATTEMPTS (1) +#define AJP14_DEF_CACHE_SZ (1) +#define AJP14_MAX_SEND_BODY_SZ (DEF_BUFFER_SZ - 6) +#define AJP14_HEADER_LEN (4) +#define AJP14_HEADER_SZ_LEN (2) + +/* + * Initial Login Phase (web server -> servlet engine) + */ +#define AJP14_LOGINIT_CMD (unsigned char)0x10 + +/* + * Second Login Phase (servlet engine -> web server), md5 seed is received + */ +#define AJP14_LOGSEED_CMD (unsigned char)0x11 + +/* + * Third Login Phase (web server -> servlet engine), md5 of seed + secret is sent + */ +#define AJP14_LOGCOMP_CMD (unsigned char)0x12 + +/* + * Login Accepted (servlet engine -> web server) + */ +#define AJP14_LOGOK_CMD (unsigned char)0x13 + +/* + * Login Rejected (servlet engine -> web server), will be logged + */ +#define AJP14_LOGNOK_CMD (unsigned char)0x14 + +/* + * Context Query (web server -> servlet engine), which URI are handled by servlet engine ? + */ +#define AJP14_CONTEXT_QRY_CMD (unsigned char)0x15 + +/* + * Context Info (servlet engine -> web server), URI handled response + */ +#define AJP14_CONTEXT_INFO_CMD (unsigned char)0x16 + +/* + * Context Update (servlet engine -> web server), status of context changed + */ +#define AJP14_CONTEXT_UPDATE_CMD (unsigned char)0x17 + +/* + * Servlet Engine Status (web server -> servlet engine), what's the status of the servlet engine ? + */ +#define AJP14_STATUS_CMD (unsigned char)0x18 + +/* + * Secure Shutdown command (web server -> servlet engine), please servlet stop yourself. + */ +#define AJP14_SHUTDOWN_CMD (unsigned char)0x19 + +/* + * Secure Shutdown command Accepted (servlet engine -> web server) + */ +#define AJP14_SHUTOK_CMD (unsigned char)0x1A + +/* + * Secure Shutdown Rejected (servlet engine -> web server) + */ +#define AJP14_SHUTNOK_CMD (unsigned char)0x1B + +/* + * Context Status (web server -> servlet engine), what's the status of the context ? + */ +#define AJP14_CONTEXT_STATE_CMD (unsigned char)0x1C + +/* + * Context Status Reply (servlet engine -> web server), status of context + */ +#define AJP14_CONTEXT_STATE_REP_CMD (unsigned char)0x1D + +/* + * Unknown Packet Reply (web server <-> servlet engine), when a packet couldn't be decoded + */ +#define AJP14_UNKNOW_PACKET_CMD (unsigned char)0x1E + + +/* + * Negociation flags + */ + +/* + * web-server want context info after login + */ +#define AJP14_CONTEXT_INFO_NEG 0x80000000 + +/* + * web-server want context updates + */ +#define AJP14_CONTEXT_UPDATE_NEG 0x40000000 + +/* + * web-server want compressed stream + */ +#define AJP14_GZIP_STREAM_NEG 0x20000000 + +/* + * web-server want crypted DES56 stream with secret key + */ +#define AJP14_DES56_STREAM_NEG 0x10000000 + +/* + * Extended info on server SSL vars + */ +#define AJP14_SSL_VSERVER_NEG 0x08000000 + +/* + *Extended info on client SSL vars + */ +#define AJP14_SSL_VCLIENT_NEG 0x04000000 + +/* + * Extended info on crypto SSL vars + */ +#define AJP14_SSL_VCRYPTO_NEG 0x02000000 + +/* + * Extended info on misc SSL vars + */ +#define AJP14_SSL_VMISC_NEG 0x01000000 + +/* + * mask of protocol supported + */ +#define AJP14_PROTO_SUPPORT_AJPXX_NEG 0x00FF0000 + +/* + * communication could use AJP14 + */ +#define AJP14_PROTO_SUPPORT_AJP14_NEG 0x00010000 + +/* + * communication could use AJP15 + */ +#define AJP14_PROTO_SUPPORT_AJP15_NEG 0x00020000 + +/* + * communication could use AJP16 + */ +#define AJP14_PROTO_SUPPORT_AJP16_NEG 0x00040000 + +/* + * Some failure codes + */ +#define AJP14_BAD_KEY_ERR 0xFFFFFFFF +#define AJP14_ENGINE_DOWN_ERR 0xFFFFFFFE +#define AJP14_RETRY_LATER_ERR 0xFFFFFFFD +#define AJP14_SHUT_AUTHOR_FAILED_ERR 0xFFFFFFFC + +/* + * Some status codes + */ +#define AJP14_CONTEXT_DOWN 0x01 +#define AJP14_CONTEXT_UP 0x02 +#define AJP14_CONTEXT_OK 0x03 + +/* + * Misc defines + */ +#define AJP14_ENTROPY_SEED_LEN 32 /* we're using MD5 => 32 chars */ +#define AJP14_COMPUTED_KEY_LEN 32 /* we're using MD5 also */ + +/* + * The login structure + */ +typedef struct jk_login_service jk_login_service_t; + +struct jk_login_service +{ + + /* + * Pointer to web-server name + */ + const char *web_server_name; + + /* + * Pointer to servlet-engine name + */ + char *servlet_engine_name; + + /* + * Pointer to secret key + */ + const char *secret_key; + + /* + * Received entropy seed + */ + char entropy[AJP14_ENTROPY_SEED_LEN + 1]; + + /* + * Computed key + */ + char computed_key[AJP14_COMPUTED_KEY_LEN + 1]; + + /* + * What we want to negociate + */ + unsigned long negociation; + + /* + * What we received from servlet engine + */ + unsigned long negociated; +}; + +/* + * functions defined here + */ + +void ajp14_compute_md5(jk_login_service_t *s, jk_logger_t *l); + +int ajp14_marshal_login_init_into_msgb(jk_msg_buf_t *msg, + jk_login_service_t *s, + jk_logger_t *l); + +int ajp14_unmarshal_login_seed(jk_msg_buf_t *msg, + jk_login_service_t *s, jk_logger_t *l); + +int ajp14_marshal_login_comp_into_msgb(jk_msg_buf_t *msg, + jk_login_service_t *s, + jk_logger_t *l); + +int ajp14_unmarshal_log_ok(jk_msg_buf_t *msg, + jk_login_service_t *s, jk_logger_t *l); + +int ajp14_unmarshal_log_nok(jk_msg_buf_t *msg, jk_logger_t *l); + +int ajp14_marshal_shutdown_into_msgb(jk_msg_buf_t *msg, + jk_login_service_t *s, + jk_logger_t *l); + +int ajp14_unmarshal_shutdown_nok(jk_msg_buf_t *msg, jk_logger_t *l); + +int ajp14_marshal_unknown_packet_into_msgb(jk_msg_buf_t *msg, + jk_msg_buf_t *unk, + jk_logger_t *l); + +int ajp14_marshal_context_query_into_msgb(jk_msg_buf_t *msg, + char *virtual, jk_logger_t *l); + +int ajp14_unmarshal_context_info(jk_msg_buf_t *msg, + jk_context_t *context, jk_logger_t *l); + +int ajp14_marshal_context_state_into_msgb(jk_msg_buf_t *msg, + jk_context_t *context, + char *cname, jk_logger_t *l); + +int ajp14_unmarshal_context_state_reply(jk_msg_buf_t *msg, + jk_context_t *context, + jk_logger_t *l); + +int ajp14_unmarshal_context_update_cmd(jk_msg_buf_t *msg, + jk_context_t *context, + jk_logger_t *l); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* JK_AJP14_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14.lo b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14.lo new file mode 100644 index 00000000..3613a169 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14.lo @@ -0,0 +1,12 @@ +# jk_ajp14.lo - a libtool object file +# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/jk_ajp14.o' + +# Name of the non-PIC object. +non_pic_object='jk_ajp14.o' + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14.o Binary files differnew file mode 100644 index 00000000..f3f783c5 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14_worker.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14_worker.c new file mode 100644 index 00000000..639fb11c --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14_worker.c @@ -0,0 +1,404 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: AJP14 next generation Bi-directional protocol. * + * Author: Henri Gomez <hgomez@apache.org> * + * Version: $Revision: 611589 $ * + ***************************************************************************/ + +#include "jk_context.h" +#include "jk_ajp14_worker.h" + + +/* + * AJP14 Autoconf Phase + * + * CONTEXT QUERY / REPLY + */ + +#define MAX_URI_SIZE 512 + +static int handle_discovery(ajp_endpoint_t * ae, + jk_worker_env_t *we, + jk_msg_buf_t *msg, jk_logger_t *l) +{ + int cmd; + int i, j; +#if 0 + /* Not used for now */ + jk_login_service_t *jl = ae->worker->login; +#endif + jk_context_item_t *ci; + jk_context_t *c; + char *buf; + +#ifndef TESTME + JK_TRACE_ENTER(l); + + ajp14_marshal_context_query_into_msgb(msg, we->virtual, l); + + jk_log(l, JK_LOG_DEBUG, "send query"); + + if (ajp_connection_tcp_send_message(ae, msg, l) != JK_TRUE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + jk_log(l, JK_LOG_DEBUG, "wait context reply"); + + jk_b_reset(msg); + + if (ajp_connection_tcp_get_message(ae, msg, l) != JK_TRUE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + if ((cmd = jk_b_get_byte(msg)) != AJP14_CONTEXT_INFO_CMD) { + jk_log(l, JK_LOG_ERROR, + "awaited command %d, received %d", + AJP14_CONTEXT_INFO_CMD, cmd); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (context_alloc(&c, we->virtual) != JK_TRUE) { + jk_log(l, JK_LOG_ERROR, + "can't allocate context room"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (ajp14_unmarshal_context_info(msg, c, l) != JK_TRUE) { + jk_log(l, JK_LOG_ERROR, + "can't get context reply"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + jk_log(l, JK_LOG_DEBUG, "received context"); + + buf = malloc(MAX_URI_SIZE); /* Really a very long URI */ + + if (!buf) { + jk_log(l, JK_LOG_ERROR, "can't malloc buf"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + for (i = 0; i < c->size; i++) { + ci = c->contexts[i]; + for (j = 0; j < ci->size; j++) { + +#ifndef USE_SPRINTF + snprintf(buf, MAX_URI_SIZE - 1, "/%s/%s", ci->cbase, ci->uris[j]); +#else + sprintf(buf, "/%s/%s", ci->cbase, ci->uris[j]); +#endif + + jk_log(l, JK_LOG_INFO, + "worker %s will handle uri %s in context %s [%s]", + ae->worker->name, ci->uris[j], ci->cbase, buf); + + uri_worker_map_add(we->uri_to_worker, buf, ae->worker->name, SOURCE_TYPE_DISCOVER, l); + } + } + + free(buf); + context_free(&c); + +#else + + uri_worker_map_add(we->uri_to_worker, "/examples/servlet/*", + ae->worker->name, SOURCE_TYPE_DISCOVER, l); + uri_worker_map_add(we->uri_to_worker, "/examples/*.jsp", ae->worker->name, + SOURCE_TYPE_DISCOVER, l); + uri_worker_map_add(we->uri_to_worker, "/examples/*.gif", ae->worker->name, + SOURCE_TYPE_DISCOVER, l); + +#endif + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +/* + * AJP14 Logon Phase + * + * INIT + REPLY / NEGO + REPLY + */ + +static int handle_logon(ajp_endpoint_t * ae, + jk_msg_buf_t *msg, jk_logger_t *l) +{ + int cmd; + + jk_login_service_t *jl = ae->worker->login; + JK_TRACE_ENTER(l); + + ajp14_marshal_login_init_into_msgb(msg, jl, l); + + jk_log(l, JK_LOG_DEBUG, "send init"); + + if (ajp_connection_tcp_send_message(ae, msg, l) != JK_TRUE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + jk_log(l, JK_LOG_DEBUG, "wait init reply"); + + jk_b_reset(msg); + + if (ajp_connection_tcp_get_message(ae, msg, l) != JK_TRUE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + if ((cmd = jk_b_get_byte(msg)) != AJP14_LOGSEED_CMD) { + jk_log(l, JK_LOG_ERROR, + "awaited command %d, received %d", + AJP14_LOGSEED_CMD, cmd); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (ajp14_unmarshal_login_seed(msg, jl, l) != JK_TRUE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + jk_log(l, JK_LOG_DEBUG, "received entropy %s", + jl->entropy); + + ajp14_compute_md5(jl, l); + + if (ajp14_marshal_login_comp_into_msgb(msg, jl, l) != JK_TRUE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + if (ajp_connection_tcp_send_message(ae, msg, l) != JK_TRUE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + jk_b_reset(msg); + + if (ajp_connection_tcp_get_message(ae, msg, l) != JK_TRUE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + switch (jk_b_get_byte(msg)) { + + case AJP14_LOGOK_CMD: + if (ajp14_unmarshal_log_ok(msg, jl, l) == JK_TRUE) { + jk_log(l, JK_LOG_DEBUG, + "Successfully connected to servlet-engine %s", + jl->servlet_engine_name); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + break; + + case AJP14_LOGNOK_CMD: + ajp14_unmarshal_log_nok(msg, l); + break; + } + + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +static int logon(ajp_endpoint_t * ae, jk_logger_t *l) +{ + jk_pool_t *p = &ae->pool; + jk_msg_buf_t *msg; + int rc; + + JK_TRACE_ENTER(l); + + msg = jk_b_new(p); + jk_b_set_buffer_size(msg, DEF_BUFFER_SZ); + + if ((rc = handle_logon(ae, msg, l)) == JK_FALSE) + ajp_close_endpoint(ae, l); + + JK_TRACE_EXIT(l); + return rc; +} + +static int discovery(ajp_endpoint_t * ae, jk_worker_env_t *we, jk_logger_t *l) +{ + jk_pool_t *p = &ae->pool; + jk_msg_buf_t *msg; + int rc; + + JK_TRACE_ENTER(l); + + msg = jk_b_new(p); + jk_b_set_buffer_size(msg, DEF_BUFFER_SZ); + + if ((rc = handle_discovery(ae, we, msg, l)) == JK_FALSE) + ajp_close_endpoint(ae, l); + + JK_TRACE_EXIT(l); + return rc; +} + +/* -------------------- Method -------------------- */ +static int JK_METHOD validate(jk_worker_t *pThis, + jk_map_t *props, + jk_worker_env_t *we, jk_logger_t *l) +{ + ajp_worker_t *aw; + const char *secret_key; + + JK_TRACE_ENTER(l); + if (ajp_validate(pThis, props, we, l, AJP14_PROTO) == JK_FALSE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + 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, + "validate error, empty or missing secretkey"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + /* jk_log(l, JK_LOG_DEBUG, "Into ajp14:validate - secret_key=%s", secret_key); */ + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +static int JK_METHOD get_endpoint(jk_worker_t *pThis, + jk_endpoint_t **pend, jk_logger_t *l) +{ + int rc; + JK_TRACE_ENTER(l); + rc = ajp_get_endpoint(pThis, pend, l, AJP14_PROTO); + JK_TRACE_EXIT(l); + return rc; +} + +static int JK_METHOD init(jk_worker_t *pThis, + jk_map_t *props, + jk_worker_env_t *we, jk_logger_t *l) +{ + ajp_worker_t *aw; + ajp_endpoint_t *ae; + jk_endpoint_t *je; + int rc; + + JK_TRACE_EXIT(l); + + if (ajp_init(pThis, props, we, l, AJP14_PROTO) == JK_FALSE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + aw = pThis->worker_private; + + /* Set Secret Key (used at logon time) */ + aw->login->secret_key = jk_get_worker_secret_key(props, aw->name); + + if (aw->login->secret_key == NULL) { + jk_log(l, JK_LOG_ERROR, "can't malloc secret_key"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + /* 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"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (get_endpoint(pThis, &je, l) == JK_FALSE) { + JK_TRACE_EXIT(l); + 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); + JK_TRACE_EXIT(l); + return rc; + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + + +static int JK_METHOD destroy(jk_worker_t **pThis, jk_logger_t *l) +{ + int rc; + ajp_worker_t *aw = (*pThis)->worker_private; + + JK_TRACE_ENTER(l); + + if (aw->login) { + free(aw->login); + aw->login = NULL; + } + + rc = ajp_destroy(pThis, l, AJP14_PROTO); + JK_TRACE_EXIT(l); + return rc; +} + +int JK_METHOD ajp14_worker_factory(jk_worker_t **w, + const char *name, jk_logger_t *l) +{ + ajp_worker_t *aw; + + JK_TRACE_ENTER(l); + if (ajp_worker_factory(w, name, l) == JK_FALSE) + return 0; + + aw = (*w)->worker_private; + 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, + "malloc failed for login area"); + JK_TRACE_EXIT(l); + return 0; + } + + 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->worker.validate = validate; + aw->worker.init = init; + aw->worker.get_endpoint = get_endpoint; + aw->worker.destroy = destroy; + + aw->logon = logon; /* LogOn Handler for AJP14 */ + + JK_TRACE_EXIT(l); + return JK_AJP14_WORKER_TYPE; +} diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14_worker.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14_worker.h new file mode 100644 index 00000000..3d5c7973 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14_worker.h @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: ajpv14 worker header file * + * Author: Henri Gomez <hgomez@apache.org> * + * Version: $Revision: 466585 $ * + ***************************************************************************/ + +#ifndef JK_AJP14_WORKER_H +#define JK_AJP14_WORKER_H + +#include "jk_pool.h" +#include "jk_connect.h" +#include "jk_util.h" +#include "jk_msg_buff.h" +#include "jk_ajp13.h" +#include "jk_ajp14.h" +#include "jk_logger.h" +#include "jk_service.h" +#include "jk_ajp13_worker.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#define JK_AJP14_WORKER_NAME ("ajp14") +#define JK_AJP14_WORKER_TYPE (3) + +int JK_METHOD ajp14_worker_factory(jk_worker_t **w, + const char *name, jk_logger_t *l); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* JK_AJP14_WORKER_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14_worker.lo b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14_worker.lo new file mode 100644 index 00000000..cfd049e1 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14_worker.lo @@ -0,0 +1,12 @@ +# jk_ajp14_worker.lo - a libtool object file +# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/jk_ajp14_worker.o' + +# Name of the non-PIC object. +non_pic_object='jk_ajp14_worker.o' + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14_worker.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14_worker.o Binary files differnew file mode 100644 index 00000000..604ad3b1 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14_worker.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp_common.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp_common.c new file mode 100644 index 00000000..7b083264 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp_common.c @@ -0,0 +1,3383 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: common stuff for bi-directional protocols ajp13/ajp14. * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Author: Henri Gomez <hgomez@apache.org> * + * Version: $Revision: 1137200 $ * + ***************************************************************************/ + + +#include "jk_global.h" +#include "jk_util.h" +#include "jk_ajp13.h" +#include "jk_ajp14.h" +#include "jk_ajp_common.h" +#include "jk_connect.h" +#if defined(AS400) && !defined(AS400_UTF8) +#include "util_ebcdic.h" +#endif +#if defined(NETWARE) && defined(__NOVELL_LIBC__) +#include "novsock2.h" +#endif + +const char *response_trans_headers[] = { + "Content-Type", + "Content-Language", + "Content-Length", + "Date", + "Last-Modified", + "Location", + "Set-Cookie", + "Set-Cookie2", + "Servlet-Engine", + "Status", + "WWW-Authenticate" +}; + +static const char *long_res_header_for_sc(int sc) +{ + const char *rc = NULL; + sc = sc & 0X00FF; + if (sc <= SC_RES_HEADERS_NUM && sc > 0) { + rc = response_trans_headers[sc - 1]; + } + + return rc; +} + +static const char *ajp_state_type[] = { + JK_AJP_STATE_TEXT_IDLE, + JK_AJP_STATE_TEXT_OK, + JK_AJP_STATE_TEXT_ERROR, + JK_AJP_STATE_TEXT_PROBE, + "unknown", + NULL +}; + +#define UNKNOWN_METHOD (-1) + +static int sc_for_req_method(const char *method, size_t len) +{ + /* Note: the following code was generated by the "shilka" tool from + the "cocom" parsing/compilation toolkit. It is an optimized lookup + based on analysis of the input keywords. Postprocessing was done + on the shilka output, but the basic structure and analysis is + from there. Should new HTTP methods be added, then manual insertion + into this code is fine, or simply re-running the shilka tool on + the appropriate input. */ + + /* Note: it is also quite reasonable to just use our method_registry, + but I'm assuming (probably incorrectly) we want more speed here + (based on the optimizations the previous code was doing). */ + + switch (len) + { + case 3: + switch (method[0]) + { + case 'A': + return (method[1] == 'C' + && method[2] == 'L' + ? SC_M_ACL : UNKNOWN_METHOD); + case 'P': + return (method[1] == 'U' + && method[2] == 'T' + ? SC_M_PUT : UNKNOWN_METHOD); + case 'G': + return (method[1] == 'E' + && method[2] == 'T' + ? SC_M_GET : UNKNOWN_METHOD); + default: + return UNKNOWN_METHOD; + } + + case 4: + switch (method[0]) + { + case 'H': + return (method[1] == 'E' + && method[2] == 'A' + && method[3] == 'D' + ? SC_M_HEAD : UNKNOWN_METHOD); + case 'P': + return (method[1] == 'O' + && method[2] == 'S' + && method[3] == 'T' + ? SC_M_POST : UNKNOWN_METHOD); + case 'M': + return (method[1] == 'O' + && method[2] == 'V' + && method[3] == 'E' + ? SC_M_MOVE : UNKNOWN_METHOD); + case 'L': + return (method[1] == 'O' + && method[2] == 'C' + && method[3] == 'K' + ? SC_M_LOCK : UNKNOWN_METHOD); + case 'C': + return (method[1] == 'O' + && method[2] == 'P' + && method[3] == 'Y' + ? SC_M_COPY : UNKNOWN_METHOD); + default: + return UNKNOWN_METHOD; + } + + case 5: + switch (method[2]) + { + case 'R': + return (memcmp(method, "MERGE", 5) == 0 + ? SC_M_MERGE : UNKNOWN_METHOD); + case 'C': + return (memcmp(method, "MKCOL", 5) == 0 + ? SC_M_MKCOL : UNKNOWN_METHOD); + case 'B': + return (memcmp(method, "LABEL", 5) == 0 + ? SC_M_LABEL : UNKNOWN_METHOD); + case 'A': + return (memcmp(method, "TRACE", 5) == 0 + ? SC_M_TRACE : UNKNOWN_METHOD); + default: + return UNKNOWN_METHOD; + } + + case 6: + switch (method[0]) + { + case 'U': + switch (method[5]) + { + case 'K': + return (memcmp(method, "UNLOCK", 6) == 0 + ? SC_M_UNLOCK : UNKNOWN_METHOD); + case 'E': + return (memcmp(method, "UPDATE", 6) == 0 + ? SC_M_UPDATE : UNKNOWN_METHOD); + default: + return UNKNOWN_METHOD; + } + case 'R': + return (memcmp(method, "REPORT", 6) == 0 + ? SC_M_REPORT : UNKNOWN_METHOD); + case 'S': + return (memcmp(method, "SEARCH", 6) == 0 + ? SC_M_SEARCH : UNKNOWN_METHOD); + case 'D': + return (memcmp(method, "DELETE", 6) == 0 + ? SC_M_DELETE : UNKNOWN_METHOD); + default: + return UNKNOWN_METHOD; + } + + case 7: + switch (method[1]) + { + case 'P': + return (memcmp(method, "OPTIONS", 7) == 0 + ? SC_M_OPTIONS : UNKNOWN_METHOD); + case 'H': + return (memcmp(method, "CHECKIN", 7) == 0 + ? SC_M_CHECKIN : UNKNOWN_METHOD); + default: + return UNKNOWN_METHOD; + } + + case 8: + switch (method[0]) + { + case 'P': + return (memcmp(method, "PROPFIND", 8) == 0 + ? SC_M_PROPFIND : UNKNOWN_METHOD); + case 'C': + return (memcmp(method, "CHECKOUT", 8) == 0 + ? SC_M_CHECKOUT : UNKNOWN_METHOD); + default: + return UNKNOWN_METHOD; + } + + case 9: + return (memcmp(method, "PROPPATCH", 9) == 0 + ? SC_M_PROPPATCH : UNKNOWN_METHOD); + + case 10: + switch (method[0]) + { + case 'U': + return (memcmp(method, "UNCHECKOUT", 10) == 0 + ? SC_M_UNCHECKOUT : UNKNOWN_METHOD); + case 'M': + return (memcmp(method, "MKACTIVITY", 10) == 0 + ? SC_M_MKACTIVITY : UNKNOWN_METHOD); + default: + return UNKNOWN_METHOD; + } + + case 11: + return (memcmp(method, "MKWORKSPACE", 11) == 0 + ? SC_M_MKWORKSPACE : UNKNOWN_METHOD); + + case 15: + return (memcmp(method, "VERSION-CONTROL", 15) == 0 + ? SC_M_VERSION_CONTROL : UNKNOWN_METHOD); + + case 16: + return (memcmp(method, "BASELINE-CONTROL", 16) == 0 + ? SC_M_BASELINE_CONTROL : UNKNOWN_METHOD); + + default: + return UNKNOWN_METHOD; + } + + /* NOTREACHED */ +} + +static int sc_for_req_header(const char *header_name) +{ + char header[16]; + size_t len = strlen(header_name); + const char *p = header_name; + int i = 0; + + /* ACCEPT-LANGUAGE is the longest header + * that is of interest. + */ + if (len < 4 || len > 15) + return UNKNOWN_METHOD; + + while (*p) { + header[i++] = toupper((unsigned char)*p); + p++; + } + + header[i] = '\0'; + p = &header[1]; + +/* Always do memcmp including the final \0-termination character. + */ + switch (header[0]) { + case 'A': + if (memcmp(p, "CCEPT", 6) == 0) { + if (!header[6]) + return SC_ACCEPT; + else if (header[6] == '-') { + p += 6; + if (memcmp(p, "CHARSET", 8) == 0) + return SC_ACCEPT_CHARSET; + else if (memcmp(p, "ENCODING", 9) == 0) + return SC_ACCEPT_ENCODING; + else if (memcmp(p, "LANGUAGE", 9) == 0) + return SC_ACCEPT_LANGUAGE; + else + return UNKNOWN_METHOD; + } + else + return UNKNOWN_METHOD; + } + else if (memcmp(p, "UTHORIZATION", 13) == 0) + return SC_AUTHORIZATION; + else + return UNKNOWN_METHOD; + break; + case 'C': + if(memcmp(p, "OOKIE2", 7) == 0) + return SC_COOKIE2; + else if (memcmp(p, "OOKIE", 6) == 0) + return SC_COOKIE; + else if(memcmp(p, "ONNECTION", 10) == 0) + return SC_CONNECTION; + else if(memcmp(p, "ONTENT-TYPE", 12) == 0) + return SC_CONTENT_TYPE; + else if(memcmp(p, "ONTENT-LENGTH", 14) == 0) + return SC_CONTENT_LENGTH; + else + return UNKNOWN_METHOD; + break; + case 'H': + if(memcmp(p, "OST", 4) == 0) + return SC_HOST; + else + return UNKNOWN_METHOD; + break; + case 'P': + if(memcmp(p, "RAGMA", 6) == 0) + return SC_PRAGMA; + else + return UNKNOWN_METHOD; + break; + case 'R': + if(memcmp(p, "EFERER", 7) == 0) + return SC_REFERER; + else + return UNKNOWN_METHOD; + break; + case 'U': + if(memcmp(p, "SER-AGENT", 10) == 0) + return SC_USER_AGENT; + else + return UNKNOWN_METHOD; + break; + default: + return UNKNOWN_METHOD; + } + /* NOTREACHED */ +} + +/* Return the string representation of the worker state */ +const char *jk_ajp_get_state(ajp_worker_t *aw, jk_logger_t *l) +{ + return ajp_state_type[aw->s->state]; +} + +/* Return the int representation of the worker state */ +int jk_ajp_get_state_code(const char *v) +{ + if (!v) + return JK_AJP_STATE_DEF; + else if (*v == 'i' || *v == 'I' || *v == 'n' || *v == 'N' || *v == '0') + return JK_AJP_STATE_IDLE; + else if (*v == 'o' || *v == 'O' || *v == '1') + return JK_AJP_STATE_OK; + else if (*v == 'e' || *v == 'E' || *v == '4') + return JK_AJP_STATE_ERROR; + else if (*v == 'p' || *v == 'P' || *v == '6') + return JK_AJP_STATE_PROBE; + else + return JK_AJP_STATE_DEF; +} + +int jk_ajp_get_cping_mode(const char *m, int def) +{ + int mv = def; + if (!m) + return mv; + while (*m != '\0') { + if (*m == 'C' || *m == 'c') + mv |= AJP_CPING_CONNECT; + else if (*m == 'P' || *m == 'p') + mv |= AJP_CPING_PREPOST; + else if (*m == 'I' || *m == 'i') + mv |= AJP_CPING_INTERVAL; + else if (*m == 'A' || *m == 'a') { + mv = AJP_CPING_CONNECT | AJP_CPING_PREPOST | AJP_CPING_INTERVAL; + break; + } + m++; + } + return mv; +} + +/* + * Message structure + * + * +AJPV13_REQUEST/AJPV14_REQUEST= + request_prefix (1) (byte) + method (byte) + protocol (string) + req_uri (string) + remote_addr (string) + remote_host (string) + server_name (string) + server_port (short) + is_ssl (boolean) + num_headers (short) + num_headers*(req_header_name header_value) + + ?context (byte)(string) + ?servlet_path (byte)(string) + ?remote_user (byte)(string) + ?auth_type (byte)(string) + ?query_string (byte)(string) + ?route (byte)(string) + ?ssl_cert (byte)(string) + ?ssl_cipher (byte)(string) + ?ssl_session (byte)(string) + ?ssl_key_size (byte)(int) via JkOptions +ForwardKeySize + request_terminator (byte) + ?body content_length*(var binary) + + */ + +static int ajp_marshal_into_msgb(jk_msg_buf_t *msg, + jk_ws_service_t *s, + jk_logger_t *l, ajp_endpoint_t * ae) +{ + int method; + unsigned int i; + + JK_TRACE_ENTER(l); + + if ((method = sc_for_req_method(s->method, + strlen(s->method))) == UNKNOWN_METHOD) + method = SC_M_JK_STORED; + + if (jk_b_append_byte(msg, JK_AJP13_FORWARD_REQUEST) || + jk_b_append_byte(msg, (unsigned char)method) || + jk_b_append_string(msg, s->protocol) || + jk_b_append_string(msg, s->req_uri) || + jk_b_append_string(msg, s->remote_addr) || + jk_b_append_string(msg, s->remote_host) || + jk_b_append_string(msg, s->server_name) || + jk_b_append_int(msg, (unsigned short)s->server_port) || + jk_b_append_byte(msg, (unsigned char)(s->is_ssl)) || + jk_b_append_int(msg, (unsigned short)(s->num_headers))) { + + jk_log(l, JK_LOG_ERROR, + "failed appending the message begining"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + for (i = 0; i < s->num_headers; i++) { + int sc; + + if ((sc = sc_for_req_header(s->headers_names[i])) != UNKNOWN_METHOD) { + if (jk_b_append_int(msg, (unsigned short)sc)) { + jk_log(l, JK_LOG_ERROR, + "failed appending the header name"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + else { + if (jk_b_append_string(msg, s->headers_names[i])) { + jk_log(l, JK_LOG_ERROR, + "failed appending the header name"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + + if (jk_b_append_string(msg, s->headers_values[i])) { + jk_log(l, JK_LOG_ERROR, + "failed appending the header value"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + + if (s->secret) { + if (jk_b_append_byte(msg, SC_A_SECRET) || + jk_b_append_string(msg, s->secret)) { + jk_log(l, JK_LOG_ERROR, + "failed appending secret"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + + if (s->remote_user) { + if (jk_b_append_byte(msg, SC_A_REMOTE_USER) || + jk_b_append_string(msg, s->remote_user)) { + jk_log(l, JK_LOG_ERROR, + "failed appending the remote user"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + if (s->auth_type) { + if (jk_b_append_byte(msg, SC_A_AUTH_TYPE) || + jk_b_append_string(msg, s->auth_type)) { + jk_log(l, JK_LOG_ERROR, + "failed appending the auth type"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + if (s->query_string) { + if (jk_b_append_byte(msg, SC_A_QUERY_STRING) || +#if defined(AS400) && !defined(AS400_UTF8) + jk_b_append_asciistring(msg, s->query_string)) { +#else + jk_b_append_string(msg, s->query_string)) { +#endif + jk_log(l, JK_LOG_ERROR, + "failed appending the query string"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + if (s->route) { + if (jk_b_append_byte(msg, SC_A_ROUTE) || + jk_b_append_string(msg, s->route)) { + jk_log(l, JK_LOG_ERROR, + "failed appending the route"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + if (s->ssl_cert_len) { + if (jk_b_append_byte(msg, SC_A_SSL_CERT) || + jk_b_append_string(msg, s->ssl_cert)) { + jk_log(l, JK_LOG_ERROR, + "failed appending the SSL certificates"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + + if (s->ssl_cipher) { + if (jk_b_append_byte(msg, SC_A_SSL_CIPHER) || + jk_b_append_string(msg, s->ssl_cipher)) { + jk_log(l, JK_LOG_ERROR, + "failed appending the SSL ciphers"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + if (s->ssl_session) { + if (jk_b_append_byte(msg, SC_A_SSL_SESSION) || + jk_b_append_string(msg, s->ssl_session)) { + jk_log(l, JK_LOG_ERROR, + "failed appending the SSL session"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + + /* + * ssl_key_size is required by Servlet 2.3 API + * added support only in ajp14 mode + * JFC removed: ae->proto == AJP14_PROTO + */ + if (s->ssl_key_size != -1) { + if (jk_b_append_byte(msg, SC_A_SSL_KEY_SIZE) || + jk_b_append_int(msg, (unsigned short)s->ssl_key_size)) { + jk_log(l, JK_LOG_ERROR, + "failed appending the SSL key size"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + + /* If the method was unrecognized, encode it as an attribute */ + if (method == SC_M_JK_STORED) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, "unknown method %s", s->method); + if (jk_b_append_byte(msg, SC_A_STORED_METHOD) || + jk_b_append_string(msg, s->method)) { + jk_log(l, JK_LOG_ERROR, + "failed appending the request method"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + + /* Forward the remote port information, which was forgotten + * from the builtin data of the AJP 13 protocol. + * Since the servlet spec allows to retrieve it via getRemotePort(), + * we provide the port to the Tomcat connector as a request + * attribute. Modern Tomcat versions know how to retrieve + * the remote port from this attribute. + */ + { + if (jk_b_append_byte(msg, SC_A_REQ_ATTRIBUTE) || + jk_b_append_string(msg, SC_A_REQ_REMOTE_PORT) || + jk_b_append_string(msg, s->remote_port)) { + jk_log(l, JK_LOG_ERROR, + "failed appending the remote port %s", + s->remote_port); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + + /* Forward activation information from the load balancer. + * It can be used by the backend to deny access by requests, + * which come with a session id but for an invalid session. + * Such requests get forwarded to backends even if they + * are disabled" in the load balancer, because the balancer + * does not know, which sessions are valid. + * If the backend can check, that is was "disabled" it can + * delete the session cookie and respond with a self-referential + * redirect. The new request will then be balanced to some + * other node that is not disabled. + */ + { + if (jk_b_append_byte(msg, SC_A_REQ_ATTRIBUTE) || + jk_b_append_string(msg, SC_A_JK_LB_ACTIVATION) || + jk_b_append_string(msg, s->activation)) { + jk_log(l, JK_LOG_ERROR, + "failed appending the activation state %s", + s->activation); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + + if (s->num_attributes > 0) { + for (i = 0; i < s->num_attributes; i++) { + if (jk_b_append_byte(msg, SC_A_REQ_ATTRIBUTE) || + jk_b_append_string(msg, s->attributes_names[i]) || + jk_b_append_string(msg, s->attributes_values[i])) { + jk_log(l, JK_LOG_ERROR, + "failed appending attribute %s=%s", + s->attributes_names[i], s->attributes_values[i]); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + } + + if (jk_b_append_byte(msg, SC_A_ARE_DONE)) { + jk_log(l, JK_LOG_ERROR, + "failed appending the message end"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, "ajp marshaling done"); + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +/* +AJPV13_RESPONSE/AJPV14_RESPONSE:= + response_prefix (2) + status (short) + status_msg (short) + num_headers (short) + num_headers*(res_header_name header_value) + *body_chunk + terminator boolean <! -- recycle connection or not --> + +req_header_name := + sc_req_header_name | (string) + +res_header_name := + sc_res_header_name | (string) + +header_value := + (string) + +body_chunk := + length (short) + body length*(var binary) + + */ + + +static int ajp_unmarshal_response(jk_msg_buf_t *msg, + jk_res_data_t * d, + ajp_endpoint_t * ae, jk_logger_t *l) +{ + jk_pool_t *p = &ae->pool; + + JK_TRACE_ENTER(l); + + d->status = jk_b_get_int(msg); + if (!d->status) { + jk_log(l, JK_LOG_ERROR, + "NULL status"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + d->msg = (char *)jk_b_get_string(msg); + if (d->msg) { +#if (defined(AS400) && !defined(AS400_UTF8)) || defined(_OSD_POSIX) + jk_xlate_from_ascii(d->msg, strlen(d->msg)); +#endif + } + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "status = %d", d->status); + + d->num_headers = jk_b_get_int(msg); + d->header_names = d->header_values = NULL; + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Number of headers is = %d", + d->num_headers); + + if (d->num_headers) { + d->header_names = jk_pool_alloc(p, sizeof(char *) * d->num_headers); + d->header_values = jk_pool_alloc(p, sizeof(char *) * d->num_headers); + + if (d->header_names && d->header_values) { + unsigned int i; + for (i = 0; i < d->num_headers; i++) { + unsigned short name = jk_b_pget_int(msg, msg->pos); + + if ((name & 0XFF00) == 0XA000) { + jk_b_get_int(msg); + name = name & 0X00FF; + if (name <= SC_RES_HEADERS_NUM) { + d->header_names[i] = + (char *)long_res_header_for_sc(name); + } + else { + jk_log(l, JK_LOG_ERROR, + "No such sc (%d)", name); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + else { + d->header_names[i] = (char *)jk_b_get_string(msg); + if (!d->header_names[i]) { + jk_log(l, JK_LOG_ERROR, + "NULL header name"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } +#if (defined(AS400) && !defined(AS400_UTF8)) || defined(_OSD_POSIX) + jk_xlate_from_ascii(d->header_names[i], + strlen(d->header_names[i])); +#endif + + } + + d->header_values[i] = (char *)jk_b_get_string(msg); + if (!d->header_values[i]) { + jk_log(l, JK_LOG_ERROR, + "NULL header value"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + +#if (defined(AS400) && !defined(AS400_UTF8)) || defined(_OSD_POSIX) + jk_xlate_from_ascii(d->header_values[i], + strlen(d->header_values[i])); +#endif + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Header[%d] [%s] = [%s]", + i, d->header_names[i], d->header_values[i]); + } + } + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +/* + * Abort endpoint use + */ +static void ajp_abort_endpoint(ajp_endpoint_t * ae, int shutdown, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + if (shutdown == JK_TRUE && IS_VALID_SOCKET(ae->sd)) { + if (ae->hard_close) { + /* Force unclean connection close to communicate client write errors + * back to Tomcat by aborting AJP response writes. + */ + jk_close_socket(ae->sd, l); + } + else { + jk_shutdown_socket(ae->sd, l); + } + } + ae->worker->s->connected--; + ae->sd = JK_INVALID_SOCKET; + ae->last_op = JK_AJP13_END_RESPONSE; + JK_TRACE_EXIT(l); +} + +/* + * Reset the endpoint (clean buf and close socket) + */ +static void ajp_reset_endpoint(ajp_endpoint_t * ae, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "(%s) resetting endpoint with socket %d%s", + ae->worker->name, ae->sd, ae->reuse? "" : " (socket shutdown)"); + if (!ae->reuse) { + ajp_abort_endpoint(ae, JK_TRUE, l); + } + jk_reset_pool(&(ae->pool)); + JK_TRACE_EXIT(l); +} + +/* + * Close the endpoint (close pool and close socket) + */ +void ajp_close_endpoint(ajp_endpoint_t * ae, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "(%s) closing endpoint with socket %d%s", + ae->worker->name, ae->sd, ae->reuse ? "" : " (socket shutdown)"); + if (IS_VALID_SOCKET(ae->sd)) { + jk_shutdown_socket(ae->sd, l); + } + ae->sd = JK_INVALID_SOCKET; + jk_close_pool(&(ae->pool)); + free(ae); + JK_TRACE_EXIT(l); +} + + +/** Steal a connection from an idle cache endpoint + * @param ae endpoint that needs a new connection + * @param l logger + * @return JK_FALSE: failure + * JK_TRUE: success + * @remark Always closes old socket endpoint + */ +static int ajp_next_connection(ajp_endpoint_t *ae, jk_logger_t *l) +{ + int rc; + int ret = JK_FALSE; + ajp_worker_t *aw = ae->worker; + + JK_TRACE_ENTER(l); + + /* Close previous socket */ + if (IS_VALID_SOCKET(ae->sd)) + jk_shutdown_socket(ae->sd, l); + /* Mark existing endpoint socket as closed */ + ae->sd = JK_INVALID_SOCKET; + JK_ENTER_CS(&aw->cs, rc); + if (rc) { + unsigned int i; + for (i = 0; i < aw->ep_cache_sz; i++) { + /* Find cache slot with usable socket */ + if (aw->ep_cache[i] && IS_VALID_SOCKET(aw->ep_cache[i]->sd)) { + ae->sd = aw->ep_cache[i]->sd; + aw->ep_cache[i]->sd = JK_INVALID_SOCKET; + break; + } + } + JK_LEAVE_CS(&aw->cs, rc); + if (IS_VALID_SOCKET(ae->sd)) { + ret = JK_TRUE; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "(%s) Will try pooled connection socket %d from slot %d", + ae->worker->name, ae->sd, i); + } + } + JK_TRACE_EXIT(l); + return ret; +} + +/** Handle the cping/cpong query + * @param ae endpoint + * @param timeout wait timeout in milliseconds + * @param l logger + * @return JK_FALSE: failure + * JK_TRUE: success + * @remark Always closes socket in case of + * a socket error + */ +static int ajp_handle_cping_cpong(ajp_endpoint_t * ae, int timeout, jk_logger_t *l) +{ + int i; + int cmd; + jk_msg_buf_t *msg; + + JK_TRACE_ENTER(l); + + ae->last_errno = 0; + msg = jk_b_new(&ae->pool); + if (!msg) { + jk_log(l, JK_LOG_ERROR, + "Failed allocating AJP message"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + if (jk_b_set_buffer_size(msg, 16)) { + jk_log(l, JK_LOG_ERROR, + "Failed allocating AJP message buffer"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + jk_b_reset(msg); + jk_b_append_byte(msg, AJP13_CPING_REQUEST); + + /* Send CPing query */ + if (ajp_connection_tcp_send_message(ae, msg, l) != JK_TRUE) { + jk_log(l, JK_LOG_INFO, + "can't send cping query"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + for (i = 0; i < 2; i++) { + /* wait for Pong reply for timeout milliseconds + */ + if (jk_is_input_event(ae->sd, timeout, l) == JK_FALSE) { + ae->last_errno = errno; + jk_log(l, JK_LOG_INFO, "timeout in reply cpong"); + /* We can't trust this connection any more. */ + ajp_abort_endpoint(ae, JK_TRUE, l); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + /* Read and check for Pong reply + */ + if (ajp_connection_tcp_get_message(ae, msg, l) != JK_TRUE) { + jk_log(l, JK_LOG_INFO, + "awaited reply cpong, not received"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if ((cmd = jk_b_get_byte(msg)) != AJP13_CPONG_REPLY) { + /* If the respose was not CPONG it means that + * the previous response was not consumed by the + * client but the AJP messages was already in + * the network buffer. + * silently drop this single extra packet instead + * recycling the connection + */ + if (i || ae->last_op == JK_AJP13_END_RESPONSE || + cmd < JK_AJP13_SEND_BODY_CHUNK || + cmd > AJP13_CPONG_REPLY) { + jk_log(l, JK_LOG_WARNING, + "awaited reply cpong, received %d instead. " + "Closing connection", + cmd); + /* We can't trust this connection any more. */ + ajp_abort_endpoint(ae, JK_TRUE, l); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + else { + jk_log(l, JK_LOG_INFO, + "awaited reply cpong, received %d instead. " + "Retrying next packet", + cmd); + + } + } + else { + ae->last_op = AJP13_CPONG_REPLY; + /* We have received Pong reply */ + break; + } + } + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +/** Connect an endpoint to a backend + * @param ae endpoint + * @param l logger + * @return JK_FALSE: failure + * JK_TRUE: success + * @remark Always closes socket in case of + * a socket error + * @remark Cares about ae->last_errno + */ +int ajp_connect_to_endpoint(ajp_endpoint_t * ae, jk_logger_t *l) +{ + char buf[32]; + int rc = JK_TRUE; + + JK_TRACE_ENTER(l); + + ae->last_errno = 0; + ae->sd = jk_open_socket(&ae->worker->worker_inet_addr, + ae->worker->keepalive, + ae->worker->socket_timeout, + ae->worker->socket_connect_timeout, + ae->worker->socket_buf, l); + + if (!IS_VALID_SOCKET(ae->sd)) { + ae->last_errno = errno; + jk_log(l, JK_LOG_INFO, + "Failed opening socket to (%s) (errno=%d)", + jk_dump_hinfo(&ae->worker->worker_inet_addr, buf), ae->last_errno); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + ae->worker->s->connected++; + /* set last_access only if needed */ + if (ae->worker->cache_timeout > 0) + ae->last_access = time(NULL); + /* Check if we must execute a logon after the physical connect */ + /* XXX: Not sure, if we really should do logon before cping/cpong */ + /* XXX: and if no cping/cpong is allowed before or after logon. */ + if (ae->worker->logon != NULL) { + rc = ae->worker->logon(ae, l); + if (rc == JK_FALSE) { + jk_log(l, JK_LOG_ERROR, + "(%s) ajp14 worker logon to the backend server failed", + ae->worker->name); + /* Close the socket if unable to logon */ + ajp_abort_endpoint(ae, JK_TRUE, l); + } + } + /* XXX: Should we send a cping also after logon to validate the connection? */ + else if (ae->worker->connect_timeout > 0) { + rc = ajp_handle_cping_cpong(ae, ae->worker->connect_timeout, l); + if (rc == JK_FALSE) + jk_log(l, JK_LOG_ERROR, + "(%s) cping/cpong after connecting to the backend server failed (errno=%d)", + ae->worker->name, ae->last_errno); + } + JK_TRACE_EXIT(l); + return rc; +} + +/* Syncing config values from shm */ +void jk_ajp_pull(ajp_worker_t * aw, int locked, jk_logger_t *l) +{ + int address_change = JK_FALSE; + int port = 0; + char host[JK_SHM_STR_SIZ+1]; + struct sockaddr_in inet_addr; + JK_TRACE_ENTER(l); + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "syncing mem for ajp worker '%s' from shm (%u -> %u) [%u->%u]", + aw->name, aw->sequence, aw->s->h.sequence, aw->addr_sequence, aw->s->addr_sequence); + if (locked == JK_FALSE) + jk_shm_lock(); + + aw->cache_timeout = aw->s->cache_timeout; + aw->connect_timeout = aw->s->connect_timeout; + aw->ping_timeout = aw->s->ping_timeout; + aw->reply_timeout = aw->s->reply_timeout; + aw->prepost_timeout = aw->s->prepost_timeout; + aw->recovery_opts = aw->s->recovery_opts; + aw->retries = aw->s->retries; + aw->retry_interval = aw->s->retry_interval; + aw->max_packet_size = aw->s->max_packet_size; + aw->sequence = aw->s->h.sequence; + if (aw->addr_sequence != aw->s->addr_sequence) { + address_change = JK_TRUE; + aw->addr_sequence = aw->s->addr_sequence; + strncpy(host, aw->s->host, JK_SHM_STR_SIZ); + port = aw->s->port; + } + if (locked == JK_FALSE) + jk_shm_unlock(); + + if (address_change == JK_TRUE) { + if (!jk_resolve(host, port, &inet_addr, + aw->worker.we->pool, l)) { + jk_log(l, JK_LOG_ERROR, + "Failed resolving address '%s:%d' for worker '%s'.", + host, port, aw->name); + } + else { + int rc; + JK_ENTER_CS(&aw->cs, rc); + if (rc) { + unsigned int i; + for (i = 0; i < aw->ep_cache_sz; i++) { + /* Close all connections in the cache */ + if (aw->ep_cache[i] && IS_VALID_SOCKET(aw->ep_cache[i]->sd)) { + int sd = aw->ep_cache[i]->sd; + aw->ep_cache[i]->sd = JK_INVALID_SOCKET; + aw->ep_cache[i]->addr_sequence = aw->addr_sequence; + jk_shutdown_socket(sd, l); + aw->s->connected--; + } + } + } + aw->port = port; + strncpy(aw->host, host, JK_SHM_STR_SIZ); + memcpy(&(aw->worker_inet_addr), &inet_addr, sizeof(inet_addr)); + if (rc) { + JK_LEAVE_CS(&aw->cs, rc); + } else { + jk_log(l, JK_LOG_ERROR, + "locking thread (errno=%d)", errno); + } + } + } + + JK_TRACE_EXIT(l); +} + +/* Syncing config values to shm */ +void jk_ajp_push(ajp_worker_t * aw, int locked, jk_logger_t *l) +{ + int address_change = JK_FALSE; + + JK_TRACE_ENTER(l); + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "syncing shm for ajp worker '%s' from mem (%u -> %u) [%u->%u]", + aw->name, aw->s->h.sequence, aw->sequence, aw->s->addr_sequence, aw->addr_sequence); + if (locked == JK_FALSE) + jk_shm_lock(); + + aw->s->cache_timeout = aw->cache_timeout; + aw->s->connect_timeout = aw->connect_timeout; + aw->s->ping_timeout = aw->ping_timeout; + aw->s->reply_timeout = aw->reply_timeout; + aw->s->prepost_timeout = aw->prepost_timeout; + aw->s->recovery_opts = aw->recovery_opts; + aw->s->retries = aw->retries; + aw->s->retry_interval = aw->retry_interval; + aw->s->max_packet_size = aw->max_packet_size; + aw->s->h.sequence = aw->sequence; + if (aw->s->addr_sequence != aw->addr_sequence) { + address_change = JK_TRUE; + strncpy(aw->s->host, aw->host, JK_SHM_STR_SIZ); + aw->s->port = aw->port; + aw->s->addr_sequence = aw->addr_sequence; + } + if (locked == JK_FALSE) + jk_shm_unlock(); + + if (address_change == JK_TRUE) { + int rc; + JK_ENTER_CS(&aw->cs, rc); + if (rc) { + unsigned int i; + for (i = 0; i < aw->ep_cache_sz; i++) { + /* Close all connections in the cache */ + if (aw->ep_cache[i] && IS_VALID_SOCKET(aw->ep_cache[i]->sd)) { + int sd = aw->ep_cache[i]->sd; + aw->ep_cache[i]->sd = JK_INVALID_SOCKET; + aw->ep_cache[i]->addr_sequence = aw->addr_sequence; + jk_shutdown_socket(sd, l); + aw->s->connected--; + } + } + JK_LEAVE_CS(&aw->cs, rc); + } else { + jk_log(l, JK_LOG_ERROR, + "locking thread (errno=%d)", errno); + } + } + JK_TRACE_EXIT(l); +} + +/** Send a message to an endpoint, using corresponding PROTO HEADER + * @param ae endpoint + * @param msg message to send + * @param l logger + * @return JK_FATAL_ERROR: endpoint contains unknown protocol + * JK_FALSE: other failure + * JK_TRUE: success + * @remark Always closes socket in case of + * a socket error, or JK_FATAL_ERROR + * @remark Cares about ae->last_errno + */ +int ajp_connection_tcp_send_message(ajp_endpoint_t * ae, + jk_msg_buf_t *msg, jk_logger_t *l) +{ + int rc; + + JK_TRACE_ENTER(l); + + ae->last_errno = 0; + if (ae->proto == AJP13_PROTO) { + jk_b_end(msg, AJP13_WS_HEADER); + if (JK_IS_DEBUG_LEVEL(l)) + jk_dump_buff(l, JK_LOG_DEBUG, "sending to ajp13", msg); + } + else if (ae->proto == AJP14_PROTO) { + jk_b_end(msg, AJP14_WS_HEADER); + if (JK_IS_DEBUG_LEVEL(l)) + jk_dump_buff(l, JK_LOG_DEBUG, "sending to ajp14", msg); + } + else { + jk_log(l, JK_LOG_ERROR, + "(%s) unknown protocol %d, supported are AJP13/AJP14", + ae->worker->name, ae->proto); + /* We've got a protocol error. */ + /* We can't trust this connection any more, */ + /* because we might have send already parts of the request. */ + ajp_abort_endpoint(ae, JK_TRUE, l); + JK_TRACE_EXIT(l); + return JK_FATAL_ERROR; + } + + /* This is the only place in this function where we use the socket. */ + /* If sendfull gets an error, it implicitely closes the socket. */ + /* So any socket error inside ajp_connection_tcp_send_message */ + /* results in a socket close and invalidated endpoint connection. */ + if ((rc = jk_tcp_socket_sendfull(ae->sd, msg->buf, + msg->len, l)) > 0) { + ae->endpoint.wr += (jk_uint64_t)rc; + JK_TRACE_EXIT(l); + return JK_TRUE; + } + ae->last_errno = errno; + jk_log(l, JK_LOG_INFO, + "sendfull for socket %d returned %d (errno=%d)", + ae->sd, rc, ae->last_errno); + ajp_abort_endpoint(ae, JK_FALSE, l); + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +/** Receive a message from an endpoint, checking PROTO HEADER + * @param ae endpoint + * @param msg message to send + * @param l logger + * @return JK_TRUE: success + * JK_FALSE: could not read the AJP packet header + * JK_AJP_PROTOCOL_ERROR: failure after reading + * the AJP packet header + * @remark Always closes socket in case of + * a socket error + * @remark Cares about ae->last_errno + */ +int ajp_connection_tcp_get_message(ajp_endpoint_t * ae, + jk_msg_buf_t *msg, jk_logger_t *l) +{ + unsigned char head[AJP_HEADER_LEN]; + int rc; + int msglen; + unsigned int header; + char buf[32]; + + JK_TRACE_ENTER(l); + + ae->last_errno = 0; + /* If recvfull gets an error, it implicitely closes the socket. */ + /* We will invalidate the endpoint connection. */ + rc = jk_tcp_socket_recvfull(ae->sd, head, AJP_HEADER_LEN, l); + + /* If the return code is not negative */ + /* then we always get back the correct number of bytes. */ + if (rc < 0) { + if (rc == JK_SOCKET_EOF) { + ae->last_errno = EPIPE; + jk_log(l, JK_LOG_INFO, + "(%s) can't receive the response header message from tomcat, " + "tomcat (%s) has forced a connection close for socket %d", + ae->worker->name, jk_dump_hinfo(&ae->worker->worker_inet_addr, buf), + ae->sd); + } + else { + ae->last_errno = -rc; + jk_log(l, JK_LOG_INFO, + "(%s) can't receive the response header message from tomcat, " + "network problems or tomcat (%s) is down (errno=%d)", + ae->worker->name, jk_dump_hinfo(&ae->worker->worker_inet_addr, buf), + ae->last_errno); + } + ajp_abort_endpoint(ae, JK_FALSE, l); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + ae->endpoint.rd += (jk_uint64_t)rc; + header = ((unsigned int)head[0] << 8) | head[1]; + + if (ae->proto == AJP13_PROTO) { + if (header != AJP13_SW_HEADER) { + + if (header == AJP14_SW_HEADER) { + jk_log(l, JK_LOG_ERROR, + "received AJP14 reply on an AJP13 connection from %s", + jk_dump_hinfo(&ae->worker->worker_inet_addr, buf)); + } + else { + jk_log(l, JK_LOG_ERROR, + "wrong message format 0x%04x from %s", + header, jk_dump_hinfo(&ae->worker->worker_inet_addr, + buf)); + } + /* We've got a protocol error. */ + /* We can't trust this connection any more. */ + ajp_abort_endpoint(ae, JK_TRUE, l); + JK_TRACE_EXIT(l); + return JK_AJP_PROTOCOL_ERROR; + } + } + else if (ae->proto == AJP14_PROTO) { + if (header != AJP14_SW_HEADER) { + + if (header == AJP13_SW_HEADER) { + jk_log(l, JK_LOG_ERROR, + "received AJP13 reply on an AJP14 connection from %s", + jk_dump_hinfo(&ae->worker->worker_inet_addr, buf)); + } + else { + jk_log(l, JK_LOG_ERROR, + "wrong message format 0x%04x from %s", + header, jk_dump_hinfo(&ae->worker->worker_inet_addr, + buf)); + } + /* We've got a protocol error. */ + /* We can't trust this connection any more. */ + ajp_abort_endpoint(ae, JK_TRUE, l); + JK_TRACE_EXIT(l); + return JK_AJP_PROTOCOL_ERROR; + } + } + + msglen = ((head[2] & 0xff) << 8); + msglen += (head[3] & 0xFF); + + if (msglen > msg->maxlen) { + jk_log(l, JK_LOG_ERROR, + "wrong message size %d %d from %s", + msglen, msg->maxlen, + jk_dump_hinfo(&ae->worker->worker_inet_addr, buf)); + /* We've got a protocol error. */ + /* We can't trust this connection any more. */ + ajp_abort_endpoint(ae, JK_TRUE, l); + JK_TRACE_EXIT(l); + return JK_AJP_PROTOCOL_ERROR; + } + + msg->len = msglen; + msg->pos = 0; + + /* If recvfull gets an error, it implicitely closes the socket. */ + /* We will invalidate the endpoint connection. */ + rc = jk_tcp_socket_recvfull(ae->sd, msg->buf, msglen, l); + /* If the return code is not negative */ + /* then we always get back the correct number of bytes. */ + if (rc < 0) { + if (rc == JK_SOCKET_EOF) { + ae->last_errno = EPIPE; + jk_log(l, JK_LOG_ERROR, + "(%s) can't receive the response body message from tomcat, " + "tomcat (%s) has forced a connection close for socket %d", + ae->worker->name, jk_dump_hinfo(&ae->worker->worker_inet_addr, buf), + ae->sd); + } + else { + ae->last_errno = -rc; + jk_log(l, JK_LOG_ERROR, + "(%s) can't receive the response body message from tomcat, " + "network problems or tomcat (%s) is down (errno=%d)", + ae->worker->name, jk_dump_hinfo(&ae->worker->worker_inet_addr, buf), + ae->last_errno); + } + ajp_abort_endpoint(ae, JK_FALSE, l); + JK_TRACE_EXIT(l); + /* Although we have a connection, this is effectively a protocol error. + * We received the AJP header packet, but not the packet payload + */ + return JK_AJP_PROTOCOL_ERROR; + } + ae->endpoint.rd += (jk_uint64_t)rc; + + if (JK_IS_DEBUG_LEVEL(l)) { + if (ae->proto == AJP13_PROTO) + jk_dump_buff(l, JK_LOG_DEBUG, "received from ajp13", msg); + else if (ae->proto == AJP14_PROTO) + jk_dump_buff(l, JK_LOG_DEBUG, "received from ajp14", msg); + } + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +/* + * Read all the data from the socket. + * + * Socket API doesn't guaranty that all the data will be kept in a + * single read, so we must loop until all awaited data is received + */ + +static int ajp_read_fully_from_server(jk_ws_service_t *s, jk_logger_t *l, + unsigned char *buf, unsigned int len) +{ + unsigned int rdlen = 0; + unsigned int padded_len = len; + + JK_TRACE_ENTER(l); + + if (s->is_chunked && s->no_more_chunks) { + JK_TRACE_EXIT(l); + return 0; + } + if (s->is_chunked) { + /* Corner case: buf must be large enough to hold next + * chunk size (if we're on or near a chunk border). + * Pad the length to a reasonable value, otherwise the + * read fails and the remaining chunks are tossed. + */ + padded_len = (len < CHUNK_BUFFER_PAD) ? len : len - CHUNK_BUFFER_PAD; + } + + while (rdlen < padded_len) { + unsigned int this_time = 0; + if (!s->read(s, buf + rdlen, len - rdlen, &this_time)) { + /* Remote Client read failed. */ + JK_TRACE_EXIT(l); + return JK_CLIENT_RD_ERROR; + } + + if (0 == this_time) { + if (s->is_chunked) { + s->no_more_chunks = 1; /* read no more */ + } + break; + } + rdlen += this_time; + } + + JK_TRACE_EXIT(l); + return (int)rdlen; +} + + +/* + * Read data from AJP13/AJP14 protocol + * Returns -1 on error, else number of bytes read + */ + +static int ajp_read_into_msg_buff(ajp_endpoint_t * ae, + jk_ws_service_t *r, + jk_msg_buf_t *msg, int len, jk_logger_t *l) +{ + unsigned char *read_buf = msg->buf; + + JK_TRACE_ENTER(l); + + jk_b_reset(msg); + + read_buf += AJP_HEADER_LEN; /* leave some space for the buffer headers */ + read_buf += AJP_HEADER_SZ_LEN; /* leave some space for the read length */ + + /* Pick the max size since we don't know the content_length */ + if (r->is_chunked && len == 0) { + len = AJP13_MAX_SEND_BODY_SZ; + } + + if ((len = ajp_read_fully_from_server(r, l, read_buf, len)) < 0) { + jk_log(l, JK_LOG_INFO, + "(%s) receiving data from client failed. " + "Connection aborted or network problems", + ae->worker->name); + JK_TRACE_EXIT(l); + return JK_CLIENT_RD_ERROR; + } + + if (!r->is_chunked) { + ae->left_bytes_to_send -= len; + } + + if (len > 0) { + /* Recipient recognizes empty packet as end of stream, not + an empty body packet */ + if (0 != jk_b_append_int(msg, (unsigned short)len)) { + jk_log(l, JK_LOG_INFO, + "Failed appending message length"); + JK_TRACE_EXIT(l); + return JK_CLIENT_RD_ERROR; + } + } + + msg->len += len; + + JK_TRACE_EXIT(l); + return len; +} + + +/* + * send request to Tomcat via Ajp13 + * - first try to find reuseable socket + * - if no such available, try to connect + * - send request, but send must be seen as asynchronous, + * since send() call will return noerror about 95% of time + * Hopefully we'll get more information on next read. + * + * nb: op->request is the original request msg buffer + * op->reply is the reply msg buffer which could be scratched + * + * Return values of ajp_send_request() function: + * return value op->recoverable reason + * JK_FATAL_ERROR JK_FALSE ajp_connection_tcp_send_message() returns JK_FATAL_ERROR + * Endpoint belongs to unknown protocol. + * JK_FATAL_ERROR JK_TRUE ajp_connection_tcp_send_message() returns JK_FALSE + * Sending request or request body in jk_tcp_socket_sendfull() returns with error. + * JK_FATAL_ERROR JK_TRUE Could not connect to backend + * JK_CLIENT_RD_ERROR JK_FALSE Error during reading parts of POST body from client + * JK_TRUE JK_TRUE All other cases (OK) + */ +static int ajp_send_request(jk_endpoint_t *e, + jk_ws_service_t *s, + jk_logger_t *l, + ajp_endpoint_t * ae, ajp_operation_t * op) +{ + int err_conn = 0; + int err_cping = 0; + int err_send = 0; + int rc; + int postlen; + + JK_TRACE_ENTER(l); + + ae->last_errno = 0; + /* Up to now, we can recover */ + op->recoverable = JK_TRUE; + + /* Check if the previous request really ended + */ + if (ae->last_op != JK_AJP13_END_RESPONSE && + ae->last_op != AJP13_CPONG_REPLY) { + jk_log(l, JK_LOG_INFO, + "(%s) did not receive END_RESPONSE, " + "closing socket %d", + ae->worker->name, ae->sd); + ajp_abort_endpoint(ae, JK_TRUE, l); + } + /* + * First try to check open connections... + */ + while (IS_VALID_SOCKET(ae->sd)) { + int err = JK_FALSE; + if (jk_is_socket_connected(ae->sd, l) == JK_FALSE) { + ae->last_errno = errno; + jk_log(l, JK_LOG_DEBUG, + "(%s) failed sending request, " + "socket %d is not connected any more (errno=%d)", + ae->worker->name, ae->sd, ae->last_errno); + ajp_abort_endpoint(ae, JK_FALSE, l); + err = JK_TRUE; + err_conn++; + } + if (ae->worker->prepost_timeout > 0 && !err) { + /* handle cping/cpong if prepost_timeout is set + * If the socket is disconnected no need to handle + * the cping/cpong + */ + if (ajp_handle_cping_cpong(ae, + ae->worker->prepost_timeout, l) == JK_FALSE) { + jk_log(l, JK_LOG_INFO, + "(%s) failed sending request, " + "socket %d prepost cping/cpong failure (errno=%d)", + ae->worker->name, ae->sd, ae->last_errno); + /* XXX: Is there any reason to try other + * connections to the node if one of them fails + * the cping/cpong heartbeat? + * Tomcat can be either too busy or simply dead, so + * there is a chance that all other connections would + * fail as well. + */ + err = JK_TRUE; + err_cping++; + } + } + + /* We've got a connected socket and the optional + * cping/cpong worked, so let's send the request now. + */ + if (err == JK_FALSE) { + rc = ajp_connection_tcp_send_message(ae, op->request, l); + /* If this worked, we can break out of the loop + * and proceed with the request. + */ + if (rc == JK_TRUE) { + ae->last_op = JK_AJP13_FORWARD_REQUEST; + break; + } + /* Error during sending the request. + */ + err_send++; + if (rc == JK_FATAL_ERROR) + op->recoverable = JK_FALSE; + jk_log(l, JK_LOG_INFO, + "(%s) failed sending request (%srecoverable) " + "(errno=%d)", + ae->worker->name, + op->recoverable ? "" : "un", + ae->last_errno); + JK_TRACE_EXIT(l); + return JK_FATAL_ERROR; + } + /* If we got an error or can't send data, then try to steal another pooled + * connection and try again. If we are not successful, break out of this + * loop and try to open a new connection after the loop. + */ + if (ajp_next_connection(ae, l) == JK_FALSE) + break; + } + + /* + * If we failed to reuse a connection, try to reconnect. + */ + if (!IS_VALID_SOCKET(ae->sd)) { + /* Could not steal any connection from an endpoint - backend is disconnected */ + if (err_conn + err_cping + err_send > 0) + jk_log(l, JK_LOG_INFO, + "(%s) all endpoints are disconnected, " + "detected by connect check (%d), cping (%d), send (%d)", + ae->worker->name, err_conn, err_cping, err_send); + else if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "(%s) all endpoints are disconnected.", + ae->worker->name); + /* Connect to the backend. + */ + if (ajp_connect_to_endpoint(ae, l) != JK_TRUE) { + jk_log(l, JK_LOG_ERROR, + "(%s) connecting to backend failed. Tomcat is probably not started " + "or is listening on the wrong port (errno=%d)", + ae->worker->name, ae->last_errno); + JK_TRACE_EXIT(l); + return JK_FATAL_ERROR; + } + if (ae->worker->connect_timeout <= 0 && + ae->worker->prepost_timeout > 0) { + /* handle cping/cpong if prepost_timeout is set + * and we didn't already do a connect cping/cpong. + */ + if (ajp_handle_cping_cpong(ae, + ae->worker->prepost_timeout, l) == JK_FALSE) { + jk_log(l, JK_LOG_INFO, + "(%s) failed sending request, " + "socket %d prepost cping/cpong failure (errno=%d)", + ae->worker->name, ae->sd, ae->last_errno); + JK_TRACE_EXIT(l); + return JK_FATAL_ERROR; + } + } + + /* We've got a connected socket and the optional + * cping/cpong worked, so let's send the request now. + */ + rc = ajp_connection_tcp_send_message(ae, op->request, l); + /* Error during sending the request. + */ + if (rc != JK_TRUE) { + if (rc == JK_FATAL_ERROR) + op->recoverable = JK_FALSE; + jk_log(l, JK_LOG_ERROR, + "(%s) failed sending request on a fresh connection (%srecoverable), " + "socket %d (errno=%d)", + ae->worker->name, op->recoverable ? "" : "un", + ae->sd, ae->last_errno); + JK_TRACE_EXIT(l); + return JK_FATAL_ERROR; + } + ae->last_op = JK_AJP13_FORWARD_REQUEST; + } + else if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "(%s) Statistics about invalid connections: " + "connect check (%d), cping (%d), send (%d)", + ae->worker->name, err_conn, err_cping, err_send); + + /* + * From now on an error means that we have an internal server error + * or Tomcat crashed. + */ + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "(%s) request body to send %" JK_UINT64_T_FMT " - request body to resend %d", + ae->worker->name, ae->left_bytes_to_send, + op->reply->len - AJP_HEADER_LEN); + + /* + * POST recovery job is done here and will work when data to + * POST are less than 8k, since it's the maximum size of op-post buffer. + * We send here the first part of data which was sent previously to the + * remote Tomcat + */ + + /* Did we have something to resend (ie the op-post has been feeded previously */ + + postlen = op->post->len; + if (postlen > AJP_HEADER_LEN) { + rc = ajp_connection_tcp_send_message(ae, op->post, l); + /* Error during sending the request body. + */ + if (rc != JK_TRUE) { + if (rc == JK_FATAL_ERROR) + op->recoverable = JK_FALSE; + jk_log(l, JK_LOG_ERROR, + "(%s) failed sending request body of size %d (%srecoverable), " + "socket %d (errno=%d)", + ae->worker->name, postlen, op->recoverable ? "" : "un", + ae->sd, ae->last_errno); + JK_TRACE_EXIT(l); + return JK_FATAL_ERROR; + } + else { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, "Resent the request body (%d)", + postlen); + } + } + else if (s->reco_status == RECO_FILLED) { + /* Recovery in LB MODE */ + postlen = s->reco_buf->len; + + if (postlen > AJP_HEADER_LEN) { + rc = ajp_connection_tcp_send_message(ae, s->reco_buf, l); + /* Error during sending the request body. + */ + if (rc != JK_TRUE) { + if (rc == JK_FATAL_ERROR) + op->recoverable = JK_FALSE; + jk_log(l, JK_LOG_ERROR, + "(%s) failed sending request body of size %d (lb mode) (%srecoverable), " + "socket %d (errno=%d)", + ae->worker->name, postlen, op->recoverable ? "" : "un", + ae->sd, ae->last_errno); + JK_TRACE_EXIT(l); + return JK_FATAL_ERROR; + } + } + else { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Resent the request body (lb mode) (%d)", postlen); + } + } + else { + /* We never sent any POST data and we check if we have to send at + * least one block of data (max 8k). These data will be kept in reply + * for resend if the remote Tomcat is down, a fact we will learn only + * doing a read (not yet) + */ + /* || s->is_chunked - this can't be done here. The original protocol + sends the first chunk of post data ( based on Content-Length ), + and that's what the java side expects. + Sending this data for chunked would break other ajp13 servers. + + Note that chunking will continue to work - using the normal read. + */ + + if (ae->left_bytes_to_send > 0) { + int len = AJP13_MAX_SEND_BODY_SZ; + if (ae->left_bytes_to_send < (jk_uint64_t)AJP13_MAX_SEND_BODY_SZ) { + len = (int)ae->left_bytes_to_send; + } + if ((len = ajp_read_into_msg_buff(ae, s, op->post, len, l)) <= 0) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "(%s) browser stop sending data, no need to recover", + ae->worker->name); + op->recoverable = JK_FALSE; + /* Send an empty POST message since per AJP protocol + * spec whenever we have content length the message + * packet must be followed with initial POST packet. + * Size zero will be handled as error in container. + */ + jk_b_reset(op->post); + jk_b_append_int(op->post, 0); + ajp_connection_tcp_send_message(ae, op->post, l); + JK_TRACE_EXIT(l); + return JK_CLIENT_RD_ERROR; + } + + /* If a RECOVERY buffer is available in LB mode, fill it */ + if (s->reco_status == RECO_INITED) { + jk_b_copy(op->post, s->reco_buf); + s->reco_status = RECO_FILLED; + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "(%s) sending %d bytes of request body", + ae->worker->name, len); + + s->content_read = (jk_uint64_t)len; + rc = ajp_connection_tcp_send_message(ae, op->post, l); + /* Error during sending the request body. + */ + if (rc != JK_TRUE) { + if (rc == JK_FATAL_ERROR) + op->recoverable = JK_FALSE; + jk_log(l, JK_LOG_ERROR, + "(%s) failed sending request body of size %d (%srecoverable), " + "socket %d (errno=%d)", + ae->worker->name, len, op->recoverable ? "" : "un", + ae->sd, ae->last_errno); + JK_TRACE_EXIT(l); + return JK_FATAL_ERROR; + } + } + } + JK_TRACE_EXIT(l); + return JK_TRUE; +} + + +/* + * What to do with incoming data (dispatcher) + */ + +static int ajp_process_callback(jk_msg_buf_t *msg, + jk_msg_buf_t *pmsg, + ajp_endpoint_t * ae, + jk_ws_service_t *r, jk_logger_t *l) +{ + int code = (int)jk_b_get_byte(msg); + + JK_TRACE_ENTER(l); + + switch (code) { + case JK_AJP13_SEND_HEADERS: + { + int rc; + jk_res_data_t res; + if (ae->last_op == JK_AJP13_SEND_HEADERS) { + /* Do not send anything to the client. + * Backend already send us the headers. + */ + if (JK_IS_DEBUG_LEVEL(l)) { + jk_log(l, JK_LOG_DEBUG, + "Already received AJP13_SEND HEADERS"); + } + JK_TRACE_EXIT(l); + return JK_AJP13_ERROR; + } + if (!ajp_unmarshal_response(msg, &res, ae, l)) { + jk_log(l, JK_LOG_ERROR, + "ajp_unmarshal_response failed"); + JK_TRACE_EXIT(l); + return JK_AJP13_ERROR; + } + r->http_response_status = res.status; + if (r->extension.fail_on_status_size > 0) + rc = is_http_status_fail(r->extension.fail_on_status_size, + r->extension.fail_on_status, res.status); + else + rc = is_http_status_fail(ae->worker->http_status_fail_num, + ae->worker->http_status_fail, res.status); + if (rc > 0) { + JK_TRACE_EXIT(l); + return JK_STATUS_FATAL_ERROR; + } + else if (rc < 0) { + JK_TRACE_EXIT(l); + return JK_STATUS_ERROR; + } + + if (r->extension.use_server_error_pages && + r->http_response_status >= r->extension.use_server_error_pages) + r->response_blocked = JK_TRUE; + + /* + * Call even if response is blocked, since it also handles + * forwarding some headers for special http status codes + * even if the server uses an own error page. + * Example: The WWW-Authenticate header in case of + * HTTP_UNAUTHORIZED (401). + */ + r->start_response(r, res.status, res.msg, + (const char *const *)res.header_names, + (const char *const *)res.header_values, + res.num_headers); + + if (!r->response_blocked) { + if (r->flush && r->flush_header) + r->flush(r); + } + } + return JK_AJP13_SEND_HEADERS; + + case JK_AJP13_SEND_BODY_CHUNK: + if (ae->last_op == JK_AJP13_FORWARD_REQUEST) { + /* AJP13_SEND_BODY_CHUNK with length 0 is + * explicit flush packet message. + * Ignore those if they are left over from previous responses. + * Reportedly some versions of JBoss suffer from that problem. + */ + if (jk_b_get_int(msg) == 0) { + jk_log(l, JK_LOG_DEBUG, + "Ignoring flush message received while sending the request"); + return ae->last_op; + } + /* We have just send a request but received something + * that probably originates from buffered response. + */ + if (JK_IS_DEBUG_LEVEL(l)) { + jk_log(l, JK_LOG_DEBUG, + "Unexpected AJP13_SEND_BODY_CHUNK"); + } + JK_TRACE_EXIT(l); + return JK_AJP13_ERROR; + } + if (!r->response_blocked) { + unsigned int len = (unsigned int)jk_b_get_int(msg); + /* + * Do a sanity check on len to prevent write reading beyond buffer + * boundaries and thus revealing possible sensitive memory + * contents to the client. + * len cannot be larger than msg->len - 3 because the ajp message + * contains the magic byte for JK_AJP13_SEND_BODY_CHUNK (1 byte) + * and the length of the chunk (2 bytes). The remaining part of + * the message is the chunk. + */ + if (len > (unsigned int)(msg->len - 3)) { + jk_log(l, JK_LOG_ERROR, + "Chunk length too large. Length of AJP message is %i," + " chunk length is %i.", msg->len, len); + JK_TRACE_EXIT(l); + return JK_INTERNAL_ERROR; + } + if (len == 0) { + /* AJP13_SEND_BODY_CHUNK with length 0 is + * explicit flush packet message. + */ + if (r->response_started) { + if (r->flush) { + r->flush(r); + } + } + else { + jk_log(l, JK_LOG_DEBUG, + "Ignoring flush message received before headers"); + } + } + else { + if (!r->write(r, msg->buf + msg->pos, len)) { + jk_log(l, JK_LOG_INFO, + "Writing to client aborted or client network problems"); + JK_TRACE_EXIT(l); + return JK_CLIENT_WR_ERROR; + } + if (r->flush && r->flush_packets) + r->flush(r); + } + } + break; + + case JK_AJP13_GET_BODY_CHUNK: + { + int len = (int)jk_b_get_int(msg); + + if (len < 0) { + len = 0; + } + if (len > AJP13_MAX_SEND_BODY_SZ) { + len = AJP13_MAX_SEND_BODY_SZ; + } + if ((jk_uint64_t)len > ae->left_bytes_to_send) { + len = (int)ae->left_bytes_to_send; + } + + /* the right place to add file storage for upload */ + if ((len = ajp_read_into_msg_buff(ae, r, pmsg, len, l)) >= 0) { + r->content_read += (jk_uint64_t)len; + JK_TRACE_EXIT(l); + return JK_AJP13_HAS_RESPONSE; + } + + jk_log(l, JK_LOG_INFO, + "Reading from client aborted or client network problems"); + + JK_TRACE_EXIT(l); + return JK_CLIENT_RD_ERROR; + } + break; + + case JK_AJP13_END_RESPONSE: + ae->reuse = (int)jk_b_get_byte(msg); + if (!ae->reuse) { + /* + * AJP13 protocol reuse flag set to false. + * Tomcat will close its side of the connection. + */ + jk_log(l, JK_LOG_WARNING, "AJP13 protocol: Reuse is set to false"); + } + else if (r->disable_reuse) { + if (JK_IS_DEBUG_LEVEL(l)) { + jk_log(l, JK_LOG_DEBUG, "AJP13 protocol: Reuse is disabled"); + } + ae->reuse = JK_FALSE; + } + else { + /* Reuse in all cases */ + if (JK_IS_DEBUG_LEVEL(l)) { + jk_log(l, JK_LOG_DEBUG, "AJP13 protocol: Reuse is OK"); + } + ae->reuse = JK_TRUE; + } + if (!r->response_blocked) { + if (r->done) { + /* Done with response */ + r->done(r); + } + else if (r->flush && !r->flush_packets) { + /* Flush after the last write */ + r->flush(r); + } + } + JK_TRACE_EXIT(l); + return JK_AJP13_END_RESPONSE; + break; + + default: + jk_log(l, JK_LOG_ERROR, + "Unknown AJP protocol code: %02X", code); + JK_TRACE_EXIT(l); + return JK_AJP13_ERROR; + } + + JK_TRACE_EXIT(l); + return JK_AJP13_NO_RESPONSE; +} + +/* + * get replies from Tomcat via Ajp13/Ajp14 + * ajp13/ajp14 is async but handling read/send this way prevent nice recovery + * In fact if tomcat link is broken during upload (browser -> apache -> tomcat) + * we'll loose data and we'll have to abort the whole request. + * + * Return values of ajp_get_reply() function: + * return value op->recoverable reason + * JK_REPLY_TIMEOUT ?recovery_options Reply timeout while waiting for response packet + * JK_FALSE ?recovery_options Error during ajp_connection_tcp_get_message() + * Could not read the AJP packet header + * JK_AJP_PROTOCOL_ERROR: ?recovery_options Error during ajp_connection_tcp_get_message() + * Failure after reading the AJP packet header + * JK_STATUS_ERROR mostly JK_TRUE ajp_process_callback() returns JK_STATUS_ERROR + * Recoverable, if callback didn't return with a JK_HAS_RESPONSE before. + * JK_HAS_RESPONSE: parts of the post buffer are consumed. + * JK_STATUS_FATAL_ERROR mostly JK_TRUE ajp_process_callback() returns JK_STATUS_FATAL_ERROR + * Recoverable, if callback didn't return with a JK_HAS_RESPONSE before. + * JK_HAS_RESPONSE: parts of the post buffer are consumed. + * JK_FATAL_ERROR ? ajp_process_callback() returns JK_AJP13_ERROR + * JK_AJP13_ERROR: protocol error, or JK_INTERNAL_ERROR: chunk size to large + * JK_CLIENT_RD_ERROR ? ajp_process_callback() returns JK_CLIENT_RD_ERROR + * JK_CLIENT_RD_ERROR: could not read post from client. + * JK_CLIENT_WR_ERROR ? ajp_process_callback() returns JK_CLIENT_WR_ERROR + * JK_CLIENT_WR_ERROR: could not write back result to client + * JK_TRUE ? ajp_process_callback() returns JK_AJP13_END_RESPONSE + * JK_FALSE ? Other unhandled cases (unknown return codes) + */ +static int ajp_get_reply(jk_endpoint_t *e, + jk_ws_service_t *s, + jk_logger_t *l, + ajp_endpoint_t * p, ajp_operation_t * op) +{ + /* Don't get header from tomcat yet */ + int headeratclient = JK_FALSE; + + JK_TRACE_ENTER(l); + + p->last_errno = 0; + /* Start read all reply message */ + while (1) { + int rc = 0; + /* Allow to overwrite reply_timeout on a per URL basis via service struct */ + int reply_timeout = s->extension.reply_timeout; + if (reply_timeout < 0) + reply_timeout = p->worker->reply_timeout; + /* If we set a reply timeout, check if something is available */ + if (reply_timeout > 0) { + if (jk_is_input_event(p->sd, reply_timeout, l) == + JK_FALSE) { + p->last_errno = errno; + jk_log(l, JK_LOG_ERROR, + "(%s) Timeout with waiting reply from tomcat. " + "Tomcat is down, stopped or network problems (errno=%d)", + p->worker->name, p->last_errno); + /* We can't trust this connection any more. */ + ajp_abort_endpoint(p, JK_TRUE, l); + if (headeratclient == JK_FALSE) { + if (p->worker->recovery_opts & RECOVER_ABORT_IF_TCGETREQUEST) + op->recoverable = JK_FALSE; + /* + * We revert back to recoverable, if recovery_opts allow it for GET or HEAD + */ + if (op->recoverable == JK_FALSE) { + if (p->worker->recovery_opts & RECOVER_ALWAYS_HTTP_HEAD) { + if (!strcmp(s->method, "HEAD")) + op->recoverable = JK_TRUE; + } + else if (p->worker->recovery_opts & RECOVER_ALWAYS_HTTP_GET) { + if (!strcmp(s->method, "GET")) + op->recoverable = JK_TRUE; + } + } + } + else { + if (p->worker->recovery_opts & RECOVER_ABORT_IF_TCSENDHEADER) + op->recoverable = JK_FALSE; + } + + JK_TRACE_EXIT(l); + return JK_REPLY_TIMEOUT; + } + } + + if ((rc = ajp_connection_tcp_get_message(p, op->reply, l)) != JK_TRUE) { + if (headeratclient == JK_FALSE) { + jk_log(l, JK_LOG_ERROR, + "(%s) Tomcat is down or refused connection. " + "No response has been sent to the client (yet)", + p->worker->name); + /* + * communication with tomcat has been interrupted BEFORE + * headers have been sent to the client. + */ + + /* + * We mark it unrecoverable if recovery_opts set to RECOVER_ABORT_IF_TCGETREQUEST + */ + if (p->worker->recovery_opts & RECOVER_ABORT_IF_TCGETREQUEST) + op->recoverable = JK_FALSE; + /* + * We revert back to recoverable, if recovery_opts allow it for GET or HEAD + */ + if (op->recoverable == JK_FALSE) { + if (p->worker->recovery_opts & RECOVER_ALWAYS_HTTP_HEAD) { + if (!strcmp(s->method, "HEAD")) + op->recoverable = JK_TRUE; + } + else if (p->worker->recovery_opts & RECOVER_ALWAYS_HTTP_GET) { + if (!strcmp(s->method, "GET")) + op->recoverable = JK_TRUE; + } + } + + } + else { + jk_log(l, JK_LOG_ERROR, + "(%s) Tomcat is down or network problems. " + "Part of the response has already been sent to the client", + p->worker->name); + + /* communication with tomcat has been interrupted AFTER + * headers have been sent to the client. + * headers (and maybe parts of the body) have already been + * sent, therefore the response is "complete" in a sense + * that nobody should append any data, especially no 500 error + * page of the webserver! + */ + + /* + * We mark it unrecoverable if recovery_opts set to RECOVER_ABORT_IF_TCSENDHEADER + */ + if (p->worker->recovery_opts & RECOVER_ABORT_IF_TCSENDHEADER) + op->recoverable = JK_FALSE; + + } + + JK_TRACE_EXIT(l); + return rc; + } + + rc = ajp_process_callback(op->reply, op->post, p, s, l); + p->last_op = rc; + /* no more data to be sent, fine we have finish here */ + if (JK_AJP13_END_RESPONSE == rc) { + JK_TRACE_EXIT(l); + return JK_TRUE; + } + else if (JK_AJP13_SEND_HEADERS == rc) { + if (headeratclient == JK_FALSE) + headeratclient = JK_TRUE; + else { + /* Backend send headers twice? + * This is protocol violation + */ + jk_log(l, JK_LOG_ERROR, + "(%s) Tomcat already send headers", + p->worker->name); + op->recoverable = JK_FALSE; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + else if (JK_STATUS_ERROR == rc || JK_STATUS_FATAL_ERROR == rc) { + jk_log(l, JK_LOG_INFO, + "(%s) request failed%s, " + "because of response status %d, ", + p->worker->name, + rc == JK_STATUS_FATAL_ERROR ? "" : " (soft)", + s->http_response_status); + JK_TRACE_EXIT(l); + return rc; + } + else if (JK_AJP13_HAS_RESPONSE == rc) { + /* + * in upload-mode there is no second chance since + * we may have already sent part of the uploaded data + * to Tomcat. + * In this case if Tomcat connection is broken we must + * abort request and indicate error. + * A possible work-around could be to store the uploaded + * data to file and replay for it + */ + op->recoverable = JK_FALSE; + rc = ajp_connection_tcp_send_message(p, op->post, l); + if (rc < 0) { + jk_log(l, JK_LOG_ERROR, + "(%s) Tomcat is down or network problems", + p->worker->name); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + else if (JK_AJP13_ERROR == rc) { + /* + * Tomcat has send invalid AJP message. + * Loadbalancer if present will decide if + * failover is possible. + */ + JK_TRACE_EXIT(l); + return JK_FATAL_ERROR; + } + else if (JK_CLIENT_RD_ERROR == rc) { + /* + * Client has stop sending to us, so get out. + * We assume this isn't our fault, so just a normal exit. + */ + JK_TRACE_EXIT(l); + return JK_CLIENT_RD_ERROR; + } + else if (JK_CLIENT_WR_ERROR == rc) { + /* + * Client has stop receiving to us, so get out. + * We assume this isn't our fault, so just a normal exit. + */ + JK_TRACE_EXIT(l); + return JK_CLIENT_WR_ERROR; + } + else if (JK_INTERNAL_ERROR == rc) { + /* + * Internal error, like memory allocation or invalid packet lengths. + */ + JK_TRACE_EXIT(l); + return JK_FATAL_ERROR; + } + else if (JK_AJP13_NO_RESPONSE == rc) { + /* + * This is fine, loop again, more data to send. + */ + continue; + } + else if (rc < 0) { + op->recoverable = JK_FALSE; + jk_log(l, JK_LOG_ERROR, + "(%s) Callback returns with unknown value %d", + p->worker->name, rc); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + /* XXX: Not reached? */ + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +static void ajp_update_stats(jk_endpoint_t *e, ajp_worker_t *aw, int rc, jk_logger_t *l) +{ + aw->s->readed += e->rd; + aw->s->transferred += e->wr; + if (aw->s->busy) + aw->s->busy--; + if (rc == JK_TRUE) { + aw->s->state = JK_AJP_STATE_OK; + } + else if (rc == JK_CLIENT_ERROR) { + aw->s->state = JK_AJP_STATE_OK; + aw->s->client_errors++; + } + else { + aw->s->state = JK_AJP_STATE_ERROR; + aw->s->errors++; + aw->s->error_time = time(NULL); + } +} + +/* + * service is now splitted in ajp_send_request and ajp_get_reply + * much more easier to do errors recovery + * + * We serve here the request, using AJP13/AJP14 (e->proto) + * + * Return values of service() method for ajp13/ajp14 worker: + * return value is_error e->recoverable reason + * JK_FALSE JK_HTTP_SERVER_ERROR TRUE Invalid Parameters (null values) + * JK_SERVER_ERROR JK_HTTP_SERVER_ERROR TRUE Error during initializing empty request, response or post body objects + * JK_CLIENT_ERROR JK_HTTP_REQUEST_TOO_LARGE JK_TRUE Request doesn't fit into buffer (error during ajp_marshal_into_msgb()) + * JK_CLIENT_ERROR JK_HTTP_BAD_REQUEST JK_FALSE Error during reading parts of POST body from client + * JK_FATAL_ERROR JK_HTTP_SERVER_ERROR JK_FALSE If ajp_send_request() returns JK_FATAL_ERROR and !op->recoverable. + * JK_FATAL_ERROR JK_HTTP_SERVER_ERROR JK_FALSE If ajp_send_request() returns JK_TRUE but !op->recoverable. + * This should never happen. + * JK_CLIENT_ERROR JK_HTTP_BAD_REQUEST ? ajp_get_reply() returns JK_CLIENT_RD_ERROR + * JK_CLIENT_ERROR JK_HTTP_OK ? ajp_get_reply() returns JK_CLIENT_WR_ERROR + * JK_FATAL_ERROR JK_HTTP_SERVER_ERROR JK_TRUE ajp_get_reply() returns JK_FATAL_ERROR + * JK_FATAL_ERROR: protocol error or internal error + * JK_FATAL_ERROR JK_HTTP_SERVER_ERROR JK_FALSE ajp_get_reply() returns JK_FATAL_ERROR + * JK_FATAL_ERROR: protocol error or internal error + * JK_STATUS_ERROR JK_HTTP_SERVER_BUSY JK_TRUE ajp_get_reply() returns JK_STATUS_ERROR + * Only if op->recoverable and no more ajp13/ajp14 direct retries + * JK_STATUS_ERROR JK_HTTP_SERVER_BUSY JK_FALSE ajp_get_reply() returns JK_STATUS_ERROR + * Only if !op->recoverable + * JK_STATUS_FATAL_ERROR JK_HTTP_SERVER_BUSY JK_TRUE ajp_get_reply() returns JK_STATUS_ERROR + * Only if op->recoverable and no more ajp13/ajp14 direct retries + * JK_STATUS_FATAL_ERROR JK_HTTP_SERVER_BUSY JK_FALSE ajp_get_reply() returns JK_STATUS_FATAL_ERROR + * Only if !op->recoverable + * JK_REPLY_TIMEOUT JK_HTTP_GATEWAY_TIME_OUT JK_TRUE ajp_get_reply() returns JK_REPLY_TIMEOUT + * JK_AJP_PROTOCOL_ERROR JK_HTTP_GATEWAY_TIME_OUT ? ajp_get_reply() returns JK_AJP_PROTOCOL_ERROR + * ??? JK_FATAL_ERROR JK_HTTP_GATEWAY_TIME_OUT JK_FALSE ajp_get_reply() returns something else + * Only if !op->recoverable + * ??? JK_FALSE JK_HTTP_SERVER_BUSY JK_TRUE ajp_get_reply() returns JK_FALSE + * Only if op->recoverable and no more ajp13/ajp14 direct retries + * JK_TRUE JK_HTTP_OK ? OK + */ +static int JK_METHOD ajp_service(jk_endpoint_t *e, + jk_ws_service_t *s, + jk_logger_t *l, int *is_error) +{ + int i; + int err = JK_TRUE; + ajp_operation_t oper; + ajp_operation_t *op = &oper; + ajp_endpoint_t *p; + ajp_worker_t *aw; + int log_error; + int rc = JK_UNSET; + char *msg = ""; + int retry_interval; + + JK_TRACE_ENTER(l); + + if (!e || !e->endpoint_private || !s || !is_error) { + JK_LOG_NULL_PARAMS(l); + if (is_error) + *is_error = JK_HTTP_SERVER_ERROR; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p = e->endpoint_private; + aw = p->worker; + + if (aw->sequence != aw->s->h.sequence) + jk_ajp_pull(aw, JK_FALSE, l); + + aw->s->used++; + + /* Set returned error to SERVER ERROR */ + *is_error = JK_HTTP_SERVER_ERROR; + + op->request = jk_b_new(&(p->pool)); + if (!op->request) { + jk_log(l, JK_LOG_ERROR, + "Failed allocating AJP message"); + JK_TRACE_EXIT(l); + return JK_SERVER_ERROR; + } + if (jk_b_set_buffer_size(op->request, aw->max_packet_size)) { + jk_log(l, JK_LOG_ERROR, + "Failed allocating AJP message buffer"); + JK_TRACE_EXIT(l); + return JK_SERVER_ERROR; + } + jk_b_reset(op->request); + + op->reply = jk_b_new(&(p->pool)); + if (!op->reply) { + jk_log(l, JK_LOG_ERROR, + "Failed allocating AJP message"); + JK_TRACE_EXIT(l); + return JK_SERVER_ERROR; + } + if (jk_b_set_buffer_size(op->reply, aw->max_packet_size)) { + jk_log(l, JK_LOG_ERROR, + "Failed allocating AJP message buffer"); + JK_TRACE_EXIT(l); + return JK_SERVER_ERROR; + } + + op->post = jk_b_new(&(p->pool)); + if (!op->post) { + jk_log(l, JK_LOG_ERROR, + "Failed allocating AJP message"); + JK_TRACE_EXIT(l); + return JK_SERVER_ERROR; + } + if (jk_b_set_buffer_size(op->post, aw->max_packet_size)) { + jk_log(l, JK_LOG_ERROR, + "Failed allocating AJP message buffer"); + JK_TRACE_EXIT(l); + return JK_SERVER_ERROR; + } + jk_b_reset(op->post); + + /* Set returned error to OK */ + *is_error = JK_HTTP_OK; + + op->recoverable = JK_TRUE; + op->uploadfd = -1; /* not yet used, later ;) */ + + p->left_bytes_to_send = s->content_length; + p->reuse = JK_FALSE; + p->hard_close = JK_FALSE; + + s->secret = aw->secret; + + /* + * We get here initial request (in op->request) + */ + if (!ajp_marshal_into_msgb(op->request, s, l, p)) { + *is_error = JK_HTTP_REQUEST_TOO_LARGE; + jk_log(l, JK_LOG_INFO, + "Creating AJP message failed, " + "without recovery"); + aw->s->client_errors++; + JK_TRACE_EXIT(l); + return JK_CLIENT_ERROR; + } + + if (JK_IS_DEBUG_LEVEL(l)) { + jk_log(l, JK_LOG_DEBUG, "processing %s with %d retries", + aw->name, aw->retries); + } + aw->s->busy++; + if (aw->s->state == JK_AJP_STATE_ERROR) + aw->s->state = JK_AJP_STATE_PROBE; + if (aw->s->busy > aw->s->max_busy) + aw->s->max_busy = aw->s->busy; + retry_interval = p->worker->retry_interval; + for (i = 0; i < aw->retries; i++) { + /* Reset reply message buffer for each retry */ + jk_b_reset(op->reply); + + /* + * ajp_send_request() already locally handles + * reconnecting and broken connection detection. + * So if we already failed in it, wait a bit before + * retrying the same backend. + */ + if (i > 0 && retry_interval >= 0) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "retry %d, sleeping for %d ms before retrying", + i, retry_interval); + jk_sleep(retry_interval); + /* Pull shared memory if something changed during sleep */ + if (aw->sequence != aw->s->h.sequence) + jk_ajp_pull(aw, JK_FALSE, l); + } + /* + * We're using op->request which hold initial request + * if Tomcat is stopped or restarted, we will pass op->request + * to next valid tomcat. + */ + log_error = JK_TRUE; + rc = JK_UNSET; + msg = ""; + err = ajp_send_request(e, s, l, p, op); + e->recoverable = op->recoverable; + if (err == JK_CLIENT_RD_ERROR) { + *is_error = JK_HTTP_BAD_REQUEST; + msg = "because of client read error"; + aw->s->client_errors++; + rc = JK_CLIENT_ERROR; + log_error = JK_FALSE; + e->recoverable = JK_FALSE; + /* Ajp message set reuse to TRUE in END_REQUEST message + * However due to client bad request if the recovery + * RECOVER_ABORT_IF_CLIENTERROR is set the physical connection + * will be closed and application in Tomcat can catch that + * generated exception, knowing the client aborted the + * connection. This AJP protocol limitation, where we + * should actually send some packet informing the backend + * that client broke the connection in a middle of + * request/response cycle. + */ + if (aw->recovery_opts & RECOVER_ABORT_IF_CLIENTERROR) { + /* Mark the endpoint for shutdown */ + p->reuse = JK_FALSE; + p->hard_close = JK_TRUE; + } + } + else if (err == JK_FATAL_ERROR) { + *is_error = JK_HTTP_SERVER_BUSY; + msg = "because of error during request sending"; + rc = err; + if (!op->recoverable) { + *is_error = JK_HTTP_SERVER_ERROR; + msg = "because of protocol error during request sending"; + } + } + else if (err == JK_TRUE && op->recoverable) { + /* Up to there we can recover */ + + err = ajp_get_reply(e, s, l, p, op); + e->recoverable = op->recoverable; + if (err == JK_TRUE) { + *is_error = JK_HTTP_OK; + /* Done with the request */ + ajp_update_stats(e, aw, JK_TRUE, l); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + + if (err == JK_CLIENT_RD_ERROR) { + *is_error = JK_HTTP_BAD_REQUEST; + msg = "because of client read error"; + aw->s->client_errors++; + rc = JK_CLIENT_ERROR; + log_error = JK_FALSE; + e->recoverable = JK_FALSE; + op->recoverable = JK_FALSE; + if (aw->recovery_opts & RECOVER_ABORT_IF_CLIENTERROR) { + /* Mark the endpoint for shutdown */ + p->reuse = JK_FALSE; + p->hard_close = JK_TRUE; + } + } + else if (err == JK_CLIENT_WR_ERROR) { + /* XXX: Is this correct to log this as 200? */ + *is_error = JK_HTTP_OK; + msg = "because of client write error"; + aw->s->client_errors++; + rc = JK_CLIENT_ERROR; + log_error = JK_FALSE; + e->recoverable = JK_FALSE; + op->recoverable = JK_FALSE; + if (aw->recovery_opts & RECOVER_ABORT_IF_CLIENTERROR) { + /* Mark the endpoint for shutdown */ + p->reuse = JK_FALSE; + p->hard_close = JK_TRUE; + } + } + else if (err == JK_FATAL_ERROR) { + *is_error = JK_HTTP_SERVER_ERROR; + msg = "because of server error"; + rc = err; + } + else if (err == JK_REPLY_TIMEOUT) { + *is_error = JK_HTTP_GATEWAY_TIME_OUT; + msg = "because of reply timeout"; + aw->s->reply_timeouts++; + rc = err; + } + else if (err == JK_STATUS_ERROR || err == JK_STATUS_FATAL_ERROR) { + *is_error = JK_HTTP_SERVER_BUSY; + msg = "because of response status"; + rc = err; + } + else if (err == JK_AJP_PROTOCOL_ERROR) { + *is_error = JK_HTTP_BAD_GATEWAY; + msg = "because of protocol error"; + rc = err; + } + /* This should only be the cases err == JK_FALSE */ + else { + /* if we can't get reply, check if unrecoverable flag was set + * if is_recoverable_error is cleared, we have started + * receiving upload data and we must consider that + * operation is no more recoverable + */ + *is_error = JK_HTTP_BAD_GATEWAY; + msg = ""; + rc = JK_FALSE; + } + } + else { + /* XXX: this should never happen: + * ajp_send_request() never returns JK_TRUE if !op->recoverable. + * and all other return values have already been handled. + */ + e->recoverable = JK_FALSE; + *is_error = JK_HTTP_SERVER_ERROR; + msg = "because of an unknown reason"; + rc = JK_FATAL_ERROR; + jk_log(l, JK_LOG_ERROR, + "(%s) unexpected condition err=%d recoverable=%d", + aw->name, err, op->recoverable); + } + if (!op->recoverable && log_error == JK_TRUE) { + jk_log(l, JK_LOG_ERROR, + "(%s) sending request to tomcat failed (unrecoverable), " + "%s " + "(attempt=%d)", + aw->name, msg, i + 1); + } + else { + jk_log(l, JK_LOG_INFO, + "(%s) sending request to tomcat failed (%srecoverable), " + "%s " + "(attempt=%d)", + aw->name, + op->recoverable ? "" : "un", + msg, i + 1); + } + if (!op->recoverable) { + ajp_update_stats(e, aw, rc, l); + JK_TRACE_EXIT(l); + return rc; + } + /* Get another connection from the pool and try again. + * Note: All sockets are probably closed already. + */ + ajp_next_connection(p, l); + } + /* Log the error only once per failed request. */ + jk_log(l, JK_LOG_ERROR, + "(%s) connecting to tomcat failed.", + aw->name); + + ajp_update_stats(e, aw, rc, l); + JK_TRACE_EXIT(l); + return rc; +} + +/* + * Validate the worker (ajp13/ajp14) + */ + +int ajp_validate(jk_worker_t *pThis, + jk_map_t *props, + jk_worker_env_t *we, jk_logger_t *l, int proto) +{ + int port; + const char *host; + + JK_TRACE_ENTER(l); + + if (proto == AJP13_PROTO) { + port = AJP13_DEF_PORT; + host = AJP13_DEF_HOST; + } + else if (proto == AJP14_PROTO) { + port = AJP14_DEF_PORT; + host = AJP14_DEF_HOST; + } + else { + jk_log(l, JK_LOG_ERROR, + "unknown protocol %d", proto); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (pThis && pThis->worker_private) { + ajp_worker_t *p = pThis->worker_private; + p->port = jk_get_worker_port(props, p->name, port); + if (!host) { + host = "undefined"; + } + strncpy(p->host, jk_get_worker_host(props, p->name, host), JK_SHM_STR_SIZ); + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "worker %s contact is '%s:%d'", + p->name, p->host, p->port); + /* Copy the contact to shm */ + strncpy(p->s->host, p->host, JK_SHM_STR_SIZ); + p->s->port = p->port; + p->s->addr_sequence = p->addr_sequence = 0; + /* Resolve if port > 0. + */ + if (p->port > 0) { + if (jk_resolve(p->host, p->port, &p->worker_inet_addr, we->pool, l)) { + JK_TRACE_EXIT(l); + return JK_TRUE; + } + jk_log(l, JK_LOG_ERROR, + "worker %s can't resolve tomcat address %s", + p->name, p->host); + p->s->port = p->port = 0; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "worker %s contact is disabled", + p->name); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + else { + p->s->port = p->port = 0; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "worker %s contact is disabled", + p->name); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + } + else { + JK_LOG_NULL_PARAMS(l); + } + + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +static int ajp_create_endpoint_cache(ajp_worker_t *p, int proto, jk_logger_t *l) +{ + unsigned int i; + time_t now = time(NULL); + + JK_TRACE_ENTER(l); + + p->ep_cache = (ajp_endpoint_t **)calloc(1, sizeof(ajp_endpoint_t *) * + p->ep_cache_sz); + if (!p->ep_cache) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "setting connection pool size to %u with min %u and acquire timeout %d", + p->ep_cache_sz, p->ep_mincache_sz, p->cache_acquire_timeout); + for (i = 0; i < p->ep_cache_sz; i++) { + p->ep_cache[i] = (ajp_endpoint_t *)calloc(1, sizeof(ajp_endpoint_t)); + if (!p->ep_cache[i]) { + jk_log(l, JK_LOG_ERROR, + "allocating endpoint slot %d (errno=%d)", + i, errno); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + p->ep_cache[i]->sd = JK_INVALID_SOCKET; + p->ep_cache[i]->reuse = JK_FALSE; + p->ep_cache[i]->hard_close = JK_FALSE; + p->ep_cache[i]->last_access = now; + jk_open_pool(&(p->ep_cache[i]->pool), p->ep_cache[i]->buf, + sizeof(p->ep_cache[i]->buf)); + p->ep_cache[i]->worker = p; + p->ep_cache[i]->endpoint.endpoint_private = p->ep_cache[i]; + p->ep_cache[i]->proto = proto; + p->ep_cache[i]->endpoint.service = ajp_service; + p->ep_cache[i]->endpoint.done = ajp_done; + p->ep_cache[i]->last_op = JK_AJP13_END_RESPONSE; + p->ep_cache[i]->addr_sequence = 0; + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +int ajp_init(jk_worker_t *pThis, + jk_map_t *props, jk_worker_env_t *we, jk_logger_t *l, int proto) +{ + int rc = JK_FALSE; + int cache; + /* + * start the connection cache + */ + JK_TRACE_ENTER(l); + + cache = jk_get_worker_def_cache_size(proto); + + if (pThis && pThis->worker_private) { + ajp_worker_t *p = pThis->worker_private; + p->worker.we = we; + p->ep_cache_sz = jk_get_worker_cache_size(props, p->name, cache); + p->ep_mincache_sz = jk_get_worker_cache_size_min(props, p->name, + (p->ep_cache_sz+1) / 2); + p->socket_timeout = + jk_get_worker_socket_timeout(props, p->name, AJP_DEF_SOCKET_TIMEOUT); + + p->socket_connect_timeout = + jk_get_worker_socket_connect_timeout(props, p->name, + p->socket_timeout * 1000); + + p->keepalive = + jk_get_worker_socket_keepalive(props, p->name, JK_FALSE); + + p->cache_timeout = + jk_get_worker_cache_timeout(props, p->name, + AJP_DEF_CACHE_TIMEOUT); + + p->ping_timeout = + jk_get_worker_ping_timeout(props, p->name, + AJP_DEF_PING_TIMEOUT); + p->ping_mode = + jk_get_worker_ping_mode(props, p->name, + AJP_CPING_NONE); + + p->connect_timeout = + jk_get_worker_connect_timeout(props, p->name, + AJP_DEF_CONNECT_TIMEOUT); + + p->prepost_timeout = + jk_get_worker_prepost_timeout(props, p->name, + AJP_DEF_PREPOST_TIMEOUT); + + if ((p->ping_mode & AJP_CPING_CONNECT) && + p->connect_timeout == AJP_DEF_CONNECT_TIMEOUT) + p->connect_timeout = p->ping_timeout; + + if ((p->ping_mode & AJP_CPING_PREPOST) && + p->prepost_timeout == AJP_DEF_PREPOST_TIMEOUT) + p->prepost_timeout = p->ping_timeout; + + p->conn_ping_interval = + jk_get_worker_conn_ping_interval(props, p->name, 0); + if ((p->ping_mode & AJP_CPING_INTERVAL) && + p->conn_ping_interval == 0) { + /* XXX: Ping timeout is in miliseconds + * and ping_interval is in seconds. + * Use 10 times larger value for ping interval + * (ping_timeout / 1000) * 10 + */ + p->conn_ping_interval = p->ping_timeout / 100; + } + p->reply_timeout = + jk_get_worker_reply_timeout(props, p->name, + AJP_DEF_REPLY_TIMEOUT); + + p->recovery_opts = + jk_get_worker_recovery_opts(props, p->name, + AJP_DEF_RECOVERY_OPTS); + + p->retries = + jk_get_worker_retries(props, p->name, + JK_RETRIES); + + p->max_packet_size = + jk_get_max_packet_size(props, p->name); + + p->socket_buf = + jk_get_worker_socket_buffer(props, p->name, p->max_packet_size); + + p->retry_interval = + jk_get_worker_retry_interval(props, p->name, + JK_SLEEP_DEF); + p->cache_acquire_timeout = jk_get_worker_cache_acquire_timeout(props, + p->name, p->retries * p->retry_interval); + p->http_status_fail_num = jk_get_worker_fail_on_status(props, p->name, + &p->http_status_fail[0], + JK_MAX_HTTP_STATUS_FAILS); + + if (p->retries < 1) { + jk_log(l, JK_LOG_INFO, + "number of retries must be greater then 1. Setting to default=%d", + JK_RETRIES); + p->retries = JK_RETRIES; + } + + p->maintain_time = jk_get_worker_maintain_time(props); + if(p->maintain_time < 0) + p->maintain_time = 0; + p->s->last_maintain_time = time(NULL); + p->s->last_reset = p->s->last_maintain_time; + + if (JK_IS_DEBUG_LEVEL(l)) { + + jk_log(l, JK_LOG_DEBUG, + "setting endpoint options:", + p->keepalive); + jk_log(l, JK_LOG_DEBUG, + "keepalive: %d", + p->keepalive); + + jk_log(l, JK_LOG_DEBUG, + "socket timeout: %d", + p->socket_timeout); + + jk_log(l, JK_LOG_DEBUG, + "socket connect timeout: %d", + p->socket_connect_timeout); + + jk_log(l, JK_LOG_DEBUG, + "buffer size: %d", + p->socket_buf); + + jk_log(l, JK_LOG_DEBUG, + "pool timeout: %d", + p->cache_timeout); + + jk_log(l, JK_LOG_DEBUG, + "ping timeout: %d", + p->ping_timeout); + + jk_log(l, JK_LOG_DEBUG, + "connect timeout: %d", + p->connect_timeout); + + jk_log(l, JK_LOG_DEBUG, + "reply timeout: %d", + p->reply_timeout); + + jk_log(l, JK_LOG_DEBUG, + "prepost timeout: %d", + p->prepost_timeout); + + jk_log(l, JK_LOG_DEBUG, + "recovery options: %d", + p->recovery_opts); + + jk_log(l, JK_LOG_DEBUG, + "retries: %d", + p->retries); + + jk_log(l, JK_LOG_DEBUG, + "max packet size: %d", + p->max_packet_size); + + jk_log(l, JK_LOG_DEBUG, + "retry interval: %d", + p->retry_interval); + } + /* + * Need to initialize secret here since we could return from inside + * of the following loop + */ + + p->secret = jk_get_worker_secret(props, p->name); + /* Initialize cache slots */ + JK_INIT_CS(&(p->cs), rc); + if (!rc) { + jk_log(l, JK_LOG_ERROR, + "creating thread lock (errno=%d)", + errno); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + if (!ajp_create_endpoint_cache(p, proto, l)) { + jk_log(l, JK_LOG_ERROR, + "allocating connection pool of size %u", + p->ep_cache_sz); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + rc = JK_TRUE; + } + else { + JK_LOG_NULL_PARAMS(l); + } + + JK_TRACE_EXIT(l); + return rc; +} + +int JK_METHOD ajp_worker_factory(jk_worker_t **w, + const char *name, jk_logger_t *l) +{ + ajp_worker_t *aw; + + JK_TRACE_ENTER(l); + if (name == NULL || w == NULL) { + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + aw = (ajp_worker_t *) calloc(1, sizeof(ajp_worker_t)); + if (!aw) { + jk_log(l, JK_LOG_ERROR, + "malloc of private_data failed"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + jk_open_pool(&aw->p, + aw->buf, + sizeof(jk_pool_atom_t) * TINY_POOL_SIZE); + + strncpy(aw->name, name, JK_SHM_STR_SIZ); + aw->login = NULL; + + aw->ep_cache_sz = 0; + aw->ep_cache = NULL; + aw->connect_retry_attempts = AJP_DEF_RETRY_ATTEMPTS; + aw->worker.worker_private = aw; + + aw->worker.maintain = ajp_maintain; + + aw->logon = NULL; + + *w = &aw->worker; + + aw->s = jk_shm_alloc_ajp_worker(&aw->p); + if (!aw->s) { + jk_close_pool(&aw->p); + free(aw); + jk_log(l, JK_LOG_ERROR, + "allocating ajp worker record from shared memory"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +int ajp_destroy(jk_worker_t **pThis, jk_logger_t *l, int proto) +{ + JK_TRACE_ENTER(l); + + if (pThis && *pThis && (*pThis)->worker_private) { + unsigned int i; + ajp_worker_t *aw = (*pThis)->worker_private; + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "up to %u endpoints to close", + aw->ep_cache_sz); + + for (i = 0; i < aw->ep_cache_sz; i++) { + if (aw->ep_cache[i]) + ajp_close_endpoint(aw->ep_cache[i], l); + } + free(aw->ep_cache); + JK_DELETE_CS(&(aw->cs), i); + + if (aw->login) { + /* take care of removing previously allocated data */ + if (aw->login->servlet_engine_name) + free(aw->login->servlet_engine_name); + + free(aw->login); + aw->login = NULL; + } + + jk_close_pool(&aw->p); + free(aw); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +int JK_METHOD ajp_done(jk_endpoint_t **e, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + if (e && *e && (*e)->endpoint_private) { + ajp_endpoint_t *p = (*e)->endpoint_private; + int rc; + ajp_worker_t *w = p->worker; + + /* set last_access only if needed */ + if (w->cache_timeout > 0) + p->last_access = time(NULL); + if (w->s->addr_sequence != p->addr_sequence) { + p->reuse = JK_FALSE; + p->addr_sequence = w->s->addr_sequence; + } + ajp_reset_endpoint(p, l); + *e = NULL; + JK_ENTER_CS(&w->cs, rc); + if (rc) { + int i; + + for (i = w->ep_cache_sz - 1; i >= 0; i--) { + if (w->ep_cache[i] == NULL) { + w->ep_cache[i] = p; + break; + } + } + JK_LEAVE_CS(&w->cs, rc); + + if (i >= 0) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "recycling connection pool slot=%u for worker %s", + i, p->worker->name); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + /* This should never hapen because + * there is always free empty cache slot + */ + jk_log(l, JK_LOG_ERROR, + "could not find empty connection pool slot from %u for worker %s", + w->ep_cache_sz, w->name); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + jk_log(l, JK_LOG_ERROR, + "locking thread (errno=%d)", errno); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +int ajp_get_endpoint(jk_worker_t *pThis, + jk_endpoint_t **je, jk_logger_t *l, int proto) +{ + JK_TRACE_ENTER(l); + + if (pThis && pThis->worker_private && je) { + ajp_worker_t *aw = pThis->worker_private; + ajp_endpoint_t *ae = NULL; + int rc; + int retry = 0; + + *je = NULL; + /* Loop until cache_acquire_timeout interval elapses */ + while ((retry * JK_SLEEP_DEF) < aw->cache_acquire_timeout) { + + JK_ENTER_CS(&aw->cs, rc); + if (rc) { + unsigned int slot; + /* Try to find connected socket cache entry */ + for (slot = 0; slot < aw->ep_cache_sz; slot++) { + if (aw->ep_cache[slot] && + IS_VALID_SOCKET(aw->ep_cache[slot]->sd)) { + ae = aw->ep_cache[slot]; + if (ae->reuse) { + aw->ep_cache[slot] = NULL; + break; + } + else { + /* XXX: We shouldn't have non reusable + * opened socket in the cache + */ + ajp_reset_endpoint(ae, l); + ae = NULL; + jk_log(l, JK_LOG_WARNING, + "closing non reusable pool slot=%d", slot); + } + } + } + if (!ae) { + /* No connected cache entry found. + * Use the first free one. + */ + for (slot = 0; slot < aw->ep_cache_sz; slot++) { + if (aw->ep_cache[slot]) { + ae = aw->ep_cache[slot]; + aw->ep_cache[slot] = NULL; + break; + } + } + } + JK_LEAVE_CS(&aw->cs, rc); + if (ae) { + if (aw->cache_timeout > 0) + ae->last_access = time(NULL); + *je = &ae->endpoint; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "acquired connection pool slot=%u after %d retries", + slot, retry); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + else { + retry++; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "could not get free endpoint for worker %s" + " (retry %d, sleeping for %d ms)", + aw->name, retry, JK_SLEEP_DEF); + jk_sleep(JK_SLEEP_DEF); + } + } + else { + jk_log(l, JK_LOG_ERROR, + "locking thread (errno=%d)", errno); + JK_TRACE_EXIT(l); + return JK_FALSE; + + } + } + jk_log(l, JK_LOG_WARNING, + "Unable to get the free endpoint for worker %s from %u slots", + aw->name, aw->ep_cache_sz); + } + else { + JK_LOG_NULL_PARAMS(l); + } + + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +int JK_METHOD ajp_maintain(jk_worker_t *pThis, time_t mstarted, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + if (pThis && pThis->worker_private) { + ajp_worker_t *aw = pThis->worker_private; + time_t now = mstarted; + int rc; + long delta; + + jk_shm_lock(); + + /* Now we check for global maintenance (once for all processes). + * Checking workers for idleness. + * Therefore we globally sync and we use a global timestamp. + * Since it's possible that we come here a few milliseconds + * before the interval has passed, we allow a little tolerance. + */ + delta = (long)difftime(mstarted, aw->s->last_maintain_time) + JK_AJP_MAINTAIN_TOLERANCE; + if (delta >= aw->maintain_time) { + aw->s->last_maintain_time = mstarted; + if (aw->s->state == JK_AJP_STATE_OK && + aw->s->used == aw->s->used_snapshot) + aw->s->state = JK_AJP_STATE_IDLE; + aw->s->used_snapshot = aw->s->used; + } + + jk_shm_unlock(); + + /* Do connection pool maintenance only if timeouts or keepalives are set */ + if (aw->cache_timeout <= 0 && + aw->conn_ping_interval <= 0) { + /* Nothing to do. */ + JK_TRACE_EXIT(l); + return JK_TRUE; + } + + JK_ENTER_CS(&aw->cs, rc); + if (rc) { + unsigned int n = 0, k = 0, cnt = 0; + int i; + unsigned int m, m_count = 0; + jk_sock_t *m_sock; + /* Count open slots */ + for (i = (int)aw->ep_cache_sz - 1; i >= 0; i--) { + if (aw->ep_cache[i] && IS_VALID_SOCKET(aw->ep_cache[i]->sd)) + cnt++; + } + m_sock = (jk_sock_t *)malloc((cnt + 1) * sizeof(jk_sock_t)); + /* Handle worker cache timeouts */ + if (aw->cache_timeout > 0) { + for (i = (int)aw->ep_cache_sz - 1; + i >= 0; i--) { + /* Skip the closed sockets */ + if (aw->ep_cache[i] && IS_VALID_SOCKET(aw->ep_cache[i]->sd)) { + int elapsed = (int)difftime(mstarted, aw->ep_cache[i]->last_access); + if (elapsed > aw->cache_timeout) { + time_t rt = 0; + n++; + if (JK_IS_DEBUG_LEVEL(l)) + rt = time(NULL); + aw->ep_cache[i]->reuse = JK_FALSE; + m_sock[m_count++] = aw->ep_cache[i]->sd; + aw->ep_cache[i]->sd = JK_INVALID_SOCKET; + ajp_reset_endpoint(aw->ep_cache[i], l); + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "cleaning pool slot=%d elapsed %d in %d", + i, elapsed, (int)(difftime(time(NULL), rt))); + } + } + if (cnt <= aw->ep_mincache_sz + n) { + if (JK_IS_DEBUG_LEVEL(l)) { + jk_log(l, JK_LOG_DEBUG, + "reached pool min size %u from %u cache slots", + aw->ep_mincache_sz, aw->ep_cache_sz); + } + break; + } + } + } + /* Handle worker connection keepalive */ + if (aw->conn_ping_interval > 0 && aw->ping_timeout > 0) { + for (i = (int)aw->ep_cache_sz - 1; i >= 0; i--) { + /* Skip the closed sockets */ + if (aw->ep_cache[i] && IS_VALID_SOCKET(aw->ep_cache[i]->sd)) { + int elapsed = (int)difftime(now, aw->ep_cache[i]->last_access); + if (elapsed > aw->conn_ping_interval) { + k++; + /* handle cping/cpong. + */ + if (ajp_handle_cping_cpong(aw->ep_cache[i], + aw->ping_timeout, l) == JK_FALSE) { + jk_log(l, JK_LOG_INFO, + "(%s) failed sending request, " + "socket %d keepalive cping/cpong " + "failure (errno=%d)", + aw->name, + aw->ep_cache[i]->sd, + aw->ep_cache[i]->last_errno); + aw->ep_cache[i]->reuse = JK_FALSE; + m_sock[m_count++] = aw->ep_cache[i]->sd; + aw->ep_cache[i]->sd = JK_INVALID_SOCKET; + ajp_reset_endpoint(aw->ep_cache[i], l); + } + else { + now = time(NULL); + aw->ep_cache[i]->last_access = now; + } + } + } + } + } + JK_LEAVE_CS(&aw->cs, rc); + /* Shutdown sockets outside of the lock. + * This has benefits only if maintain was + * called from the watchdog thread. + */ + for (m = 0; m < m_count; m++) { + jk_shutdown_socket(m_sock[m], l); + } + free(m_sock); + if (n && JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "recycled %u sockets in %d seconds from %u pool slots", + n, (int)(difftime(time(NULL), mstarted)), + aw->ep_cache_sz); + if (k && JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "pinged %u sockets in %d seconds from %u pool slots", + k, (int)(difftime(time(NULL), mstarted)), + aw->ep_cache_sz); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + else { + jk_log(l, JK_LOG_ERROR, + "locking thread (errno=%d)", + errno); + JK_TRACE_EXIT(l); + return JK_FALSE; + + } + } + else { + JK_LOG_NULL_PARAMS(l); + } + + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +int ajp_has_endpoint(jk_worker_t *pThis, + jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + if (pThis && pThis->worker_private) { + ajp_worker_t *aw = pThis->worker_private; + int rc; + + JK_ENTER_CS(&aw->cs, rc); + if (rc) { + unsigned int slot; + /* Try to find connected socket cache entry */ + for (slot = 0; slot < aw->ep_cache_sz; slot++) { + if (aw->ep_cache[slot]) { + JK_LEAVE_CS(&aw->cs, rc); + return JK_TRUE; + } + } + JK_LEAVE_CS(&aw->cs, rc); + } + else { + jk_log(l, JK_LOG_ERROR, + "locking thread (errno=%d)", errno); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + else { + JK_LOG_NULL_PARAMS(l); + } + + JK_TRACE_EXIT(l); + return JK_FALSE; +} diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp_common.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp_common.h new file mode 100644 index 00000000..09940fd9 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp_common.h @@ -0,0 +1,467 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: common stuff for bi-directional protocol ajp13/ajp14. * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Author: Henri Gomez <hgomez@apache.org> * + * Version: $Revision: 1137200 $ * + ***************************************************************************/ + +#ifndef JK_AJP_COMMON_H +#define JK_AJP_COMMON_H + +#include "jk_service.h" +#include "jk_msg_buff.h" +#include "jk_shm.h" +#include "jk_mt.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#define JK_AJP_STATE_IDLE (0) +#define JK_AJP_STATE_OK (1) +#define JK_AJP_STATE_ERROR (2) +#define JK_AJP_STATE_PROBE (3) +#define JK_AJP_STATE_DEF (JK_AJP_STATE_IDLE) +#define JK_AJP_STATE_TEXT_IDLE ("OK/IDLE") +#define JK_AJP_STATE_TEXT_OK ("OK") +#define JK_AJP_STATE_TEXT_ERROR ("ERR") +#define JK_AJP_STATE_TEXT_PROBE ("ERR/PRB") +#define JK_AJP_STATE_TEXT_MAX (JK_AJP_STATE_PROBE) +#define JK_AJP_STATE_TEXT_DEF (JK_AJP_STATE_TEXT_IDLE) + +/* We accept doing global maintenance if we are */ +/* JK_AJP_MAINTAIN_TOLERANCE seconds early. */ +#define JK_AJP_MAINTAIN_TOLERANCE (2) + +/* + * Conditional request attributes + * + */ +#define SC_A_CONTEXT (unsigned char)1 +#define SC_A_SERVLET_PATH (unsigned char)2 +#define SC_A_REMOTE_USER (unsigned char)3 +#define SC_A_AUTH_TYPE (unsigned char)4 +#define SC_A_QUERY_STRING (unsigned char)5 +#define SC_A_ROUTE (unsigned char)6 +#define SC_A_SSL_CERT (unsigned char)7 +#define SC_A_SSL_CIPHER (unsigned char)8 +#define SC_A_SSL_SESSION (unsigned char)9 +#define SC_A_REQ_ATTRIBUTE (unsigned char)10 +#define SC_A_SSL_KEY_SIZE (unsigned char)11 /* only in if JkOptions +ForwardKeySize */ +#define SC_A_SECRET (unsigned char)12 +#define SC_A_STORED_METHOD (unsigned char)13 +#define SC_A_ARE_DONE (unsigned char)0xFF + +/* + * AJP private request attributes + * + * The following request attribute is recognized by Tomcat + * to contain the forwarded remote port. + */ +#define SC_A_REQ_REMOTE_PORT ("AJP_REMOTE_PORT") + +/* + * JK public request attributes + * + * Activation state of the worker in the load balancer. + * Can be any of the JK_LB_ACTIVATION_TEXT_* strings + * from jk_lb_worker.h. + */ +#define SC_A_JK_LB_ACTIVATION ("JK_LB_ACTIVATION") + +/* + * Request methods, coded as numbers instead of strings. + * The list of methods was taken from Section 5.1.1 of RFC 2616, + * RFC 2518, the ACL IETF draft, and the DeltaV IESG Proposed Standard. + * Method = "OPTIONS" + * | "GET" + * | "HEAD" + * | "POST" + * | "PUT" + * | "DELETE" + * | "TRACE" + * | "PROPFIND" + * | "PROPPATCH" + * | "MKCOL" + * | "COPY" + * | "MOVE" + * | "LOCK" + * | "UNLOCK" + * | "ACL" + * | "REPORT" + * | "VERSION-CONTROL" + * | "CHECKIN" + * | "CHECKOUT" + * | "UNCHECKOUT" + * | "SEARCH" + * | "MKWORKSPACE" + * | "UPDATE" + * | "LABEL" + * | "MERGE" + * | "BASELINE-CONTROL" + * | "MKACTIVITY" + * + */ +#define SC_M_OPTIONS (unsigned char)1 +#define SC_M_GET (unsigned char)2 +#define SC_M_HEAD (unsigned char)3 +#define SC_M_POST (unsigned char)4 +#define SC_M_PUT (unsigned char)5 +#define SC_M_DELETE (unsigned char)6 +#define SC_M_TRACE (unsigned char)7 +#define SC_M_PROPFIND (unsigned char)8 +#define SC_M_PROPPATCH (unsigned char)9 +#define SC_M_MKCOL (unsigned char)10 +#define SC_M_COPY (unsigned char)11 +#define SC_M_MOVE (unsigned char)12 +#define SC_M_LOCK (unsigned char)13 +#define SC_M_UNLOCK (unsigned char)14 +#define SC_M_ACL (unsigned char)15 +#define SC_M_REPORT (unsigned char)16 +#define SC_M_VERSION_CONTROL (unsigned char)17 +#define SC_M_CHECKIN (unsigned char)18 +#define SC_M_CHECKOUT (unsigned char)19 +#define SC_M_UNCHECKOUT (unsigned char)20 +#define SC_M_SEARCH (unsigned char)21 +#define SC_M_MKWORKSPACE (unsigned char)22 +#define SC_M_UPDATE (unsigned char)23 +#define SC_M_LABEL (unsigned char)24 +#define SC_M_MERGE (unsigned char)25 +#define SC_M_BASELINE_CONTROL (unsigned char)26 +#define SC_M_MKACTIVITY (unsigned char)27 +#define SC_M_JK_STORED (unsigned char)0xFF + +/* + * Frequent request headers, these headers are coded as numbers + * instead of strings. + * + * Accept + * Accept-Charset + * Accept-Encoding + * Accept-Language + * Authorization + * Connection + * Content-Type + * Content-Length + * Cookie + * Cookie2 + * Host + * Pragma + * Referer + * User-Agent + * + */ + +#define SC_ACCEPT (unsigned short)0xA001 +#define SC_ACCEPT_CHARSET (unsigned short)0xA002 +#define SC_ACCEPT_ENCODING (unsigned short)0xA003 +#define SC_ACCEPT_LANGUAGE (unsigned short)0xA004 +#define SC_AUTHORIZATION (unsigned short)0xA005 +#define SC_CONNECTION (unsigned short)0xA006 +#define SC_CONTENT_TYPE (unsigned short)0xA007 +#define SC_CONTENT_LENGTH (unsigned short)0xA008 +#define SC_COOKIE (unsigned short)0xA009 +#define SC_COOKIE2 (unsigned short)0xA00A +#define SC_HOST (unsigned short)0xA00B +#define SC_PRAGMA (unsigned short)0xA00C +#define SC_REFERER (unsigned short)0xA00D +#define SC_USER_AGENT (unsigned short)0xA00E + +/* + * Frequent response headers, these headers are coded as numbers + * instead of strings. + * + * Content-Type + * Content-Language + * Content-Length + * Date + * Last-Modified + * Location + * Set-Cookie + * Servlet-Engine + * Status + * WWW-Authenticate + * + */ + +#define SC_RESP_CONTENT_TYPE (unsigned short)0xA001 +#define SC_RESP_CONTENT_LANGUAGE (unsigned short)0xA002 +#define SC_RESP_CONTENT_LENGTH (unsigned short)0xA003 +#define SC_RESP_DATE (unsigned short)0xA004 +#define SC_RESP_LAST_MODIFIED (unsigned short)0xA005 +#define SC_RESP_LOCATION (unsigned short)0xA006 +#define SC_RESP_SET_COOKIE (unsigned short)0xA007 +#define SC_RESP_SET_COOKIE2 (unsigned short)0xA008 +#define SC_RESP_SERVLET_ENGINE (unsigned short)0xA009 +#define SC_RESP_STATUS (unsigned short)0xA00A +#define SC_RESP_WWW_AUTHENTICATE (unsigned short)0xA00B +#define SC_RES_HEADERS_NUM 11 + +/* + * AJP13/AJP14 use same message structure + */ + +#define AJP_DEF_RETRY_ATTEMPTS (1) + +#define AJP_HEADER_LEN (4) +#define AJP_HEADER_SZ_LEN (2) +#define CHUNK_BUFFER_PAD (12) +#define AJP_DEF_CACHE_TIMEOUT (0) +#define AJP_DEF_CONNECT_TIMEOUT (0) /* NO CONNECTION TIMEOUT => NO CPING/CPONG */ +#define AJP_DEF_REPLY_TIMEOUT (0) /* NO REPLY TIMEOUT */ +#define AJP_DEF_PREPOST_TIMEOUT (0) /* NO PREPOST TIMEOUT => NO CPING/CPONG */ +#define AJP_DEF_RECOVERY_OPTS (0) /* NO RECOVERY / NO */ +#define AJP_DEF_SOCKET_TIMEOUT (0) /* No timeout */ +#define AJP_DEF_PING_TIMEOUT (10000) /* Default CPING/CPONG timeout (10 seconds) */ + +#define AJP_CPING_NONE (0) /* Do not send cping packets */ +#define AJP_CPING_CONNECT (1) /* Send cping on fresh connection */ +#define AJP_CPING_PREPOST (2) /* Send cping before sending request */ +#define AJP_CPING_INTERVAL (4) /* Send cping on regular intervals */ + + +#define RECOVER_ABORT_IF_TCGETREQUEST 0x0001 /* DON'T RECOVER IF TOMCAT FAILS AFTER RECEIVING REQUEST */ +#define RECOVER_ABORT_IF_TCSENDHEADER 0x0002 /* DON'T RECOVER IF TOMCAT FAILS AFTER SENDING HEADERS */ +#define RECOVER_ABORT_IF_CLIENTERROR 0x0004 /* CLOSE THE SOCKET IN CASE OF CLIENT ERROR */ +#define RECOVER_ALWAYS_HTTP_HEAD 0x0008 /* RECOVER HTTP HEAD REQUESTS, EVEN IF ABORT OPTIONS ARE SET */ +#define RECOVER_ALWAYS_HTTP_GET 0x0010 /* RECOVER HTTP GET REQUESTS, EVEN IF ABORT OPTIONS ARE SET */ + +#define JK_MAX_HTTP_STATUS_FAILS 32 /* Should be enough for most 400 and 500 statuses */ + +struct jk_res_data +{ + int status; +#ifdef AS400 + char *msg; +#else + const char *msg; +#endif + unsigned num_headers; + char **header_names; + char **header_values; +}; +typedef struct jk_res_data jk_res_data_t; + +#include "jk_ajp14.h" + +struct ajp_operation; +typedef struct ajp_operation ajp_operation_t; + +struct ajp_endpoint; +typedef struct ajp_endpoint ajp_endpoint_t; + +struct ajp_worker; +typedef struct ajp_worker ajp_worker_t; + +struct ajp_worker +{ + jk_worker_t worker; + /* Shared memory worker data */ + jk_shm_ajp_worker_t *s; + + char name[JK_SHM_STR_SIZ+1]; + /* Sequence counter starting at 0 and increasing + * every time we change the config + */ + volatile unsigned int sequence; + + jk_pool_t p; + jk_pool_atom_t buf[TINY_POOL_SIZE]; + + JK_CRIT_SEC cs; + + struct sockaddr_in worker_inet_addr; /* Contains host and port */ + unsigned connect_retry_attempts; + char host[JK_SHM_STR_SIZ+1]; + int port; + int addr_sequence; /* Whether the address is resolved */ + int maintain_time; + /* + * Open connections cache... + * + * 1. Critical section object to protect the cache. + * 2. Cache size. + * 3. An array of "open" endpoints. + */ + unsigned int ep_cache_sz; + unsigned int ep_mincache_sz; + unsigned int ep_maxcache_sz; + int cache_acquire_timeout; + ajp_endpoint_t **ep_cache; + + int proto; /* PROTOCOL USED AJP13/AJP14 */ + + jk_login_service_t *login; + + /* Weak secret similar with ajp12, used in ajp13 */ + const char *secret; + + /* + * Post physical connect handler. + * AJP14 will set here its login handler + */ + int (*logon) (ajp_endpoint_t * ae, jk_logger_t *l); + + /* + * Handle Socket Timeouts + */ + int socket_timeout; + int socket_connect_timeout; + int keepalive; + int socket_buf; + /* + * Handle Cache Timeouts + */ + int cache_timeout; + + /* + * Handle Connection/Reply Timeouts + */ + int connect_timeout; /* connect cping/cpong delay in ms (0 means disabled) */ + int reply_timeout; /* reply timeout delay in ms (0 means disabled) */ + int prepost_timeout; /* before sending a request cping/cpong timeout delay in ms (0 means disabled) */ + int conn_ping_interval; /* interval for sending keepalive cping packets on + * unused connection */ + int ping_timeout; /* generic cping/cpong timeout. Used for keepalive packets or + * as default for boolean valued connect and prepost timeouts. + */ + unsigned int ping_mode; /* Ping mode flags (which types of cpings should be used) */ + /* + * Recovery options + */ + unsigned int recovery_opts; + + /* + * Public property to enable the number of retry attempts + * on this worker. + */ + int retries; + + unsigned int max_packet_size; /* Maximum AJP Packet size */ + + int retry_interval; /* Number of milliseconds to sleep before doing a retry */ + + /* + * HTTP status that will cause failover (0 means disabled) + */ + unsigned int http_status_fail_num; + int http_status_fail[JK_MAX_HTTP_STATUS_FAILS]; +}; + + +/* + * endpoint, the remote connector which does the work + */ +struct ajp_endpoint +{ + ajp_worker_t *worker; + + jk_pool_t pool; + jk_pool_atom_t buf[BIG_POOL_SIZE]; + + int proto; /* PROTOCOL USED AJP13/AJP14 */ + + jk_sock_t sd; + int reuse; + + /* Used with RECOVER_ABORT_IF_CLIENTERROR to hard abort + write of AJP response on client write errors */ + int hard_close; + + jk_endpoint_t endpoint; + + jk_uint64_t left_bytes_to_send; + + /* time of the last request + handled by this endpoint */ + time_t last_access; + int last_errno; + /* Last operation performed via this endpoint */ + int last_op; + int addr_sequence; /* Whether the address is resolved */ +}; + +/* + * little struct to avoid multiples ptr passing + * this struct is ready to hold upload file fd + * to add upload persistant storage + */ +struct ajp_operation +{ + jk_msg_buf_t *request; /* original request storage */ + jk_msg_buf_t *reply; /* reply storage (chuncked by ajp13 */ + jk_msg_buf_t *post; /* small post data storage area */ + int uploadfd; /* future persistant storage id */ + int recoverable; /* if exchange could be conducted on another TC */ +}; + +/* + * Functions + */ + + +const char *jk_ajp_get_state(ajp_worker_t *aw, jk_logger_t *l); + +int jk_ajp_get_state_code(const char *v); + +int ajp_validate(jk_worker_t *pThis, + jk_map_t *props, + jk_worker_env_t *we, jk_logger_t *l, int proto); + +int ajp_init(jk_worker_t *pThis, + jk_map_t *props, + jk_worker_env_t *we, jk_logger_t *l, int proto); + +int JK_METHOD ajp_worker_factory(jk_worker_t **w, + const char *name, jk_logger_t *l); + +int ajp_destroy(jk_worker_t **pThis, jk_logger_t *l, int proto); + +int JK_METHOD ajp_done(jk_endpoint_t **e, jk_logger_t *l); + +int ajp_get_endpoint(jk_worker_t *pThis, + jk_endpoint_t **pend, jk_logger_t *l, int proto); + +int ajp_connect_to_endpoint(ajp_endpoint_t * ae, jk_logger_t *l); + +void ajp_close_endpoint(ajp_endpoint_t * ae, jk_logger_t *l); + +void jk_ajp_pull(ajp_worker_t * aw, int locked, jk_logger_t *l); + +void jk_ajp_push(ajp_worker_t * aw, int locked, jk_logger_t *l); + +int ajp_connection_tcp_send_message(ajp_endpoint_t * ae, + jk_msg_buf_t *msg, jk_logger_t *l); + +int ajp_connection_tcp_get_message(ajp_endpoint_t * ae, + jk_msg_buf_t *msg, jk_logger_t *l); + +int JK_METHOD ajp_maintain(jk_worker_t *pThis, time_t now, jk_logger_t *l); + +int jk_ajp_get_cping_mode(const char *m, int def); + +int ajp_has_endpoint(jk_worker_t *pThis, jk_logger_t *l); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* JK_AJP_COMMON_H */ + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp_common.lo b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp_common.lo new file mode 100644 index 00000000..9d02a8f0 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp_common.lo @@ -0,0 +1,12 @@ +# jk_ajp_common.lo - a libtool object file +# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/jk_ajp_common.o' + +# Name of the non-PIC object. +non_pic_object='jk_ajp_common.o' + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp_common.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp_common.o Binary files differnew file mode 100644 index 00000000..2e6679aa --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp_common.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.c new file mode 100644 index 00000000..edf8c33b --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.c @@ -0,0 +1,1190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Description: Socket/Naming manipulation functions + * Based on: Various Jserv files + */ +/** + * @package jk_connect + * @author Gal Shachor <shachor@il.ibm.com> + * @author Mladen Turk <mturk@apache.org> + * @version $Revision: 1125651 $ + */ + + +#include "jk_connect.h" +#include "jk_util.h" + +#ifdef HAVE_APR +#include "apr_network_io.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_pools.h" +static apr_pool_t *jk_apr_pool = NULL; +#endif + +#ifdef HAVE_SYS_FILIO_H +/* FIONREAD on Solaris et al. */ +#include <sys/filio.h> +#endif +#ifdef HAVE_POLL_H +/* Use poll instead select */ +#include <poll.h> +#endif + +#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__)) +#define JK_IS_SOCKET_ERROR(x) ((x) == SOCKET_ERROR) +#define JK_GET_SOCKET_ERRNO() errno = WSAGetLastError() - WSABASEERR +#else +#define JK_IS_SOCKET_ERROR(x) ((x) == -1) +#define JK_GET_SOCKET_ERRNO() ((void)0) +#endif /* WIN32 */ + +#if defined(NETWARE) && defined(__NOVELL_LIBC__) +#define USE_SOCK_CLOEXEC +#endif + +/* our compiler cant deal with char* <-> const char* ... */ +#if defined(NETWARE) && !defined(__NOVELL_LIBC__) +typedef char* SET_TYPE; +#else +typedef const char* SET_TYPE; +#endif + +/** Set socket to blocking + * @param sd socket to manipulate + * @return errno: fcntl returns -1 (!WIN32) + * pseudo errno: ioctlsocket returns SOCKET_ERROR (WIN32) + * 0: success + */ +static int soblock(jk_sock_t sd) +{ +/* BeOS uses setsockopt at present for non blocking... */ +#if defined (WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__)) + u_long on = 0; + if (JK_IS_SOCKET_ERROR(ioctlsocket(sd, FIONBIO, &on))) { + JK_GET_SOCKET_ERRNO(); + return errno; + } +#else + int fd_flags; + + fd_flags = fcntl(sd, F_GETFL, 0); +#if defined(O_NONBLOCK) + fd_flags &= ~O_NONBLOCK; +#elif defined(O_NDELAY) + fd_flags &= ~O_NDELAY; +#elif defined(FNDELAY) + fd_flags &= ~FNDELAY; +#else +#error Please teach JK how to make sockets blocking on your platform. +#endif + if (fcntl(sd, F_SETFL, fd_flags) == -1) { + return errno; + } +#endif /* WIN32 || (NETWARE && __NOVELL_LIBC__) */ + return 0; +} + +/** Set socket to non-blocking + * @param sd socket to manipulate + * @return errno: fcntl returns -1 (!WIN32) + * pseudo errno: ioctlsocket returns SOCKET_ERROR (WIN32) + * 0: success + */ +static int sononblock(jk_sock_t sd) +{ +#if defined (WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__)) + u_long on = 1; + if (JK_IS_SOCKET_ERROR(ioctlsocket(sd, FIONBIO, &on))) { + JK_GET_SOCKET_ERRNO(); + return errno; + } +#else + int fd_flags; + + fd_flags = fcntl(sd, F_GETFL, 0); +#if defined(O_NONBLOCK) + fd_flags |= O_NONBLOCK; +#elif defined(O_NDELAY) + fd_flags |= O_NDELAY; +#elif defined(FNDELAY) + fd_flags |= FNDELAY; +#else +#error Please teach JK how to make sockets non-blocking on your platform. +#endif + if (fcntl(sd, F_SETFL, fd_flags) == -1) { + return errno; + } +#endif /* WIN32 || (NETWARE && __NOVELL_LIBC__) */ + return 0; +} + +#if defined (WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__)) +/* WIN32 implementation */ +/** Non-blocking socket connect + * @param sd socket to connect + * @param addr address to connect to + * @param timeout connect timeout in seconds + * (<=0: no timeout=blocking) + * @param l logger + * @return -1: some kind of error occured + * SOCKET_ERROR: no timeout given and error + * during blocking connect + * 0: success + */ +static int nb_connect(jk_sock_t sd, struct sockaddr *addr, int timeout, jk_logger_t *l) +{ + int rc; + + JK_TRACE_ENTER(l); + + if (timeout <= 0) { + rc = connect(sd, addr, sizeof(struct sockaddr_in)); + JK_TRACE_EXIT(l); + return rc; + } + + if ((rc = sononblock(sd))) { + JK_TRACE_EXIT(l); + return -1; + } + if (JK_IS_SOCKET_ERROR(connect(sd, addr, sizeof(struct sockaddr_in)))) { + struct timeval tv; + fd_set wfdset, efdset; + + if ((rc = WSAGetLastError()) != WSAEWOULDBLOCK) { + soblock(sd); + WSASetLastError(rc); + JK_TRACE_EXIT(l); + return -1; + } + /* wait for the connect to complete or timeout */ + FD_ZERO(&wfdset); + FD_SET(sd, &wfdset); + FD_ZERO(&efdset); + FD_SET(sd, &efdset); + + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + + rc = select((int)sd + 1, NULL, &wfdset, &efdset, &tv); + if (JK_IS_SOCKET_ERROR(rc) || rc == 0) { + rc = WSAGetLastError(); + soblock(sd); + WSASetLastError(rc); + JK_TRACE_EXIT(l); + return -1; + } + /* Evaluate the efdset */ + if (FD_ISSET(sd, &efdset)) { + /* The connect failed. */ + int rclen = (int)sizeof(rc); + if (getsockopt(sd, SOL_SOCKET, SO_ERROR, (char*) &rc, &rclen)) + rc = 0; + soblock(sd); + if (rc) + WSASetLastError(rc); + JK_TRACE_EXIT(l); + return -1; + } + } + soblock(sd); + JK_TRACE_EXIT(l); + return 0; +} + +#elif !defined(NETWARE) +/* POSIX implementation */ +/** Non-blocking socket connect + * @param sd socket to connect + * @param addr address to connect to + * @param timeout connect timeout in seconds + * (<=0: no timeout=blocking) + * @param l logger + * @return -1: some kind of error occured + * 0: success + */ +static int nb_connect(jk_sock_t sd, struct sockaddr *addr, int timeout, jk_logger_t *l) +{ + int rc = 0; + + JK_TRACE_ENTER(l); + + if (timeout > 0) { + if (sononblock(sd)) { + JK_TRACE_EXIT(l); + return -1; + } + } + do { + rc = connect(sd, addr, sizeof(struct sockaddr_in)); + } while (rc == -1 && errno == EINTR); + + if ((rc == -1) && (errno == EINPROGRESS || errno == EALREADY) + && (timeout > 0)) { + fd_set wfdset; + struct timeval tv; + socklen_t rclen = (socklen_t)sizeof(rc); + + FD_ZERO(&wfdset); + FD_SET(sd, &wfdset); + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + rc = select(sd + 1, NULL, &wfdset, NULL, &tv); + if (rc <= 0) { + /* Save errno */ + int err = errno; + soblock(sd); + errno = err; + JK_TRACE_EXIT(l); + return -1; + } + rc = 0; +#ifdef SO_ERROR + if (!FD_ISSET(sd, &wfdset) || + (getsockopt(sd, SOL_SOCKET, SO_ERROR, + (char *)&rc, &rclen) < 0) || rc) { + if (rc) + errno = rc; + rc = -1; + } +#endif /* SO_ERROR */ + } + /* Not sure we can be already connected */ + if (rc == -1 && errno == EISCONN) + rc = 0; + soblock(sd); + JK_TRACE_EXIT(l); + return rc; +} +#else +/* NETWARE implementation - blocking for now */ +/** Non-blocking socket connect + * @param sd socket to connect + * @param addr address to connect to + * @param timeout connect timeout in seconds (ignored!) + * @param l logger + * @return -1: some kind of error occured + * 0: success + */ +static int nb_connect(jk_sock_t sd, struct sockaddr *addr, int timeout, jk_logger_t *l) +{ + int rc; + + JK_TRACE_ENTER(l); + + rc = connect(sd, addr, sizeof(struct sockaddr_in)); + JK_TRACE_EXIT(l); + return rc; +} +#endif + + +#ifdef AS400_UTF8 + +/* + * i5/OS V5R4 need EBCDIC for its runtime calls but APR/APACHE works in UTF + */ +in_addr_t jk_inet_addr(const char * addrstr) +{ + in_addr_t addr; + char *ptr; + + ptr = (char *)malloc(strlen(addrstr) + 1); + jk_ascii2ebcdic((char *)addrstr, ptr); + addr = inet_addr(ptr); + free(ptr); + + return(addr); +} + +#endif + +/** Resolve the host IP + * @param host host or ip address + * @param port port + * @param rc return value pointer + * @param l logger + * @return JK_FALSE: some kind of error occured + * JK_TRUE: success + */ +int jk_resolve(const char *host, int port, struct sockaddr_in *rc, + void *pool, jk_logger_t *l) +{ + int x; + struct in_addr laddr; + + JK_TRACE_ENTER(l); + + memset(rc, 0, sizeof(struct sockaddr_in)); + + rc->sin_port = htons((short)port); + rc->sin_family = AF_INET; + + /* Check if we only have digits in the string */ + for (x = 0; host[x] != '\0'; x++) { + if (!isdigit((int)(host[x])) && host[x] != '.') { + break; + } + } + + /* If we found also characters we should make name to IP resolution */ + if (host[x] != '\0') { + +#ifdef HAVE_APR + apr_sockaddr_t *remote_sa, *temp_sa; + char *remote_ipaddr; + + if (!jk_apr_pool) { + if (apr_pool_create(&jk_apr_pool, (apr_pool_t *)pool) != APR_SUCCESS) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + apr_pool_clear(jk_apr_pool); + if (apr_sockaddr_info_get + (&remote_sa, host, APR_UNSPEC, (apr_port_t) port, 0, jk_apr_pool) + != APR_SUCCESS) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + /* Since we are only handling AF_INET (IPV4) address (in_addr_t) */ + /* make sure we find one of those. */ + temp_sa = remote_sa; + while ((NULL != temp_sa) && (AF_INET != temp_sa->family)) + temp_sa = temp_sa->next; + + /* if temp_sa is set, we have a valid address otherwise, just return */ + if (NULL != temp_sa) + remote_sa = temp_sa; + else { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + apr_sockaddr_ip_get(&remote_ipaddr, remote_sa); + + laddr.s_addr = jk_inet_addr(remote_ipaddr); + +#else /* HAVE_APR */ + + /* XXX : WARNING : We should really use gethostbyname_r in multi-threaded env */ + /* Fortunatly when APR is available, ie under Apache 2.0, we use it */ +#if defined(NETWARE) && !defined(__NOVELL_LIBC__) + struct hostent *hoste = gethostbyname((char*)host); +#else + struct hostent *hoste = gethostbyname(host); +#endif + if (!hoste) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + laddr = *((struct in_addr *)hoste->h_addr_list[0]); + +#endif /* HAVE_APR */ + } + else { + /* If we found only digits we use inet_addr() */ + laddr.s_addr = jk_inet_addr(host); + } + memcpy(&(rc->sin_addr), &laddr, sizeof(laddr)); + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +/** Connect to Tomcat + * @param addr address to connect to + * @param keepalive should we set SO_KEEPALIVE (if !=0) + * @param timeout connect timeout in seconds + * (<=0: no timeout=blocking) + * @param sock_buf size of send and recv buffer + * (<=0: use default) + * @param l logger + * @return JK_INVALID_SOCKET: some kind of error occured + * created socket: success + * @remark Cares about errno + */ +jk_sock_t jk_open_socket(struct sockaddr_in *addr, int keepalive, + int timeout, int connect_timeout, + int sock_buf, jk_logger_t *l) +{ + char buf[64]; + jk_sock_t sd; + int set = 1; + int ret = 0; + int flags = 0; +#ifdef SO_LINGER + struct linger li; +#endif + + JK_TRACE_ENTER(l); + + errno = 0; +#if defined(SOCK_CLOEXEC) && defined(USE_SOCK_CLOEXEC) + flags |= SOCK_CLOEXEC; +#endif + sd = socket(AF_INET, SOCK_STREAM | flags, 0); + if (!IS_VALID_SOCKET(sd)) { + JK_GET_SOCKET_ERRNO(); + jk_log(l, JK_LOG_ERROR, + "socket() failed (errno=%d)", errno); + JK_TRACE_EXIT(l); + return JK_INVALID_SOCKET; + } +#if defined(FD_CLOEXEC) && !defined(USE_SOCK_CLOEXEC) + if ((flags = fcntl(sd, F_GETFD)) == -1) { + JK_GET_SOCKET_ERRNO(); + jk_log(l, JK_LOG_ERROR, + "fcntl() failed (errno=%d)", errno); + jk_close_socket(sd, l); + JK_TRACE_EXIT(l); + return JK_INVALID_SOCKET; + } + flags |= FD_CLOEXEC; + if (fcntl(sd, F_SETFD, flags) == -1) { + JK_GET_SOCKET_ERRNO(); + jk_log(l, JK_LOG_ERROR, + "fcntl() failed (errno=%d)", errno); + jk_close_socket(sd, l); + JK_TRACE_EXIT(l); + return JK_INVALID_SOCKET; + } +#endif + + /* Disable Nagle algorithm */ + if (setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, (SET_TYPE)&set, + sizeof(set))) { + JK_GET_SOCKET_ERRNO(); + jk_log(l, JK_LOG_ERROR, + "failed setting TCP_NODELAY (errno=%d)", errno); + jk_close_socket(sd, l); + JK_TRACE_EXIT(l); + return JK_INVALID_SOCKET; + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "socket TCP_NODELAY set to On"); + if (keepalive) { +#if defined(WIN32) && !defined(NETWARE) + DWORD dw; + struct tcp_keepalive ka = { 0 }, ks = { 0 }; + if (timeout) + ka.keepalivetime = timeout * 10000; + else + ka.keepalivetime = 60 * 10000; /* 10 minutes */ + ka.keepaliveinterval = 1000; + ka.onoff = 1; + if (WSAIoctl(sd, SIO_KEEPALIVE_VALS, &ka, sizeof(ka), + &ks, sizeof(ks), &dw, NULL, NULL)) { + JK_GET_SOCKET_ERRNO(); + jk_log(l, JK_LOG_ERROR, + "failed setting SIO_KEEPALIVE_VALS (errno=%d)", errno); + jk_close_socket(sd, l); + JK_TRACE_EXIT(l); + return JK_INVALID_SOCKET; + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "socket SO_KEEPALIVE set to %d seconds", + ka.keepalivetime / 1000); +#else + set = 1; + if (setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, (SET_TYPE)&set, + sizeof(set))) { + JK_GET_SOCKET_ERRNO(); + jk_log(l, JK_LOG_ERROR, + "failed setting SO_KEEPALIVE (errno=%d)", errno); + jk_close_socket(sd, l); + JK_TRACE_EXIT(l); + return JK_INVALID_SOCKET; + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "socket SO_KEEPALIVE set to On"); +#endif + } + + if (sock_buf > 0) { + set = sock_buf; + /* Set socket send buffer size */ + if (setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (SET_TYPE)&set, + sizeof(set))) { + JK_GET_SOCKET_ERRNO(); + jk_log(l, JK_LOG_ERROR, + "failed setting SO_SNDBUF (errno=%d)", errno); + jk_close_socket(sd, l); + JK_TRACE_EXIT(l); + return JK_INVALID_SOCKET; + } + set = sock_buf; + /* Set socket receive buffer size */ + if (setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (SET_TYPE)&set, + sizeof(set))) { + JK_GET_SOCKET_ERRNO(); + jk_log(l, JK_LOG_ERROR, + "failed setting SO_RCVBUF (errno=%d)", errno); + jk_close_socket(sd, l); + JK_TRACE_EXIT(l); + return JK_INVALID_SOCKET; + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "socket SO_SNDBUF and SO_RCVBUF set to %d", + sock_buf); + } + + if (timeout > 0) { +#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__)) + int tmout = timeout * 1000; + setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, + (const char *) &tmout, sizeof(int)); + setsockopt(sd, SOL_SOCKET, SO_SNDTIMEO, + (const char *) &tmout, sizeof(int)); + JK_GET_SOCKET_ERRNO(); +#elif defined(SO_RCVTIMEO) && defined(USE_SO_RCVTIMEO) && defined(SO_SNDTIMEO) && defined(USE_SO_SNDTIMEO) + struct timeval tv; + tv.tv_sec = timeout; + tv.tv_usec = 0; + setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, + (const void *) &tv, sizeof(tv)); + setsockopt(sd, SOL_SOCKET, SO_SNDTIMEO, + (const void *) &tv, sizeof(tv)); +#endif + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "timeout %d set for socket=%d", + timeout, sd); + } +#ifdef SO_NOSIGPIPE + /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when + * sending data to a dead peer. Possibly also existing and in use on other BSD + * systems? + */ + set = 1; + if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, (const char *)&set, + sizeof(int))) { + JK_GET_SOCKET_ERRNO(); + jk_log(l, JK_LOG_ERROR, + "failed setting SO_NOSIGPIPE (errno=%d)", errno); + jk_close_socket(sd, l); + JK_TRACE_EXIT(l); + return JK_INVALID_SOCKET; + } +#endif +#ifdef SO_LINGER + /* Make hard closesocket by disabling lingering */ + li.l_linger = li.l_onoff = 0; + if (setsockopt(sd, SOL_SOCKET, SO_LINGER, (SET_TYPE)&li, + sizeof(li))) { + JK_GET_SOCKET_ERRNO(); + jk_log(l, JK_LOG_ERROR, + "failed setting SO_LINGER (errno=%d)", errno); + jk_close_socket(sd, l); + JK_TRACE_EXIT(l); + return JK_INVALID_SOCKET; + } +#endif + /* Tries to connect to Tomcat (continues trying while error is EINTR) */ + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "trying to connect socket %d to %s", sd, + jk_dump_hinfo(addr, buf)); + +/* Need more infos for BSD 4.4 and Unix 98 defines, for now only +iSeries when Unix98 is required at compil time */ +#if (_XOPEN_SOURCE >= 520) && defined(AS400) + ((struct sockaddr *)addr)->sa_len = sizeof(struct sockaddr_in); +#endif + ret = nb_connect(sd, (struct sockaddr *)addr, connect_timeout, l); +#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__)) + if (JK_IS_SOCKET_ERROR(ret)) { + JK_GET_SOCKET_ERRNO(); + } +#endif /* WIN32 */ + + /* Check if we are connected */ + if (ret) { + jk_log(l, JK_LOG_INFO, + "connect to %s failed (errno=%d)", + jk_dump_hinfo(addr, buf), errno); + jk_close_socket(sd, l); + sd = JK_INVALID_SOCKET; + } + else { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, "socket %d [%s] connected", + sd, jk_dump_sinfo(sd, buf)); + } + JK_TRACE_EXIT(l); + return sd; +} + +/** Close the socket + * @param sd socket to close + * @param l logger + * @return -1: some kind of error occured (!WIN32) + * SOCKET_ERROR: some kind of error occured (WIN32) + * 0: success + * @remark Does not change errno + */ +int jk_close_socket(jk_sock_t sd, jk_logger_t *l) +{ + int rc; + int save_errno; + + JK_TRACE_ENTER(l); + + if (!IS_VALID_SOCKET(sd)) { + JK_TRACE_EXIT(l); + return -1; + } + + save_errno = errno; +#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__)) + rc = closesocket(sd) ? -1 : 0; +#else + do { + rc = close(sd); + } while (JK_IS_SOCKET_ERROR(rc) && (errno == EINTR || errno == EAGAIN)); +#endif + JK_TRACE_EXIT(l); + errno = save_errno; + return rc; +} + +#ifndef MAX_SECS_TO_LINGER +#define MAX_SECS_TO_LINGER 2 +#endif +#define MS_TO_LINGER 500 +#define MS_TO_LINGER_LAST 2 + +#ifndef MAX_LINGER_BYTES +#define MAX_LINGER_BYTES 32768 +#endif + +#ifndef SHUT_WR +#ifdef SD_SEND +#define SHUT_WR SD_SEND +#else +#define SHUT_WR 0x01 +#endif +#endif + +#ifndef SHUT_RD +#ifdef SD_RECEIVE +#define SHUT_RD SD_RECEIVE +#else +#define SHUT_RD 0x00 +#endif +#endif + +/** Drain and close the socket + * @param sd socket to close + * @param l logger + * @return -1: socket to close is invalid + * -1: some kind of error occured (!WIN32) + * SOCKET_ERROR: some kind of error occured (WIN32) + * 0: success + * @remark Does not change errno + */ +int jk_shutdown_socket(jk_sock_t sd, jk_logger_t *l) +{ + char dummy[512]; + char buf[64]; + char *sb = NULL; + int rc = 0; + size_t rd = 0; + size_t rp = 0; + int save_errno; + int timeout = MS_TO_LINGER; + time_t start = time(NULL); + + JK_TRACE_ENTER(l); + + if (!IS_VALID_SOCKET(sd)) { + JK_TRACE_EXIT(l); + return -1; + } + + save_errno = errno; + if (JK_IS_DEBUG_LEVEL(l)) { + sb = jk_dump_sinfo(sd, buf); + jk_log(l, JK_LOG_DEBUG, "About to shutdown socket %d [%s]", + sd, sb); + } + /* Shut down the socket for write, which will send a FIN + * to the peer. + */ + if (shutdown(sd, SHUT_WR)) { + rc = jk_close_socket(sd, l); + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Failed sending SHUT_WR for socket %d [%s]", + sd, sb); + errno = save_errno; + JK_TRACE_EXIT(l); + return rc; + } + + do { + rp = 0; + if (jk_is_input_event(sd, timeout, l)) { + /* Do a restartable read on the socket + * draining out all the data currently in the socket buffer. + */ + do { +#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__)) + rc = recv(sd, &dummy[0], sizeof(dummy), 0); + if (JK_IS_SOCKET_ERROR(rc)) + JK_GET_SOCKET_ERRNO(); +#else + rc = read(sd, &dummy[0], sizeof(dummy)); +#endif + if (rc > 0) + rp += rc; + } while (JK_IS_SOCKET_ERROR(rc) && (errno == EINTR || errno == EAGAIN)); + + if (rc < 0) { + /* Read failed. + * Bail out from the loop. + */ + break; + } + } + else { + /* Error or timeout (reason is logged within jk_is_input_event) + * Exit the drain loop + */ + break; + } + rd += rp; + if (rp < sizeof(dummy)) { + if (timeout > MS_TO_LINGER_LAST) { + /* Try one last time with a short timeout + */ + timeout = MS_TO_LINGER_LAST; + continue; + } + /* We have read less then size of buffer + * It's a good chance there will be no more data + * to read. + */ + if ((rc = sononblock(sd))) { + rc = jk_close_socket(sd, l); + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "error setting socket %d [%s] to nonblocking", + sd, sb); + errno = save_errno; + JK_TRACE_EXIT(l); + return rc; + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "shutting down the read side of socket %d [%s]", + sd, sb); + shutdown(sd, SHUT_RD); + break; + } + timeout = MS_TO_LINGER; + } while ((rd < MAX_LINGER_BYTES) && (difftime(time(NULL), start) < MAX_SECS_TO_LINGER)); + + rc = jk_close_socket(sd, l); + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Shutdown socket %d [%s] and read %d lingering bytes in %d sec.", + sd, sb, rd, (int)difftime(time(NULL), start)); + errno = save_errno; + JK_TRACE_EXIT(l); + return rc; +} + +/** send a message + * @param sd socket to use + * @param b buffer containing the data + * @param len length to send + * @param l logger + * @return negative errno: write returns a fatal -1 (!WIN32) + * negative pseudo errno: send returns SOCKET_ERROR (WIN32) + * JK_SOCKET_EOF: no bytes could be sent + * >0: success, provided number of bytes send + * @remark Always closes socket in case of error + * @remark Cares about errno + * @bug this fails on Unixes if len is too big for the underlying + * protocol + */ +int jk_tcp_socket_sendfull(jk_sock_t sd, const unsigned char *b, int len, jk_logger_t *l) +{ + int sent = 0; + int wr; + + JK_TRACE_ENTER(l); + + errno = 0; + while (sent < len) { + do { +#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__)) + wr = send(sd, (const char*)(b + sent), + len - sent, 0); + if (JK_IS_SOCKET_ERROR(wr)) + JK_GET_SOCKET_ERRNO(); +#else + wr = write(sd, b + sent, len - sent); +#endif + } while (JK_IS_SOCKET_ERROR(wr) && (errno == EINTR || errno == EAGAIN)); + + if (JK_IS_SOCKET_ERROR(wr)) { + int err; + jk_shutdown_socket(sd, l); + err = (errno > 0) ? -errno : errno; + JK_TRACE_EXIT(l); + return err; + } + else if (wr == 0) { + jk_shutdown_socket(sd, l); + JK_TRACE_EXIT(l); + return JK_SOCKET_EOF; + } + sent += wr; + } + + JK_TRACE_EXIT(l); + return sent; +} + +/** receive a message + * @param sd socket to use + * @param b buffer to store the data + * @param len length to receive + * @param l logger + * @return negative errno: read returns a fatal -1 (!WIN32) + * negative pseudo errno: recv returns SOCKET_ERROR (WIN32) + * JK_SOCKET_EOF: no bytes could be read + * >0: success, requested number of bytes received + * @remark Always closes socket in case of error + * @remark Cares about errno + */ +int jk_tcp_socket_recvfull(jk_sock_t sd, unsigned char *b, int len, jk_logger_t *l) +{ + int rdlen = 0; + int rd; + + JK_TRACE_ENTER(l); + + errno = 0; + while (rdlen < len) { + do { +#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__)) + rd = recv(sd, (char *)b + rdlen, + len - rdlen, 0); + if (JK_IS_SOCKET_ERROR(rd)) + JK_GET_SOCKET_ERRNO(); +#else + rd = read(sd, (char *)b + rdlen, len - rdlen); +#endif + } while (JK_IS_SOCKET_ERROR(rd) && errno == EINTR); + + if (JK_IS_SOCKET_ERROR(rd)) { + int err = (errno > 0) ? -errno : errno; + jk_shutdown_socket(sd, l); + JK_TRACE_EXIT(l); + return (err == 0) ? JK_SOCKET_EOF : err; + } + else if (rd == 0) { + jk_shutdown_socket(sd, l); + JK_TRACE_EXIT(l); + return JK_SOCKET_EOF; + } + rdlen += rd; + } + + JK_TRACE_EXIT(l); + return rdlen; +} + +/** + * dump a sockaddr_in in A.B.C.D:P in ASCII buffer + * + */ +char *jk_dump_hinfo(struct sockaddr_in *saddr, char *buf) +{ + unsigned long laddr = (unsigned long)htonl(saddr->sin_addr.s_addr); + unsigned short lport = (unsigned short)htons(saddr->sin_port); + + sprintf(buf, "%d.%d.%d.%d:%d", + (int)(laddr >> 24), (int)((laddr >> 16) & 0xff), + (int)((laddr >> 8) & 0xff), (int)(laddr & 0xff), (int)lport); + + return buf; +} + +char *jk_dump_sinfo(jk_sock_t sd, char *buf) +{ + struct sockaddr_in rsaddr; + struct sockaddr_in lsaddr; + socklen_t salen; + + salen = sizeof(struct sockaddr); + if (getsockname(sd, (struct sockaddr *)&lsaddr, &salen) == 0) { + salen = sizeof(struct sockaddr); + if (getpeername(sd, (struct sockaddr *)&rsaddr, &salen) == 0) { + unsigned long laddr = (unsigned long)htonl(lsaddr.sin_addr.s_addr); + unsigned short lport = (unsigned short)htons(lsaddr.sin_port); + unsigned long raddr = (unsigned long)htonl(rsaddr.sin_addr.s_addr); + unsigned short rport = (unsigned short)htons(rsaddr.sin_port); + sprintf(buf, "%d.%d.%d.%d:%d -> %d.%d.%d.%d:%d", + (int)(laddr >> 24), (int)((laddr >> 16) & 0xff), + (int)((laddr >> 8) & 0xff), (int)(laddr & 0xff), (int)lport, + (int)(raddr >> 24), (int)((raddr >> 16) & 0xff), + (int)((raddr >> 8) & 0xff), (int)(raddr & 0xff), (int)rport); + return buf; + } + } + sprintf(buf, "error=%d", errno); + return buf; +} + +/** Wait for input event on socket until timeout + * @param sd socket to use + * @param timeout wait timeout in milliseconds + * @param l logger + * @return JK_FALSE: Timeout expired without something to read + * JK_FALSE: Error during waiting + * JK_TRUE: success + * @remark Does not close socket in case of error + * to allow for iterative waiting + * @remark Cares about errno + */ +#ifdef HAVE_POLL +int jk_is_input_event(jk_sock_t sd, int timeout, jk_logger_t *l) +{ + struct pollfd fds; + int rc; + int save_errno; + char buf[64]; + + JK_TRACE_ENTER(l); + + errno = 0; + fds.fd = sd; + fds.events = POLLIN; + fds.revents = 0; + + do { + rc = poll(&fds, 1, timeout); + } while (rc < 0 && errno == EINTR); + + if (rc == 0) { + if (JK_IS_DEBUG_LEVEL(l)) { + jk_log(l, JK_LOG_DEBUG, + "timeout during poll on socket %d [%s] (timeout=%d)", + sd, jk_dump_sinfo(sd, buf), timeout); + } + /* Timeout. Set the errno to timeout */ + errno = ETIMEDOUT; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + else if (rc < 0) { + save_errno = errno; + if (JK_IS_DEBUG_LEVEL(l)) { + jk_log(l, JK_LOG_DEBUG, + "error during poll on socket %d [%s] (errno=%d)", + sd, jk_dump_sinfo(sd, buf), errno); + } + errno = save_errno; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + if ((fds.revents & (POLLERR | POLLHUP))) { + save_errno = fds.revents & (POLLERR | POLLHUP); + if (JK_IS_DEBUG_LEVEL(l)) { + jk_log(l, JK_LOG_DEBUG, + "error event during poll on socket %d [%s] (event=%d)", + sd, jk_dump_sinfo(sd, buf), save_errno); + } + errno = save_errno; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + errno = 0; + JK_TRACE_EXIT(l); + return JK_TRUE; +} +#else +int jk_is_input_event(jk_sock_t sd, int timeout, jk_logger_t *l) +{ + fd_set rset; + struct timeval tv; + int rc; + int save_errno; + char buf[64]; + + JK_TRACE_ENTER(l); + + errno = 0; + FD_ZERO(&rset); + FD_SET(sd, &rset); + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + + do { + rc = select((int)sd + 1, &rset, NULL, NULL, &tv); + } while (rc < 0 && errno == EINTR); + + if (rc == 0) { + if (JK_IS_DEBUG_LEVEL(l)) { + jk_log(l, JK_LOG_DEBUG, + "timeout during select on socket %d [%s] (timeout=%d)", + sd, jk_dump_sinfo(sd, buf), timeout); + } + /* Timeout. Set the errno to timeout */ +#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__)) + errno = WSAETIMEDOUT - WSABASEERR; +#else + errno = ETIMEDOUT; +#endif + JK_TRACE_EXIT(l); + return JK_FALSE; + } + else if (rc < 0) { + save_errno = errno; + if (JK_IS_DEBUG_LEVEL(l)) { + jk_log(l, JK_LOG_DEBUG, + "error during select on socket %d [%s] (errno=%d)", + sd, jk_dump_sinfo(sd, buf), errno); + } + errno = save_errno; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + errno = 0; + JK_TRACE_EXIT(l); + return JK_TRUE; +} +#endif + +/** Test if a socket is still connected + * @param sd socket to use + * @param l logger + * @return JK_FALSE: failure + * JK_TRUE: success + * @remark Always closes socket in case of error + * @remark Cares about errno + */ +#ifdef HAVE_POLL +int jk_is_socket_connected(jk_sock_t sd, jk_logger_t *l) +{ + struct pollfd fds; + int rc; + + JK_TRACE_ENTER(l); + + errno = 0; + fds.fd = sd; + fds.events = POLLIN; + + do { + rc = poll(&fds, 1, 0); + } while (rc < 0 && errno == EINTR); + + if (rc == 0) { + /* If we get a timeout, then we are still connected */ + JK_TRACE_EXIT(l); + return JK_TRUE; + } + else if (rc == 1 && fds.revents == POLLIN) { + char buf; + do { + rc = (int)recvfrom(sd, &buf, 1, MSG_PEEK, NULL, NULL); + } while (rc < 0 && errno == EINTR); + if (rc == 1) { + /* There is at least one byte to read. */ + JK_TRACE_EXIT(l); + return JK_TRUE; + } + } + jk_shutdown_socket(sd, l); + + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +#else +int jk_is_socket_connected(jk_sock_t sd, jk_logger_t *l) +{ + fd_set fd; + struct timeval tv; + int rc; + + JK_TRACE_ENTER(l); + + errno = 0; + FD_ZERO(&fd); + FD_SET(sd, &fd); + + /* Initially test the socket without any blocking. + */ + tv.tv_sec = 0; + tv.tv_usec = 0; + + do { + rc = select((int)sd + 1, &fd, NULL, NULL, &tv); + JK_GET_SOCKET_ERRNO(); + /* Wait one microsecond on next select, if EINTR */ + tv.tv_sec = 0; + tv.tv_usec = 1; + } while (JK_IS_SOCKET_ERROR(rc) && errno == EINTR); + + errno = 0; + if (rc == 0) { + /* If we get a timeout, then we are still connected */ + JK_TRACE_EXIT(l); + return JK_TRUE; + } + else if (rc == 1) { +#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__)) + u_long nr; + rc = ioctlsocket(sd, FIONREAD, &nr); + if (rc == 0) { + if (WSAGetLastError() == 0) + errno = 0; + else + JK_GET_SOCKET_ERRNO(); + } +#else + int nr; + rc = ioctl(sd, FIONREAD, (void*)&nr); +#endif + if (rc == 0 && nr != 0) { + JK_TRACE_EXIT(l); + return JK_TRUE; + } + JK_GET_SOCKET_ERRNO(); + } + jk_shutdown_socket(sd, l); + + JK_TRACE_EXIT(l); + return JK_FALSE; +} +#endif + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.h new file mode 100644 index 00000000..04edde23 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.h @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Socket connections header file * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Version: $Revision: 995751 $ * + ***************************************************************************/ + +#ifndef JK_CONNECT_H +#define JK_CONNECT_H + +#include "jk_logger.h" +#include "jk_global.h" + +#if !defined(WIN32) && !(defined(NETWARE) && defined(__NOVELL_LIBC__)) +#define closesocket close +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#define JK_SOCKET_EOF (-2) + +int jk_resolve(const char *host, int port, struct sockaddr_in *rc, void *pool, jk_logger_t *l); + +jk_sock_t jk_open_socket(struct sockaddr_in *addr, int keepalive, + int timeout, int connect_timeout, + int sock_buf, jk_logger_t *l); + +int jk_close_socket(jk_sock_t sd, jk_logger_t *l); + +int jk_shutdown_socket(jk_sock_t sd, jk_logger_t *l); + +int jk_tcp_socket_sendfull(jk_sock_t sd, const unsigned char *b, int len, jk_logger_t *l); + +int jk_tcp_socket_recvfull(jk_sock_t sd, unsigned char *b, int len, jk_logger_t *l); + +char *jk_dump_hinfo(struct sockaddr_in *saddr, char *buf); + +char *jk_dump_sinfo(jk_sock_t sd, char *buf); + +int jk_is_input_event(jk_sock_t sd, int timeout, jk_logger_t *l); + +int jk_is_socket_connected(jk_sock_t sd, jk_logger_t *l); + + +/*** + * i5/OS V5R4 need ASCII<->EBCDIC translation for inet_addr() call + */ +#if !defined(AS400_UTF8) + +#define jk_inet_addr inet_addr + +#endif + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* JK_CONNECT_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.lo b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.lo new file mode 100644 index 00000000..d1cf96e4 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.lo @@ -0,0 +1,12 @@ +# jk_connect.lo - a libtool object file +# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/jk_connect.o' + +# Name of the non-PIC object. +non_pic_object='jk_connect.o' + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.o Binary files differnew file mode 100644 index 00000000..d33c04e2 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_context.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_context.c new file mode 100644 index 00000000..f65ba836 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_context.c @@ -0,0 +1,296 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Context handling (Autoconf) * + * Author: Henri Gomez <hgomez@apache.org> * + * Version: $Revision: 466585 $ * + ***************************************************************************/ + +#include "jk_global.h" +#include "jk_context.h" +#include "jk_ajp_common.h" + + +/* + * Set the virtual name of the context + */ + +int context_set_virtual(jk_context_t *c, char *virt) +{ + if (c) { + + if (virt) { + c->virt = jk_pool_strdup(&c->p, virt); + + if (!c->virt) + return JK_FALSE; + } + + return JK_TRUE; + } + + return JK_FALSE; +} + +/* + * Init the context info struct + */ + +int context_open(jk_context_t *c, char *virt) +{ + if (c) { + jk_open_pool(&c->p, c->buf, sizeof(jk_pool_atom_t) * SMALL_POOL_SIZE); + c->size = 0; + c->capacity = 0; + c->contexts = NULL; + + return context_set_virtual(c, virt); + } + + return JK_FALSE; +} + +/* + * Close the context info struct + */ + +int context_close(jk_context_t *c) +{ + if (c) { + + jk_close_pool(&c->p); + return JK_TRUE; + } + + return JK_FALSE; +} + +/* + * Allocate and open context + */ + +int context_alloc(jk_context_t **c, char *virt) +{ + if (c) + return context_open(*c = + (jk_context_t *)calloc(1, sizeof(jk_context_t)), + virt); + + return JK_FALSE; +} + +/* + * Close and destroy context + */ + +int context_free(jk_context_t **c) +{ + if (c && *c) { + context_close(*c); + free(*c); + *c = NULL; + return JK_TRUE; + } + + return JK_FALSE; +} + + +/* + * Ensure there will be memory in context info to store Context Bases + */ + +static int context_realloc(jk_context_t *c) +{ + if (c->size == c->capacity) { + jk_context_item_t **contexts; + int capacity = c->capacity + CBASE_INC_SIZE; + + contexts = + (jk_context_item_t **)jk_pool_alloc(&c->p, + sizeof(jk_context_item_t *) * + capacity); + + if (!contexts) + return JK_FALSE; + + if (c->capacity && c->contexts) + memcpy(contexts, c->contexts, + sizeof(jk_context_item_t *) * c->capacity); + + c->contexts = contexts; + c->capacity = capacity; + } + + return JK_TRUE; +} + +/* + * Ensure there will be memory in context info to URIS + */ + +static int context_item_realloc(jk_context_t *c, jk_context_item_t *ci) +{ + if (ci->size == ci->capacity) { + char **uris; + int capacity = ci->capacity + URI_INC_SIZE; + + uris = (char **)jk_pool_alloc(&c->p, sizeof(char *) * capacity); + + if (!uris) + return JK_FALSE; + + memcpy(uris, ci->uris, sizeof(char *) * ci->capacity); + + ci->uris = uris; + ci->capacity = capacity; + } + + return JK_TRUE; +} + + +/* + * Locate a context base in context list + */ + +jk_context_item_t *context_find_base(jk_context_t *c, char *cbase) +{ + int i; + jk_context_item_t *ci; + + if (!c || !cbase) + return NULL; + + for (i = 0; i < c->size; i++) { + + ci = c->contexts[i]; + + if (!ci) + continue; + + if (!strcmp(ci->cbase, cbase)) + return ci; + } + + return NULL; +} + +/* + * Locate an URI in a context item + */ + +char *context_item_find_uri(jk_context_item_t *ci, char *uri) +{ + int i; + + if (!ci || !uri) + return NULL; + + for (i = 0; i < ci->size; i++) { + if (!strcmp(ci->uris[i], uri)) + return ci->uris[i]; + } + + return NULL; +} + +void context_dump_uris(jk_context_t *c, char *cbase, FILE * f) +{ + jk_context_item_t *ci; + int i; + + ci = context_find_base(c, cbase); + + if (!ci) + return; + + for (i = 0; i < ci->size; i++) + fprintf(f, "/%s/%s\n", ci->cbase, ci->uris[i]); + + fflush(f); +} + + +/* + * Add a new context item to context + */ + +jk_context_item_t *context_add_base(jk_context_t *c, char *cbase) +{ + jk_context_item_t *ci; + + if (!c || !cbase) + return NULL; + + /* Check if the context base was not allready created */ + ci = context_find_base(c, cbase); + + if (ci) + return ci; + + if (context_realloc(c) != JK_TRUE) + return NULL; + + ci = (jk_context_item_t *)jk_pool_alloc(&c->p, sizeof(jk_context_item_t)); + + if (!ci) + return NULL; + + c->contexts[c->size] = ci; + c->size++; + ci->cbase = jk_pool_strdup(&c->p, cbase); + ci->status = 0; + ci->size = 0; + ci->capacity = 0; + ci->uris = NULL; + + return ci; +} + +/* + * Add a new URI to a context item + */ + +int context_add_uri(jk_context_t *c, char *cbase, char *uri) +{ + jk_context_item_t *ci; + + if (!uri) + return JK_FALSE; + + /* Get/Create the context base */ + ci = context_add_base(c, cbase); + + if (!ci) + return JK_FALSE; + + if (context_item_find_uri(ci, uri) != NULL) + return JK_TRUE; + + if (context_item_realloc(c, ci) == JK_FALSE) + return JK_FALSE; + + ci->uris[ci->size] = jk_pool_strdup(&c->p, uri); + + if (ci->uris[ci->size] == NULL) + return JK_FALSE; + + ci->size++; + return JK_TRUE; +} diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_context.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_context.h new file mode 100644 index 00000000..7c872f58 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_context.h @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Context Stuff (Autoconf) * + * Author: Henri Gomez <hgomez@apache.org> * + * Version: $Revision: 466585 $ * + ***************************************************************************/ +#ifndef JK_CONTEXT_H +#define JK_CONTEXT_H + +#include "jk_pool.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#define CBASE_INC_SIZE (8) /* Allocate memory by step of 8 URIs : ie 8 URI by context */ +#define URI_INC_SIZE (8) /* Allocate memory by step of 8 CONTEXTs : ie 8 contexts by worker */ + +typedef struct +{ + + /* + * Context base (ie examples) + */ + + char *cbase; + + /* + * Status (Up/Down) + */ + + int status; + + /* + * Num of URI handled + */ + + int size; + + /* + * Capacity + */ + + int capacity; + + /* + * URL/URIs (autoconf) + */ + + char **uris; +} +jk_context_item_t; + + +typedef struct +{ + + /* + * Memory Pool + */ + + jk_pool_t p; + jk_pool_atom_t buf[SMALL_POOL_SIZE]; + + /* + * Virtual Server (if use) + */ + + char *virt; + + /* + * Num of context handled (ie: examples, admin...) + */ + + int size; + + /* + * Capacity + */ + + int capacity; + + /* + * Context list, context / URIs + */ + + jk_context_item_t **contexts; +} +jk_context_t; + + +/* + * functions defined here + */ + +int context_set_virtual(jk_context_t *c, char *virt); + +int context_open(jk_context_t *c, char *virt); + +int context_close(jk_context_t *c); + +int context_alloc(jk_context_t **c, char *virt); + +int context_free(jk_context_t **c); + +jk_context_item_t *context_find_base(jk_context_t *c, char *cbase); + +char *context_item_find_uri(jk_context_item_t *ci, char *uri); + +void context_dump_uris(jk_context_t *c, char *cbase, FILE * f); + +jk_context_item_t *context_add_base(jk_context_t *c, char *cbase); + +int context_add_uri(jk_context_t *c, char *cbase, char *uri); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* JK_CONTEXT_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_context.lo b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_context.lo new file mode 100644 index 00000000..a03a50c6 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_context.lo @@ -0,0 +1,12 @@ +# jk_context.lo - a libtool object file +# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/jk_context.o' + +# Name of the non-PIC object. +non_pic_object='jk_context.o' + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_context.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_context.o Binary files differnew file mode 100644 index 00000000..88da42a1 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_context.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_global.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_global.h new file mode 100644 index 00000000..c041b49a --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_global.h @@ -0,0 +1,405 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Global definitions and include files that should exist * + * anywhere * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Version: $Revision: 1126561 $ * + ***************************************************************************/ + +#ifndef JK_GLOBAL_H +#define JK_GLOBAL_H + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#if defined(WIN32) + +/* Ignore most warnings (back down to /W3) for poorly constructed headers + */ +#if defined(_MSC_VER) && _MSC_VER >= 1200 +#pragma warning(push, 3) +#endif + +/* disable or reduce the frequency of... + * C4057: indirection to slightly different base types + * C4075: slight indirection changes (unsigned short* vs short[]) + * C4100: unreferenced formal parameter + * C4127: conditional expression is constant + * C4163: '_rotl64' : not available as an intrinsic function + * C4201: nonstandard extension nameless struct/unions + * C4244: int to char/short - precision loss + * C4514: unreferenced inline function removed + */ +#pragma warning(disable: 4100 4127 4163 4201 4514; once: 4057 4075 4244) + +/* Ignore Microsoft's interpretation of secure development + * and the POSIX string handling API + */ +#if defined(_MSC_VER) && _MSC_VER >= 1400 +#ifndef _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE +#endif +#pragma warning(disable: 4996) +#endif /* defined(_MSC_VER) && _MSC_VER >= 1400 */ +#endif /* defined(WIN32) */ + +#include "jk_version.h" + +#ifdef HAVE_APR +#include "apr_lib.h" +#include "apr_strings.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <errno.h> +#include <time.h> +#include <ctype.h> +#include <limits.h> + +#ifdef _OSD_POSIX +#include "ap_config.h" +#endif + +#ifdef AS400 +#include "ap_config.h" +extern char *strdup(const char *str); +#endif + +#include <sys/types.h> +#include <sys/stat.h> + +#ifdef WIN32 +#ifndef _WINDOWS_ +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef _WIN32_WINNT + +/* Restrict the server to a subset of Windows NT 4.0 header files by default + */ +#define _WIN32_WINNT 0x0500 +#endif +#ifndef NOUSER +#define NOUSER +#endif +#ifndef NOMCX +#define NOMCX +#endif +#ifndef NOIME +#define NOIME +#endif +#include <windows.h> +/* + * Add a _very_few_ declarations missing from the restricted set of headers + * (If this list becomes extensive, re-enable the required headers above!) + * winsock headers were excluded by WIN32_LEAN_AND_MEAN, so include them now + */ +#include <winsock2.h> +#include <mswsock.h> +#include <mstcpip.h> +#endif /* _WINDOWS_ */ +#ifdef _WINDOWS_ +#ifndef SIO_RCVALL +#include <mstcpip.h> +#endif +#endif +#include <sys/timeb.h> +#include <process.h> +#include <io.h> +#include <ws2tcpip.h> +#else /* WIN32 */ +#include <unistd.h> +#if defined(NETWARE) && defined(__NOVELL_LIBC__) +#include <novsock2.h> +#define __sys_socket_h__ +#define __netdb_h__ +#define __netinet_in_h__ +#define HAVE_VSNPRINTF +#define HAVE_SNPRINTF +#endif +#include <netdb.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <fcntl.h> +#ifdef NETWARE +#ifndef _SOCKLEN_T +#define _SOCKLEN_T +typedef int socklen_t; +#endif +#else +#include <netinet/tcp.h> +#include <arpa/inet.h> +#include <sys/un.h> +#if !defined(_OSD_POSIX) && !defined(AS400) && !defined(__CYGWIN__) && !defined(HPUX11) +#include <sys/socketvar.h> +#endif +#if !defined(HPUX11) && !defined(AS400) +#include <sys/select.h> +#endif +#endif /* NETWARE */ + +#include <sys/time.h> +#include <sys/ioctl.h> +#endif /* WIN32 */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#define JK_WORKER_FILE_TAG ("worker_file") +#define JK_MOUNT_FILE_TAG ("worker_mount_file") +#define JK_LOG_LEVEL_TAG ("log_level") +#define JK_LOG_FILE_TAG ("log_file") +#define JK_SHM_FILE_TAG ("shm_file") +#define JK_WORKER_NAME_TAG ("worker") + +#define JK_WORKER_FILE_DEF ("workers.properties") + +/* Urimap reload check time. Use 60 seconds by default. + */ +#define JK_URIMAP_DEF_RELOAD (60) + +#define JK_TRUE (1) +#define JK_FALSE (0) + +#define JK_UNSET (-1) + +#define JK_LF (10) +#define JK_CR (13) + +#define JK_SESSION_IDENTIFIER "JSESSIONID" +#define JK_PATH_SESSION_IDENTIFIER ";jsessionid" + +#if defined(WIN32) || defined(NETWARE) +#ifdef __GNUC__ +#define JK_METHOD +#define C_LEVEL_TRY_START +#define C_LEVEL_TRY_END +#define C_LEVEL_FINALLY_START +#define C_LEVEL_FINALLY_END +#else +#define JK_METHOD __stdcall +#define C_LEVEL_TRY_START __try { +#define C_LEVEL_TRY_END } +#define C_LEVEL_FINALLY_START __finally { +#define C_LEVEL_FINALLY_END } +#endif +#define PATH_SEPERATOR (';') +#define FILE_SEPERATOR ('\\') +#define PATH_ENV_VARIABLE ("PATH") + + /* incompatible names... */ +#ifndef strcasecmp +#define strcasecmp stricmp +#endif +#else /* defined(WIN32) || defined(NETWARE) */ +#define JK_METHOD +#define C_LEVEL_TRY_START +#define C_LEVEL_TRY_END +#define C_LEVEL_FINALLY_START +#define C_LEVEL_FINALLY_END +#define PATH_SEPERATOR (':') +#define FILE_SEPERATOR ('/') +#define PATH_ENV_VARIABLE ("LD_LIBRARY_PATH") +#endif /* defined(WIN32) || defined(NETWARE) */ + +/* HTTP Error codes + */ + +#define JK_HTTP_OK 200 +#define JK_HTTP_BAD_REQUEST 400 +#define JK_HTTP_UNAUTHORIZED 401 +#define JK_HTTP_REQUEST_TOO_LARGE 413 +#define JK_HTTP_SERVER_ERROR 500 +#define JK_HTTP_NOT_IMPLEMENTED 501 +#define JK_HTTP_BAD_GATEWAY 502 +#define JK_HTTP_SERVER_BUSY 503 +#define JK_HTTP_GATEWAY_TIME_OUT 504 + + +/* + * RECO STATUS + */ + +#define RECO_NONE 0x00 +#define RECO_INITED 0x01 +#define RECO_FILLED 0x02 + +/* + * JK options + */ + +#define JK_OPT_FWDURIMASK 0x0007 + +#define JK_OPT_FWDURICOMPAT 0x0001 +#define JK_OPT_FWDURICOMPATUNPARSED 0x0002 +#define JK_OPT_FWDURIESCAPED 0x0003 +#define JK_OPT_FWDURIPROXY 0x0004 + +#define JK_OPT_FWDURIDEFAULT JK_OPT_FWDURIPROXY + +#define JK_OPT_FWDDIRS 0x0008 +/* Forward local instead remote address */ +#define JK_OPT_FWDLOCAL 0x0010 +#define JK_OPT_FLUSHPACKETS 0x0020 +#define JK_OPT_FLUSHEADER 0x0040 +#define JK_OPT_DISABLEREUSE 0x0080 +#define JK_OPT_FWDCERTCHAIN 0x0100 +#define JK_OPT_FWDKEYSIZE 0x0200 +#define JK_OPT_REJECTUNSAFE 0x0400 + +#define JK_OPT_DEFAULT (JK_OPT_FWDURIDEFAULT | JK_OPT_FWDKEYSIZE) + +/* Check for EBCDIC systems */ + +/* Check for Apache 2.0 running on an EBCDIC system */ +#if APR_CHARSET_EBCDIC + +#include <util_ebcdic.h> + +#define USE_CHARSET_EBCDIC +#define jk_xlate_to_ascii(b, l) ap_xlate_proto_to_ascii(b, l) +#define jk_xlate_from_ascii(b, l) ap_xlate_proto_from_ascii(b, l) + +#else /* APR_CHARSET_EBCDIC */ + +/* Check for Apache 1.3 running on an EBCDIC system */ +#ifdef CHARSET_EBCDIC + +#define USE_CHARSET_EBCDIC +#define jk_xlate_to_ascii(b, l) ebcdic2ascii(b, b, l) +#define jk_xlate_from_ascii(b, l) ascii2ebcdic(b, b, l) + +#else /* CHARSET_EBCDIC */ + +/* We're in on an ASCII system */ + +#define jk_xlate_to_ascii(b, l) /* NOOP */ +#define jk_xlate_from_ascii(b, l) /* NOOP */ + +#endif /* CHARSET_EBCDIC */ + +#endif /* APR_CHARSET_EBCDIC */ + +/* on i5/OS V5R4 HTTP/APR APIs and Datas are in UTF */ +#if defined(AS400_UTF8) +#undef USE_CHARSET_EBCDIC +#define jk_xlate_to_ascii(b, l) /* NOOP */ +#define jk_xlate_from_ascii(b, l) /* NOOP */ +#endif + +/* jk_uint32_t defines a four byte word */ +/* jk_uint64_t defines a eight byte word */ +#if defined (WIN32) + typedef unsigned int jk_uint32_t; +#define JK_UINT32_T_FMT "u" +#define JK_UINT32_T_HEX_FMT "x" + typedef unsigned __int64 jk_uint64_t; +#define JK_UINT64_T_FMT "I64u" +#define JK_UINT64_T_HEX_FMT "I64x" +#define JK_PID_T_FMT "d" +#define JK_PTHREAD_T_FMT "d" +#elif defined(AS400) || defined(NETWARE) + typedef unsigned int jk_uint32_t; +#define JK_UINT32_T_FMT "u" +#define JK_UINT32_T_HEX_FMT "x" + typedef unsigned long long jk_uint64_t; +#define JK_UINT64_T_FMT "llu" +#define JK_UINT64_T_HEX_FMT "llx" +#define JK_PID_T_FMT "d" +#define JK_PTHREAD_T_FMT "d" +#else +#include "jk_types.h" +#endif + +#define JK_UINT32_T_FMT_LEN (sizeof(JK_UINT32_T_FMT) - 1) +#define JK_UINT32_T_HEX_FMT_LEN (sizeof(JK_UINT32_T_HEX_FMT) - 1) +#define JK_UINT64_T_FMT_LEN (sizeof(JK_UINT64_T_FMT) - 1) +#define JK_UINT64_T_HEX_FMT_LEN (sizeof(JK_UINT64_T_HEX_FMT) - 1) + +#ifdef WIN32 +/* For WIN32, emulate gettimeofday() using _ftime() */ +#define gettimeofday(tv, tz) { struct _timeb tb; _ftime(&tb); \ + (tv)->tv_sec = (long)tb.time; \ + (tv)->tv_usec = tb.millitm * 1000; } +#define HAVE_VSNPRINTF +#define HAVE_SNPRINTF +#ifdef HAVE_APR +#define snprintf apr_snprintf +#define vsnprintf apr_vsnprintf +#else +/* define snprint to match windows version */ +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#endif +#endif /* WIN32" */ + +/* Use apr snprintf() and vsnprintf() when needed */ +#if defined(HAVE_APR) +#if !defined(HAVE_SNPRINTF) +#define snprintf apr_snprintf +#endif +#if !defined(HAVE_VSNPRINTF) +#define vsnprintf apr_vsnprintf +#endif +#endif + +/* Use ap snprintf() and vsnprintf() when needed */ +#if !defined(HAVE_APR) +#if !defined(HAVE_SNPRINTF) +#define snprintf ap_snprintf +#endif +#if !defined(HAVE_VSNPRINTF) +#define vsnprintf ap_vsnprintf +#endif +#endif + +#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__)) +typedef SOCKET jk_sock_t; +#define IS_VALID_SOCKET(s) ((s) != INVALID_SOCKET) +#define JK_INVALID_SOCKET INVALID_SOCKET +#else +typedef int jk_sock_t; +#define IS_VALID_SOCKET(s) ((s) > 0) +#define JK_INVALID_SOCKET (-1) +#endif + +#ifdef NETWARE +#ifdef __NOVELL_LIBC__ +#define MAX_PATH 511 +#else +#define MAX_PATH 255 +#endif +#endif + +#ifdef AS400_UTF8 +#define strcasecmp(a,b) apr_strnatcasecmp(a,b) +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* JK_GLOBAL_H */ + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.c new file mode 100644 index 00000000..048f4435 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.c @@ -0,0 +1,1267 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: In process JNI worker * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Based on: * + * Version: $Revision: 750428 $ * + ***************************************************************************/ + +#if !defined(WIN32) && !defined(NETWARE) && !defined(AS400) +#include <dlfcn.h> +#endif + +#include <jni.h> + +#include "jk_pool.h" +#include "jk_jni_worker.h" +#include "jk_util.h" + +#if !defined(JNI_VERSION_1_6) +#if defined LINUX && defined APACHE2_SIGHACK +#include <pthread.h> +#include <signal.h> +#include <bits/signum.h> +#endif + +#ifdef NETWARE +#ifdef __NOVELL_LIBC__ +#include <dlfcn.h> +#else +#include <nwthread.h> +#include <nwadv.h> +#endif +#endif + +#ifndef JNI_VERSION_1_1 +#define JNI_VERSION_1_1 0x00010001 +#endif + +/* probably on an older system that doesn't support RTLD_NOW or RTLD_LAZY. + * The below define is a lie since we are really doing RTLD_LAZY since the + * system doesn't support RTLD_NOW. + */ +#ifndef RTLD_NOW +#define RTLD_NOW 1 +#endif + +#ifndef RTLD_GLOBAL +#define RTLD_GLOBAL 0 +#endif + +#define null_check(e) if ((e) == 0) return JK_FALSE + +jint(JNICALL * jni_get_default_java_vm_init_args) (void *) = NULL; +jint(JNICALL * jni_create_java_vm) (JavaVM **, JNIEnv **, void *) = NULL; +#ifdef AS400 +jint(JNICALL * jni_get_created_java_vms) (JavaVM **, long, long *) = NULL; +#else +jint(JNICALL * jni_get_created_java_vms) (JavaVM **, int, int *) = NULL; +#endif + +#define TC33_JAVA_BRIDGE_CLASS_NAME ("org/apache/tomcat/modules/server/JNIEndpoint") +#define TC32_JAVA_BRIDGE_CLASS_NAME ("org/apache/tomcat/service/JNIEndpoint") + +static jk_worker_t *the_singleton_jni_worker = NULL; + +struct jni_worker +{ + + int was_verified; + int was_initialized; + + jk_pool_t p; + jk_pool_atom_t buf[TINY_POOL_SIZE]; + + /* + * JVM Object pointer. + */ + JavaVM *jvm; + + /* + * [V] JNIEnv used for boostraping from validate -> init w/o an attach + */ + JNIEnv *tmp_env; + + /* + * Web Server to Java bridge, instance and class. + */ + jobject jk_java_bridge_object; + jclass jk_java_bridge_class; + + /* + * Java methods ids, to jump into the JVM + */ + jmethodID jk_startup_method; + jmethodID jk_service_method; + jmethodID jk_shutdown_method; + + /* + * Command line for tomcat startup + */ + char *tomcat_cmd_line; + + /* + * Bridge Type, Tomcat 32/33/40/41/5 + */ + unsigned bridge_type; + + /* + * Classpath + */ + char *tomcat_classpath; + + /* + * Full path to the jni javai/jvm dll + */ + char *jvm_dll_path; + + /* + * Initial Java heap size + */ + unsigned tomcat_ms; + + /* + * Max Java heap size + */ + unsigned tomcat_mx; + + /* + * Java system properties + */ + char **sysprops; + +#ifdef JNI_VERSION_1_2 + /* + * Java 2 initialization options (-X... , -verbose etc.) + */ + char **java2opts; + + /* + * Java 2 lax/strict option checking (bool) + */ + int java2lax; +#endif + + /* + * stdout and stderr file names for Java + */ + char *stdout_name; + char *stderr_name; + + char *name; + jk_worker_t worker; +}; +typedef struct jni_worker jni_worker_t; + +struct jni_endpoint +{ + int attached; + JNIEnv *env; + jni_worker_t *worker; + + jk_endpoint_t endpoint; +}; +typedef struct jni_endpoint jni_endpoint_t; + + +static int load_jvm_dll(jni_worker_t * p, jk_logger_t *l); + +static int open_jvm(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l); + +static int open_jvm1(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l); + +#ifdef JNI_VERSION_1_2 +static int detect_jvm_version(jk_logger_t *l); + +static int open_jvm2(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l); +#endif + + +static int get_bridge_object(jni_worker_t * p, JNIEnv * env, jk_logger_t *l); + +static int get_method_ids(jni_worker_t * p, JNIEnv * env, jk_logger_t *l); + +static JNIEnv *attach_to_jvm(jni_worker_t * p, jk_logger_t *l); + +static void detach_from_jvm(jni_worker_t * p, jk_logger_t *l); + + +/* + Duplicate string and convert it to ASCII on EBDIC based systems + Needed for at least AS/400 (before V5R4 ?) and BS2000 but what about other EBDIC systems ? +*/ +static void *strdup_ascii(jk_pool_t *p, char *s) +{ + char *rc; + rc = jk_pool_strdup(p, s); + +#if defined(AS400) || defined(_OSD_POSIX) + jk_xlate_to_ascii(rc, strlen(rc)); +#endif + + return rc; +} + +#if defined LINUX && defined APACHE2_SIGHACK +static void linux_signal_hack() +{ + sigset_t newM; + sigset_t old; + + sigemptyset(&newM); + pthread_sigmask(SIG_SETMASK, &newM, &old); + + sigdelset(&old, SIGUSR1); + sigdelset(&old, SIGUSR2); + sigdelset(&old, SIGUNUSED); + sigdelset(&old, SIGRTMIN); + sigdelset(&old, SIGRTMIN + 1); + sigdelset(&old, SIGRTMIN + 2); + pthread_sigmask(SIG_SETMASK, &old, NULL); +} + +static void print_signals(sigset_t * sset) +{ + int sig; + for (sig = 1; sig < 20; sig++) { + if (sigismember(sset, sig)) { + printf(" %d", sig); + } + } + printf("\n"); +} +#endif + +/* + * Return values of service() method for jni worker: + * return value is_error reason + * JK_FALSE JK_HTTP_SERVER_ERROR Invalid parameters (null values) + * Error during attach to the JNI backend + * Error during JNI call + * JK_TRUE JK_HTTP_OK All other cases + */ +static int JK_METHOD service(jk_endpoint_t *e, + jk_ws_service_t *s, + jk_logger_t *l, int *is_error) +{ + jni_endpoint_t *p; + jint rc; + + JK_TRACE_ENTER(l); + + if (!e || !e->endpoint_private || !s || !is_error) { + JK_LOG_NULL_PARAMS(l); + if (is_error) + *is_error = JK_HTTP_SERVER_ERROR; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p = e->endpoint_private; + + /* Set returned error to OK */ + *is_error = JK_HTTP_OK; + + if (!p->attached) { + /* Try to attach */ + if (!(p->env = attach_to_jvm(p->worker, l))) { + jk_log(l, JK_LOG_EMERG, "Attach failed"); + *is_error = JK_HTTP_SERVER_ERROR; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + p->attached = JK_TRUE; + } + + /* we are attached now */ + + /* + * When we call the JVM we cannot know what happens + * So we can not recover !!! + */ + jk_log(l, JK_LOG_DEBUG, "In service, calling Tomcat..."); + + rc = (*(p->env))->CallIntMethod(p->env, + p->worker->jk_java_bridge_object, + p->worker->jk_service_method, + /* [V] For some reason gcc likes this pointer -> int -> jlong conversion, */ + /* but not the direct pointer -> jlong conversion. I hope it's okay. */ +#ifdef AS400 + s, l +#else + (jlong) (int)s, (jlong) (int)l +#endif + ); + + /* [V] Righ now JNIEndpoint::service() only returns 1 or 0 */ + if (rc) { + jk_log(l, JK_LOG_DEBUG, "Tomcat returned OK, done"); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + else { + jk_log(l, JK_LOG_ERROR, "Tomcat FAILED!"); + *is_error = JK_HTTP_SERVER_ERROR; + JK_TRACE_EXIT(l); + return JK_FALSE; + } +} + +static int JK_METHOD done(jk_endpoint_t **e, jk_logger_t *l) +{ + jni_endpoint_t *p; + + JK_TRACE_ENTER(l); + if (!e || !*e || !(*e)->endpoint_private) { + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p = (*e)->endpoint_private; + + if (p->attached) { + detach_from_jvm(p->worker, l); + } + + free(p); + *e = NULL; + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +static int JK_METHOD validate(jk_worker_t *pThis, + jk_map_t *props, + jk_worker_env_t *we, jk_logger_t *l) +{ + jni_worker_t *p; + int mem_config = 0; + int btype = 0; + const char *str_config = NULL; + JNIEnv *env; + + JK_TRACE_ENTER(l); + + if (!pThis || !pThis->worker_private) { + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p = pThis->worker_private; + + if (p->was_verified) { + jk_log(l, JK_LOG_DEBUG, "been here before, done"); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + + if (jk_get_worker_mx(props, p->name, (unsigned int *)&mem_config)) { + p->tomcat_mx = mem_config; + } + + if (jk_get_worker_ms(props, p->name, (unsigned int *)&mem_config)) { + p->tomcat_ms = mem_config; + } + + if (jk_get_worker_classpath(props, p->name, &str_config)) { + p->tomcat_classpath = jk_pool_strdup(&p->p, str_config); + } + + if (!p->tomcat_classpath) { + jk_log(l, JK_LOG_EMERG, "no classpath"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (jk_get_worker_bridge_type(props, p->name, (unsigned int *)&btype)) { + p->bridge_type = btype; + } + + if (jk_get_worker_jvm_path(props, p->name, &str_config)) { + p->jvm_dll_path = jk_pool_strdup(&p->p, str_config); + } + + if (!p->jvm_dll_path || !jk_file_exists(p->jvm_dll_path)) { + jk_log(l, JK_LOG_EMERG, "no jvm_dll_path"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (jk_get_worker_cmd_line(props, p->name, &str_config)) { + p->tomcat_cmd_line = jk_pool_strdup(&p->p, str_config); + } + + if (jk_get_worker_stdout(props, p->name, &str_config)) { + p->stdout_name = jk_pool_strdup(&p->p, str_config); + } + + if (jk_get_worker_stderr(props, p->name, &str_config)) { + p->stderr_name = jk_pool_strdup(&p->p, str_config); + } + + if (jk_get_worker_sysprops(props, p->name, &str_config)) { + p->sysprops = jk_parse_sysprops(&p->p, str_config); + } + +#ifdef JNI_VERSION_1_2 + if (jk_get_worker_str_prop(props, p->name, "java2opts", &str_config)) { + /* jk_log(l, JK_LOG_DEBUG, "Got opts: %s", str_config); */ + p->java2opts = jk_parse_sysprops(&p->p, str_config); + } + if (jk_get_worker_int_prop(props, p->name, "java2lax", &mem_config)) { + p->java2lax = mem_config ? JK_TRUE : JK_FALSE; + } +#endif + + if (jk_get_worker_libpath(props, p->name, &str_config)) { + jk_append_libpath(&p->p, str_config); + } + + if (!load_jvm_dll(p, l)) { + jk_log(l, JK_LOG_EMERG, "can't load jvm dll"); + /* [V] no detach needed here */ + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (!open_jvm(p, &env, l)) { + jk_log(l, JK_LOG_EMERG, "can't open jvm"); + /* [V] no detach needed here */ + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (!get_bridge_object(p, env, l)) { + jk_log(l, JK_LOG_EMERG, "can't get bridge object"); + /* [V] the detach here may segfault on 1.1 JVM... */ + detach_from_jvm(p, l); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (!get_method_ids(p, env, l)) { + jk_log(l, JK_LOG_EMERG, "can't get method ids"); + /* [V] the detach here may segfault on 1.1 JVM... */ + detach_from_jvm(p, l); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p->was_verified = JK_TRUE; + p->tmp_env = env; + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +static int JK_METHOD init(jk_worker_t *pThis, + jk_map_t *props, + jk_worker_env_t *we, jk_logger_t *l) +{ + jni_worker_t *p; + JNIEnv *env; + + JK_TRACE_ENTER(l); + + if (!pThis || !pThis->worker_private) { + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p = pThis->worker_private; + + if (p->was_initialized) { + jk_log(l, JK_LOG_DEBUG, "done (been here!)"); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + + if (!p->jvm || + !p->jk_java_bridge_object || + !p->jk_service_method || + !p->jk_startup_method || !p->jk_shutdown_method) { + jk_log(l, JK_LOG_EMERG, "worker not set completely"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + /* [V] init is called from the same thread that called validate */ + /* there is no need to attach to the JVM, just get the env */ + + /* if(env = attach_to_jvm(p,l)) { */ + if ((env = p->tmp_env)) { + jstring cmd_line = (jstring) NULL; + jstring stdout_name = (jstring) NULL; + jstring stderr_name = (jstring) NULL; + jint rc = 0; + + /* AS400/BS2000 need EBCDIC to ASCII conversion for JNI */ + + if (p->tomcat_cmd_line) { + cmd_line = + (*env)->NewStringUTF(env, + strdup_ascii(&p->p, p->tomcat_cmd_line)); + } + if (p->stdout_name) { + stdout_name = + (*env)->NewStringUTF(env, + strdup_ascii(&p->p, p->stdout_name)); + } + if (p->stderr_name) { + stderr_name = + (*env)->NewStringUTF(env, + strdup_ascii(&p->p, p->stderr_name)); + } + + jk_log(l, JK_LOG_DEBUG, + "calling Tomcat to intialize itself..."); + rc = (*env)->CallIntMethod(env, p->jk_java_bridge_object, + p->jk_startup_method, cmd_line, + stdout_name, stderr_name); + + detach_from_jvm(p, l); + + if (rc) { + p->was_initialized = JK_TRUE; + jk_log(l, JK_LOG_DEBUG, "Tomcat initialized OK, done"); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + else { + jk_log(l, JK_LOG_EMERG, "could not initialize Tomcat"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + else { + jk_log(l, JK_LOG_ERROR, + "In init, FIXME: init didn't gen env from validate!"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } +} + +static int JK_METHOD get_endpoint(jk_worker_t *pThis, + jk_endpoint_t **pend, jk_logger_t *l) +{ + /* [V] This slow, needs replacement */ + jni_endpoint_t *p; + + JK_TRACE_ENTER(l); + + if (!pThis || !pThis->worker_private || !pend) { + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p = (jni_endpoint_t *) calloc(1, sizeof(jni_endpoint_t)); + if (p) { + p->attached = JK_FALSE; + p->env = NULL; + p->worker = pThis->worker_private; + p->endpoint.endpoint_private = p; + p->endpoint.service = service; + p->endpoint.done = done; + *pend = &p->endpoint; + + JK_TRACE_EXIT(l); + return JK_TRUE; + } + else { + jk_log(l, JK_LOG_ERROR, + "could not allocate endpoint"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } +} + +static int JK_METHOD destroy(jk_worker_t **pThis, jk_logger_t *l) +{ + jni_worker_t *p; + JNIEnv *env; + + JK_TRACE_ENTER(l); + + if (!pThis || !*pThis || !(*pThis)->worker_private) { + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p = (*pThis)->worker_private; + + if (!p->jvm) { + jk_log(l, JK_LOG_DEBUG, "JVM not intantiated"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (!p->jk_java_bridge_object || !p->jk_shutdown_method) { + jk_log(l, JK_LOG_DEBUG, "Tomcat not intantiated"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if ((env = attach_to_jvm(p, l))) { + jk_log(l, JK_LOG_DEBUG, "shutting down Tomcat..."); + (*env)->CallVoidMethod(env, + p->jk_java_bridge_object, + p->jk_shutdown_method); + detach_from_jvm(p, l); + } + + jk_close_pool(&p->p); + free(p); + + jk_log(l, JK_LOG_DEBUG, "destroyed"); + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +int JK_METHOD jni_worker_factory(jk_worker_t **w, + const char *name, jk_logger_t *l) +{ + jni_worker_t *private_data; + + JK_TRACE_ENTER(l); + + jk_log(l, JK_LOG_WARNING, + "Worker '%s' is of type jni, which is deprecated " + "and will be removed in a future release.", + name ? name : "(null)"); + + if (!name || !w) { + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return 0; + } + + if (the_singleton_jni_worker) { + jk_log(l, JK_LOG_DEBUG, + "instance already created"); + *w = the_singleton_jni_worker; + JK_TRACE_EXIT(l); + return JK_JNI_WORKER_TYPE; + } + + private_data = (jni_worker_t *) malloc(sizeof(jni_worker_t)); + + if (!private_data) { + jk_log(l, JK_LOG_ERROR, + "memory allocation error"); + JK_TRACE_EXIT(l); + return 0; + } + + jk_open_pool(&private_data->p, + private_data->buf, sizeof(jk_pool_atom_t) * TINY_POOL_SIZE); + + private_data->name = jk_pool_strdup(&private_data->p, name); + + if (!private_data->name) { + jk_log(l, JK_LOG_ERROR, + "memory allocation error"); + jk_close_pool(&private_data->p); + free(private_data); + JK_TRACE_EXIT(l); + return 0; + } + + private_data->was_verified = JK_FALSE; + private_data->was_initialized = JK_FALSE; + private_data->jvm = NULL; + private_data->tmp_env = NULL; + private_data->jk_java_bridge_object = (jobject) NULL; + private_data->jk_java_bridge_class = (jclass) NULL; + private_data->jk_startup_method = (jmethodID) NULL; + private_data->jk_service_method = (jmethodID) NULL; + private_data->jk_shutdown_method = (jmethodID) NULL; + private_data->tomcat_cmd_line = NULL; + private_data->tomcat_classpath = NULL; + private_data->bridge_type = TC33_BRIDGE_TYPE; + private_data->jvm_dll_path = NULL; + private_data->tomcat_ms = 0; + private_data->tomcat_mx = 0; + private_data->sysprops = NULL; +#ifdef JNI_VERSION_1_2 + private_data->java2opts = NULL; + private_data->java2lax = JK_TRUE; +#endif + private_data->stdout_name = NULL; + private_data->stderr_name = NULL; + + private_data->worker.worker_private = private_data; + private_data->worker.validate = validate; + private_data->worker.init = init; + private_data->worker.get_endpoint = get_endpoint; + private_data->worker.destroy = destroy; + + *w = &private_data->worker; + the_singleton_jni_worker = &private_data->worker; + + JK_TRACE_EXIT(l); + return JK_JNI_WORKER_TYPE; +} + +static int load_jvm_dll(jni_worker_t * p, jk_logger_t *l) +{ +#ifdef WIN32 + HINSTANCE hInst = LoadLibrary(p->jvm_dll_path); + if (hInst) { + (FARPROC) jni_create_java_vm = + GetProcAddress(hInst, "JNI_CreateJavaVM"); + + (FARPROC) jni_get_created_java_vms = + GetProcAddress(hInst, "JNI_GetCreatedJavaVMs"); + + (FARPROC) jni_get_default_java_vm_init_args = + GetProcAddress(hInst, "JNI_GetDefaultJavaVMInitArgs"); + + jk_log(l, JK_LOG_DEBUG, "Loaded all JNI procs"); + + if (jni_create_java_vm && jni_get_default_java_vm_init_args + && jni_get_created_java_vms) { + return JK_TRUE; + } + + FreeLibrary(hInst); + } +#elif defined(NETWARE) && !defined(__NOVELL_LIBC__) + int javaNlmHandle = FindNLMHandle("JVM"); + if (0 == javaNlmHandle) { + /* if we didn't get a handle, try to load java and retry getting the */ + /* handle */ + spawnlp(P_NOWAIT, "JVM.NLM", NULL); + ThreadSwitchWithDelay(); + javaNlmHandle = FindNLMHandle("JVM"); + if (0 == javaNlmHandle) + printf("Error loading Java."); + + } + if (0 != javaNlmHandle) { + jni_create_java_vm = ImportSymbol(GetNLMHandle(), "JNI_CreateJavaVM"); + jni_get_created_java_vms = + ImportSymbol(GetNLMHandle(), "JNI_GetCreatedJavaVMs"); + jni_get_default_java_vm_init_args = + ImportSymbol(GetNLMHandle(), "JNI_GetDefaultJavaVMInitArgs"); + } + if (jni_create_java_vm && jni_get_default_java_vm_init_args + && jni_get_created_java_vms) { + return JK_TRUE; + } +#elif defined(AS400) + jk_log(l, JK_LOG_DEBUG, + "Direct reference to JNI entry points (no SRVPGM)"); + jni_create_java_vm = &JNI_CreateJavaVM; + jni_get_default_java_vm_init_args = &JNI_GetDefaultJavaVMInitArgs; + jni_get_created_java_vms = &JNI_GetCreatedJavaVMs; +#else + void *handle; + jk_log(l, JK_LOG_DEBUG, "loading JVM %s", p->jvm_dll_path); + + handle = dlopen(p->jvm_dll_path, RTLD_NOW | RTLD_GLOBAL); + + if (!handle) { + jk_log(l, JK_LOG_EMERG, + "Can't load native library %s : %s", p->jvm_dll_path, + dlerror()); + } + else { + jni_create_java_vm = dlsym(handle, "JNI_CreateJavaVM"); + jni_get_default_java_vm_init_args = + dlsym(handle, "JNI_GetDefaultJavaVMInitArgs"); + jni_get_created_java_vms = dlsym(handle, "JNI_GetCreatedJavaVMs"); + + if (jni_create_java_vm && jni_get_default_java_vm_init_args && + jni_get_created_java_vms) { + jk_log(l, JK_LOG_DEBUG, + "In load_jvm_dll, symbols resolved, done"); + return JK_TRUE; + } + jk_log(l, JK_LOG_EMERG, + "Can't resolve JNI_CreateJavaVM or JNI_GetDefaultJavaVMInitArgs"); + dlclose(handle); + } +#endif + return JK_FALSE; +} + +static int open_jvm(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l) +{ +#ifdef JNI_VERSION_1_2 + int jvm_version = detect_jvm_version(l); + + switch (jvm_version) { + case JNI_VERSION_1_1: + return open_jvm1(p, env, l); + case JNI_VERSION_1_2: + return open_jvm2(p, env, l); + default: + return JK_FALSE; + } +#else + /* [V] Make sure this is _really_ visible */ +#warning ------------------------------------------------------- +#warning NO JAVA 2 HEADERS! SUPPORT FOR JAVA 2 FEATURES DISABLED +#warning ------------------------------------------------------- + return open_jvm1(p, env, l); +#endif +} + +static int open_jvm1(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l) +{ + JDK1_1InitArgs vm_args; + JNIEnv *penv; + int err; + *env = NULL; + + JK_TRACE_ENTER(l); + + vm_args.version = JNI_VERSION_1_1; + + if (0 != jni_get_default_java_vm_init_args(&vm_args)) { + jk_log(l, JK_LOG_EMERG, "can't get default vm init args"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + jk_log(l, JK_LOG_DEBUG, "got default jvm args"); + + if (vm_args.classpath) { + size_t len = strlen(vm_args.classpath) + + strlen(p->tomcat_classpath) + 3; + char *tmp = jk_pool_alloc(&p->p, len); + if (tmp) { + sprintf(tmp, "%s%c%s", + strdup_ascii(&p->p, p->tomcat_classpath), + PATH_SEPERATOR, vm_args.classpath); + p->tomcat_classpath = tmp; + } + else { + jk_log(l, JK_LOG_EMERG, + "allocation error for classpath"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + vm_args.classpath = p->tomcat_classpath; + + if (p->tomcat_mx) { + vm_args.maxHeapSize = p->tomcat_mx; + } + + if (p->tomcat_ms) { + vm_args.minHeapSize = p->tomcat_ms; + } + + if (p->sysprops) { + /* No EBCDIC to ASCII conversion here for AS/400 - later */ + vm_args.properties = p->sysprops; + } + + jk_log(l, JK_LOG_DEBUG, "In open_jvm1, about to create JVM..."); + if ((err = jni_create_java_vm(&(p->jvm), &penv, &vm_args)) != 0) { + jk_log(l, JK_LOG_EMERG, + "could not create JVM, code: %d ", err); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + jk_log(l, JK_LOG_DEBUG, "JVM created, done"); + + *env = penv; + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +#ifdef JNI_VERSION_1_2 +static int detect_jvm_version(jk_logger_t *l) +{ + JNIEnv *env = NULL; + JDK1_1InitArgs vm_args; + + JK_TRACE_ENTER(l); + + /* [V] Idea: ask for 1.2. If the JVM is 1.1 it will return 1.1 instead */ + /* Note: asking for 1.1 won't work, 'cause 1.2 JVMs will return 1.1 */ + vm_args.version = JNI_VERSION_1_2; + + if (0 != jni_get_default_java_vm_init_args(&vm_args)) { + jk_log(l, JK_LOG_EMERG, "can't get default vm init args"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + jk_log(l, JK_LOG_DEBUG, + "found version: %X, done", vm_args.version); + + JK_TRACE_EXIT(l); + return vm_args.version; +} + +static char *build_opt_str(jk_pool_t *p, + char *opt_name, char *opt_value, jk_logger_t *l) +{ + size_t len = strlen(opt_name) + strlen(opt_value) + 2; + + /* [V] IMHO, these should not be deallocated as long as the JVM runs */ + char *tmp = jk_pool_alloc(p, len); + + if (tmp) { + sprintf(tmp, "%s%s", opt_name, opt_value); + return tmp; + } + else { + jk_log(l, JK_LOG_EMERG, + "allocation error for %s", opt_name); + return NULL; + } +} + +static char *build_opt_int(jk_pool_t *p, + char *opt_name, int opt_value, jk_logger_t *l) +{ + /* [V] this should suffice even for 64-bit int */ + size_t len = strlen(opt_name) + 20 + 2; + /* [V] IMHO, these should not be deallocated as long as the JVM runs */ + char *tmp = jk_pool_alloc(p, len); + + if (tmp) { + sprintf(tmp, "%s%d", opt_name, opt_value); + return tmp; + } + else { + jk_log(l, JK_LOG_EMERG, + "allocation error for %s", opt_name); + return NULL; + } +} + +static int open_jvm2(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l) +{ + JavaVMInitArgs vm_args; + JNIEnv *penv = NULL; + JavaVMOption options[100]; + int optn = 0, err; + char *tmp; + + *env = NULL; + + JK_TRACE_ENTER(l); + + vm_args.version = JNI_VERSION_1_2; + vm_args.options = options; + +/* AS/400 need EBCDIC to ASCII conversion to parameters passed to JNI */ +/* No conversion for ASCII based systems (what about BS2000 ?) */ + + if (p->tomcat_classpath) { + jk_log(l, JK_LOG_DEBUG, "setting classpath to %s", + p->tomcat_classpath); + tmp = + build_opt_str(&p->p, "-Djava.class.path=", p->tomcat_classpath, + l); + null_check(tmp); + options[optn++].optionString = strdup_ascii(&p->p, tmp); + } + + if (p->tomcat_mx) { + jk_log(l, JK_LOG_DEBUG, "setting max heap to %d", + p->tomcat_mx); + tmp = build_opt_int(&p->p, "-Xmx", p->tomcat_mx, l); + null_check(tmp); + options[optn++].optionString = strdup_ascii(&p->p, tmp); + } + + if (p->tomcat_ms) { + jk_log(l, JK_LOG_DEBUG, "setting start heap to %d", + p->tomcat_ms); + tmp = build_opt_int(&p->p, "-Xms", p->tomcat_ms, l); + null_check(tmp); + options[optn++].optionString = strdup_ascii(&p->p, tmp); + } + + if (p->sysprops) { + int i = 0; + while (p->sysprops[i]) { + jk_log(l, JK_LOG_DEBUG, "setting %s", + p->sysprops[i]); + tmp = build_opt_str(&p->p, "-D", p->sysprops[i], l); + null_check(tmp); + options[optn++].optionString = strdup_ascii(&p->p, tmp); + i++; + } + } + + if (p->java2opts) { + int i = 0; + + while (p->java2opts[i]) { + jk_log(l, JK_LOG_DEBUG, "using option: %s", + p->java2opts[i]); + /* Pass it "as is" */ + options[optn++].optionString = + strdup_ascii(&p->p, p->java2opts[i++]); + } + } + + vm_args.nOptions = optn; + + if (p->java2lax) { + jk_log(l, JK_LOG_DEBUG, + "the JVM will ignore unknown options"); + vm_args.ignoreUnrecognized = JNI_TRUE; + } + else { + jk_log(l, JK_LOG_DEBUG, + "the JVM will FAIL if it finds unknown options"); + vm_args.ignoreUnrecognized = JNI_FALSE; + } + + jk_log(l, JK_LOG_DEBUG, "about to create JVM..."); + + err = jni_create_java_vm(&(p->jvm), &penv, &vm_args); + + if (JNI_EEXIST == err) { +#ifdef AS400 + long vmCount; +#else + int vmCount; +#endif + jk_log(l, JK_LOG_DEBUG, "JVM alread instantiated." + "Trying to attach instead."); + + jni_get_created_java_vms(&(p->jvm), 1, &vmCount); + if (NULL != p->jvm) + penv = attach_to_jvm(p, l); + + if (NULL != penv) + err = 0; + } + + if (err != 0) { + jk_log(l, JK_LOG_EMERG, "Fail-> could not create JVM, code: %d ", + err); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + *env = penv; + jk_log(l, JK_LOG_DEBUG, "JVM created"); + + JK_TRACE_EXIT(l); + return JK_TRUE; +} +#endif + +static int get_bridge_object(jni_worker_t * p, JNIEnv * env, jk_logger_t *l) +{ + char *btype; + char *ctype; + + jmethodID constructor_method_id; + + JK_TRACE_ENTER(l); + + switch (p->bridge_type) { + case TC32_BRIDGE_TYPE: + btype = TC32_JAVA_BRIDGE_CLASS_NAME; + break; + + case TC33_BRIDGE_TYPE: + btype = TC33_JAVA_BRIDGE_CLASS_NAME; + break; + + case TC40_BRIDGE_TYPE: + case TC41_BRIDGE_TYPE: + case TC50_BRIDGE_TYPE: + jk_log(l, JK_LOG_EMERG, "Bridge type %d not supported", + p->bridge_type); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + +/* AS400/BS2000 need conversion from EBCDIC to ASCII before passing to JNI */ +/* for others, strdup_ascii is just jk_pool_strdup */ + + ctype = strdup_ascii(&p->p, btype); + + p->jk_java_bridge_class = (*env)->FindClass(env, ctype); + + if (!p->jk_java_bridge_class) { + jk_log(l, JK_LOG_EMERG, "Can't find class %s", btype); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + jk_log(l, JK_LOG_DEBUG, + "In get_bridge_object, loaded %s bridge class", btype); + + constructor_method_id = (*env)->GetMethodID(env, p->jk_java_bridge_class, strdup_ascii(&p->p, "<init>"), /* method name */ + strdup_ascii(&p->p, "()V")); /* method sign */ + + if (!constructor_method_id) { + p->jk_java_bridge_class = (jclass) NULL; + jk_log(l, JK_LOG_EMERG, "Can't find constructor"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p->jk_java_bridge_object = (*env)->NewObject(env, + p->jk_java_bridge_class, + constructor_method_id); + if (!p->jk_java_bridge_object) { + p->jk_java_bridge_class = (jclass) NULL; + jk_log(l, JK_LOG_EMERG, "Can't create new bridge object"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p->jk_java_bridge_object = + (jobject) (*env)->NewGlobalRef(env, p->jk_java_bridge_object); + if (!p->jk_java_bridge_object) { + jk_log(l, JK_LOG_EMERG, "Can't create global ref to bridge object"); + p->jk_java_bridge_class = (jclass) NULL; + p->jk_java_bridge_object = (jobject) NULL; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +static int get_method_ids(jni_worker_t * p, JNIEnv * env, jk_logger_t *l) +{ + +/* AS400/BS2000 need conversion from EBCDIC to ASCII before passing to JNI */ + + p->jk_startup_method = (*env)->GetMethodID(env, + p->jk_java_bridge_class, + strdup_ascii(&p->p, "startup"), + strdup_ascii(&p->p, + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I")); + + if (!p->jk_startup_method) { + jk_log(l, JK_LOG_EMERG, "Can't find startup()"); + return JK_FALSE; + } + + p->jk_service_method = (*env)->GetMethodID(env, + p->jk_java_bridge_class, + strdup_ascii(&p->p, "service"), + strdup_ascii(&p->p, "(JJ)I")); + + if (!p->jk_service_method) { + jk_log(l, JK_LOG_EMERG, "Can't find service()"); + return JK_FALSE; + } + + p->jk_shutdown_method = (*env)->GetMethodID(env, + p->jk_java_bridge_class, + strdup_ascii(&p->p, + "shutdown"), + strdup_ascii(&p->p, "()V")); + + if (!p->jk_shutdown_method) { + jk_log(l, JK_LOG_EMERG, "Can't find shutdown()"); + return JK_FALSE; + } + + return JK_TRUE; +} + +static JNIEnv *attach_to_jvm(jni_worker_t * p, jk_logger_t *l) +{ + JNIEnv *rc = NULL; + /* [V] This message is important. If there are signal mask issues, * + * the JVM usually hangs when a new thread tries to attach to it */ + JK_TRACE_ENTER(l); + +#if defined LINUX && defined APACHE2_SIGHACK + linux_signal_hack(); +#endif + + if (0 == (*(p->jvm))->AttachCurrentThread(p->jvm, +#ifdef JNI_VERSION_1_2 + (void **) +#endif + &rc, NULL)) { + jk_log(l, JK_LOG_DEBUG, "In attach_to_jvm, attached ok"); + JK_TRACE_EXIT(l); + return rc; + } + jk_log(l, JK_LOG_ERROR, + "In attach_to_jvm, cannot attach thread to JVM."); + JK_TRACE_EXIT(l); + return NULL; +} + +/* +static JNIEnv *attach_to_jvm(jni_worker_t *p) +{ + JNIEnv *rc = NULL; + +#ifdef LINUX + linux_signal_hack(); +#endif + + if(0 == (*(p->jvm))->AttachCurrentThread(p->jvm, +#ifdef JNI_VERSION_1_2 + (void **) +#endif + &rc, + NULL)) { + return rc; + } + + return NULL; +} +*/ +static void detach_from_jvm(jni_worker_t * p, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + if (!p->jvm || !(*(p->jvm))) { + jk_log(l, JK_LOG_ERROR, + "cannot detach from NULL JVM."); + } + + if (0 == (*(p->jvm))->DetachCurrentThread(p->jvm)) { + jk_log(l, JK_LOG_DEBUG, "detached ok"); + } + else { + jk_log(l, JK_LOG_ERROR, + "cannot detach from JVM."); + } + JK_TRACE_EXIT(l); +} +#else +int JK_METHOD jni_worker_factory(jk_worker_t **w, + const char *name, jk_logger_t *l) +{ + jk_log(l, JK_LOG_WARNING, + "Worker '%s' is of type jni, which is deprecated " + "and will be removed in a future release.", + name ? name : "(null)"); + if (w) + *w = NULL; + return 0; +} +#endif /* JNI_VERSION_1_6 */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.h new file mode 100644 index 00000000..0adef2ab --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.h @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: jni worker header file * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Version: $Revision: 466585 $ * + ***************************************************************************/ + +#ifndef JK_JNI_WORKER_H +#define JK_JNI_WORKER_H + +#include "jk_logger.h" +#include "jk_service.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#define JK_JNI_WORKER_NAME ("jni") +#define JK_JNI_WORKER_TYPE (4) + +int JK_METHOD jni_worker_factory(jk_worker_t **w, + const char *name, jk_logger_t *l); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* JK_JNI_WORKER_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.lo b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.lo new file mode 100644 index 00000000..b3a8ed60 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.lo @@ -0,0 +1,12 @@ +# jk_jni_worker.lo - a libtool object file +# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/jk_jni_worker.o' + +# Name of the non-PIC object. +non_pic_object='jk_jni_worker.o' + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.o Binary files differnew file mode 100644 index 00000000..9f00e3e5 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_lb_worker.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_lb_worker.c new file mode 100644 index 00000000..3c0ce67a --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_lb_worker.c @@ -0,0 +1,1823 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Load balancer worker, knows how to load balance among * + * several workers. * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Author: Mladen Turk <mturk@apache.org> * + * Author: Rainer Jung <rjung@apache.org> * + * Based on: * + * Version: $Revision: 1137200 $ * + ***************************************************************************/ + +#include "jk_pool.h" +#include "jk_service.h" +#include "jk_util.h" +#include "jk_worker.h" +#include "jk_lb_worker.h" +#include "jk_ajp13.h" +#include "jk_ajp13_worker.h" +#include "jk_ajp14_worker.h" +#include "jk_mt.h" +#include "jk_shm.h" + +/* + * The load balancing code in this + */ + +/* + * The following two macros need to be kept in sync with + * the existing values for state and activation. + * Note: state <= JK_LB_STATE_FORCE is equivalent to + * state is none of JK_LB_STATE_BUSY, JK_LB_STATE_ERROR, JK_LB_STATE_PROBE + * Note: state <= JK_LB_STATE_BUSY is equivalent to + * state is none of JK_LB_STATE_ERROR, JK_LB_STATE_PROBE + * Note: activation == JK_LB_ACTIVATION_ACTIVE is equivalent to + * activation is none of JK_LB_ACTIVATION_STOPPED, JK_LB_ACTIVATION_DISABLED + */ +#define JK_WORKER_USABLE(s, activation) ((s) <= JK_LB_STATE_FORCE && activation == JK_LB_ACTIVATION_ACTIVE) +#define JK_WORKER_USABLE_STICKY(s, activation) ((s) <= JK_LB_STATE_BUSY && activation != JK_LB_ACTIVATION_STOPPED) + +static const char *lb_locking_type[] = { + JK_LB_LOCK_TEXT_OPTIMISTIC, + JK_LB_LOCK_TEXT_PESSIMISTIC, + "unknown", + NULL +}; + +static const char *lb_method_type[] = { + JK_LB_METHOD_TEXT_REQUESTS, + JK_LB_METHOD_TEXT_TRAFFIC, + JK_LB_METHOD_TEXT_BUSYNESS, + JK_LB_METHOD_TEXT_SESSIONS, + "unknown", + NULL +}; + +static const char *lb_state_type[] = { + JK_LB_STATE_TEXT_IDLE, + JK_LB_STATE_TEXT_OK, + JK_LB_STATE_TEXT_RECOVER, + JK_LB_STATE_TEXT_FORCE, + JK_LB_STATE_TEXT_BUSY, + JK_LB_STATE_TEXT_ERROR, + JK_LB_STATE_TEXT_PROBE, + "unknown", + NULL +}; + +static const char *lb_activation_type[] = { + JK_LB_ACTIVATION_TEXT_ACTIVE, + JK_LB_ACTIVATION_TEXT_DISABLED, + JK_LB_ACTIVATION_TEXT_STOPPED, + "unknown", + NULL +}; + +static const char *lb_first_log_names[] = { + JK_NOTE_LB_FIRST_NAME, + JK_NOTE_LB_FIRST_VALUE, + JK_NOTE_LB_FIRST_ACCESSED, + JK_NOTE_LB_FIRST_READ, + JK_NOTE_LB_FIRST_TRANSFERRED, + JK_NOTE_LB_FIRST_ERRORS, + JK_NOTE_LB_FIRST_BUSY, + JK_NOTE_LB_FIRST_ACTIVATION, + JK_NOTE_LB_FIRST_STATE, + NULL +}; + +static const char *lb_last_log_names[] = { + JK_NOTE_LB_LAST_NAME, + JK_NOTE_LB_LAST_VALUE, + JK_NOTE_LB_LAST_ACCESSED, + JK_NOTE_LB_LAST_READ, + JK_NOTE_LB_LAST_TRANSFERRED, + JK_NOTE_LB_LAST_ERRORS, + JK_NOTE_LB_LAST_BUSY, + JK_NOTE_LB_LAST_ACTIVATION, + JK_NOTE_LB_LAST_STATE, + NULL +}; + +struct lb_endpoint +{ + lb_worker_t *worker; + jk_endpoint_t endpoint; + int *states; +}; +typedef struct lb_endpoint lb_endpoint_t; + + +/* Calculate the greatest common divisor of two positive integers */ +static jk_uint64_t gcd(jk_uint64_t a, jk_uint64_t b) +{ + jk_uint64_t r; + if (b > a) { + r = a; + a = b; + b = r; + } + while (b > 0) { + r = a % b; + a = b; + b = r; + } + return a; +} + +/* Calculate the smallest common multiple of two positive integers */ +static jk_uint64_t scm(jk_uint64_t a, jk_uint64_t b) +{ + return a * b / gcd(a, b); +} + +/* Return the string representation of the lb lock type */ +const char *jk_lb_get_lock(lb_worker_t *p, jk_logger_t *l) +{ + return lb_locking_type[p->lblock]; +} + +/* Return the int representation of the lb lock type */ +int jk_lb_get_lock_code(const char *v) +{ + if (!v) + return JK_LB_LOCK_DEF; + else if (*v == 'o' || *v == 'O' || *v == '0') + return JK_LB_LOCK_OPTIMISTIC; + else if (*v == 'p' || *v == 'P' || *v == '1') + return JK_LB_LOCK_PESSIMISTIC; + else + return JK_LB_LOCK_DEF; +} + +/* Return the string representation of the lb method type */ +const char *jk_lb_get_method(lb_worker_t *p, jk_logger_t *l) +{ + return lb_method_type[p->lbmethod]; +} + +/* Return the int representation of the lb method type */ +int jk_lb_get_method_code(const char *v) +{ + if (!v) + return JK_LB_METHOD_DEF; + else if (*v == 'r' || *v == 'R' || *v == '0') + return JK_LB_METHOD_REQUESTS; + else if (*v == 't' || *v == 'T' || *v == '1') + return JK_LB_METHOD_TRAFFIC; + else if (*v == 'b' || *v == 'B' || *v == '2') + return JK_LB_METHOD_BUSYNESS; + else if (*v == 's' || *v == 'S' || *v == '3') + return JK_LB_METHOD_SESSIONS; + else + return JK_LB_METHOD_DEF; +} + +/* Return the string representation of the balance worker state */ +const char *jk_lb_get_state(lb_sub_worker_t *p, jk_logger_t *l) +{ + return lb_state_type[p->s->state]; +} + +/* Return the int representation of the lb state */ +int jk_lb_get_state_code(const char *v) +{ + if (!v) + return JK_LB_STATE_DEF; + else if (*v == 'i' || *v == 'I' || *v == 'n' || *v == 'N' || *v == '0') + return JK_LB_STATE_IDLE; + else if (*v == 'o' || *v == 'O' || *v == '1') + return JK_LB_STATE_OK; + else if (*v == 'r' || *v == 'R' || *v == '2') + return JK_LB_STATE_RECOVER; + else if (*v == 'f' || *v == 'F' || *v == '3') + return JK_LB_STATE_FORCE; + else if (*v == 'b' || *v == 'B' || *v == '4') + return JK_LB_STATE_BUSY; + else if (*v == 'e' || *v == 'E' || *v == '5') + return JK_LB_STATE_ERROR; + else if (*v == 'p' || *v == 'P' || *v == '6') + return JK_LB_STATE_PROBE; + else + return JK_LB_STATE_DEF; +} + +/* Return the string representation of the balance worker activation */ +/* based on the integer representation */ +const char *jk_lb_get_activation_direct(int activation, jk_logger_t *l) +{ + return lb_activation_type[activation]; +} + +/* Return the string representation of the balance worker activation */ +/* based on the sub worker struct */ +const char *jk_lb_get_activation(lb_sub_worker_t *p, jk_logger_t *l) +{ + return lb_activation_type[p->activation]; +} + +int jk_lb_get_activation_code(const char *v) +{ + if (!v) + return JK_LB_ACTIVATION_DEF; + else if (*v == 'a' || *v == 'A' || *v == '0') + return JK_LB_ACTIVATION_ACTIVE; + else if (*v == 'd' || *v == 'D' || *v == '1') + return JK_LB_ACTIVATION_DISABLED; + else if (*v == 's' || *v == 'S' || *v == '2') + return JK_LB_ACTIVATION_STOPPED; + else + return JK_LB_ACTIVATION_DEF; +} + +/* Update the load multipliers wrt. lb_factor */ +void update_mult(lb_worker_t *p, jk_logger_t *l) +{ + unsigned int i = 0; + jk_uint64_t s = 1; + JK_TRACE_ENTER(l); + for (i = 0; i < p->num_of_workers; i++) { + s = scm(s, p->lb_workers[i].lb_factor); + } + for (i = 0; i < p->num_of_workers; i++) { + p->lb_workers[i].lb_mult = s / p->lb_workers[i].lb_factor; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "worker %s gets multiplicity %" + JK_UINT64_T_FMT, + p->lb_workers[i].name, + p->lb_workers[i].lb_mult); + } + JK_TRACE_EXIT(l); +} + +/* Reset all lb values. + */ +void reset_lb_values(lb_worker_t *p, jk_logger_t *l) +{ + unsigned int i = 0; + JK_TRACE_ENTER(l); + if (p->lbmethod != JK_LB_METHOD_BUSYNESS) { + for (i = 0; i < p->num_of_workers; i++) { + p->lb_workers[i].s->lb_value = 0; + } + } + JK_TRACE_EXIT(l); +} + +/* Syncing config values from shm */ +void jk_lb_pull(lb_worker_t *p, int locked, jk_logger_t *l) +{ + unsigned int i = 0; + + JK_TRACE_ENTER(l); + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "syncing mem for lb '%s' from shm (%u->%u)", + p->name, p->sequence, p->s->h.sequence); + if (locked == JK_FALSE) + jk_shm_lock(); + p->sticky_session = p->s->sticky_session; + p->sticky_session_force = p->s->sticky_session_force; + p->recover_wait_time = p->s->recover_wait_time; + p->error_escalation_time = p->s->error_escalation_time; + p->max_reply_timeouts = p->s->max_reply_timeouts; + p->retries = p->s->retries; + p->retry_interval = p->s->retry_interval; + p->lbmethod = p->s->lbmethod; + p->lblock = p->s->lblock; + p->max_packet_size = p->s->max_packet_size; + p->sequence = p->s->h.sequence; + strncpy(p->session_cookie, p->s->session_cookie, JK_SHM_STR_SIZ); + strncpy(p->session_path, p->s->session_path, JK_SHM_STR_SIZ); + + for (i = 0; i < p->num_of_workers; i++) { + lb_sub_worker_t *w = &p->lb_workers[i]; + if (w->sequence != w->s->h.sequence) { + jk_worker_t *jw = w->worker; + ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private; + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "syncing mem for member '%s' of lb '%s' from shm", + w->name, p->name); + + jk_ajp_pull(aw, JK_TRUE, l); + strncpy(w->route, w->s->route, JK_SHM_STR_SIZ); + strncpy(w->domain, w->s->domain, JK_SHM_STR_SIZ); + strncpy(w->redirect, w->s->redirect, JK_SHM_STR_SIZ); + w->distance = w->s->distance; + w->activation = w->s->activation; + w->lb_factor = w->s->lb_factor; + w->lb_mult = w->s->lb_mult; + w->sequence = w->s->h.sequence; + } + } + if (locked == JK_FALSE) + jk_shm_unlock(); + + JK_TRACE_EXIT(l); +} + +/* Syncing config values to shm */ +void jk_lb_push(lb_worker_t *p, int locked, jk_logger_t *l) +{ + unsigned int i = 0; + + JK_TRACE_ENTER(l); + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "syncing shm for lb '%s' from mem (%u->%u)", + p->name, p->s->h.sequence, p->sequence); + if (locked == JK_FALSE) + jk_shm_lock(); + p->s->sticky_session = p->sticky_session; + p->s->sticky_session_force = p->sticky_session_force; + p->s->recover_wait_time = p->recover_wait_time; + p->s->error_escalation_time = p->error_escalation_time; + p->s->max_reply_timeouts = p->max_reply_timeouts; + p->s->retries = p->retries; + p->s->retry_interval = p->retry_interval; + p->s->lbmethod = p->lbmethod; + p->s->lblock = p->lblock; + p->s->max_packet_size = p->max_packet_size; + p->s->h.sequence = p->sequence; + strncpy(p->s->session_cookie, p->session_cookie, JK_SHM_STR_SIZ); + strncpy(p->s->session_path, p->session_path, JK_SHM_STR_SIZ); + + for (i = 0; i < p->num_of_workers; i++) { + lb_sub_worker_t *w = &p->lb_workers[i]; + if (w->sequence != w->s->h.sequence) { + jk_worker_t *jw = w->worker; + ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private; + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "syncing shm for member '%s' of lb '%s' from mem", + w->name, p->name); + + jk_ajp_push(aw, JK_TRUE, l); + strncpy(w->s->route, w->route, JK_SHM_STR_SIZ); + strncpy(w->s->domain, w->domain, JK_SHM_STR_SIZ); + strncpy(w->s->redirect, w->redirect, JK_SHM_STR_SIZ); + w->s->distance = w->distance; + w->s->activation = w->activation; + w->s->lb_factor = w->lb_factor; + w->s->lb_mult = w->lb_mult; + w->s->h.sequence = w->sequence; + } + } + if (locked == JK_FALSE) + jk_shm_unlock(); + + JK_TRACE_EXIT(l); +} + +/* 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, '?')) != NULL) { + *id_end = '\0'; + } + /* + * Remove any trailing path element. + */ + if ((id_end = strchr(id_start, ';')) != NULL) { + *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; + char *result = NULL; + + for (i = 0; i < s->num_headers; i++) { + if (strcasecmp(s->headers_names[i], "cookie") == 0) { + + char *id_start; + for (id_start = strstr(s->headers_values[i], name); + id_start; id_start = strstr(id_start + 1, name)) { + if (id_start == s->headers_values[i] || + id_start[-1] == ';' || + id_start[-1] == ',' || isspace((int)id_start[-1])) { + id_start += strlen(name); + while (*id_start && isspace((int)(*id_start))) + ++id_start; + if (*id_start == '=' && id_start[1]) { + /* + * Session cookie was found, get it's value + */ + char *id_end; + size_t sz; + ++id_start; + if ((id_end = strpbrk(id_start, ";,")) != NULL) + sz = id_end - id_start; + else { + sz = strlen(id_start); + id_end = id_start + sz; + } + if (result == NULL) { + result = jk_pool_alloc(s->pool, sz + 1); + memcpy(result, id_start, sz); + result[sz] = '\0'; + } + else { + size_t osz = strlen(result) + 1; + result = + jk_pool_realloc(s->pool, osz + sz + 1, result, osz); + strcat(result, ";"); + strncat(result, id_start, sz); + } + id_start = id_end; + } + } + } + } + } + + return result; +} + + +/* Retrieve session id from the cookie or the parameter + * (parameter first) + */ +static char *get_sessionid(jk_ws_service_t *s, lb_worker_t *p, jk_logger_t *l) +{ + char *val; + val = get_path_param(s, p->session_path); + if (!val) { + val = get_cookie(s, p->session_cookie); + } + if (val && !*val) { + /* TODO: For now only log the empty sessions. + * However we should probably return 400 + * (BAD_REQUEST) in this case + */ + jk_log(l, JK_LOG_INFO, + "Detected empty session identifier."); + return NULL; + } + return val; +} + +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].worker->destroy(&(p->lb_workers[i].worker), l); + } +} + +/* If the worker is in error state run + * retry on that worker. It will be marked as + * operational if the retry timeout is elapsed. + * The worker might still be unusable, but we try + * anyway. + * If the worker is in ok state and got no requests + * since the last global maintenance, we mark its + * state as not available. + * Return the number of workers not in error state. + */ +static int recover_workers(lb_worker_t *p, + jk_uint64_t curmax, + time_t now, + jk_logger_t *l) +{ + unsigned int i; + int non_error = 0; + int elapsed; + lb_sub_worker_t *w = NULL; + ajp_worker_t *aw = NULL; + JK_TRACE_ENTER(l); + + if (p->sequence != p->s->h.sequence) + jk_lb_pull(p, JK_TRUE, l); + for (i = 0; i < p->num_of_workers; i++) { + w = &p->lb_workers[i]; + aw = (ajp_worker_t *)w->worker->worker_private; + if (w->s->state == JK_LB_STATE_ERROR) { + elapsed = (int)difftime(now, w->s->error_time); + if (elapsed <= p->recover_wait_time) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "worker %s will recover in %d seconds", + w->name, p->recover_wait_time - elapsed); + } + else { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "worker %s is marked for recovery", + w->name); + if (p->lbmethod != JK_LB_METHOD_BUSYNESS) + w->s->lb_value = curmax; + aw->s->reply_timeouts = 0; + w->s->state = JK_LB_STATE_RECOVER; + non_error++; + } + } + else if (w->s->error_time > 0 && + (int)difftime(now, w->s->error_time) >= p->error_escalation_time) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "worker %s escalating local error to global error", + w->name); + w->s->state = JK_LB_STATE_ERROR; + } + else { + non_error++; + if (w->s->state == JK_LB_STATE_OK && + aw->s->used == w->s->elected_snapshot) + w->s->state = JK_LB_STATE_IDLE; + } + w->s->elected_snapshot = aw->s->used; + } + + JK_TRACE_EXIT(l); + return non_error; +} + +static int force_recovery(lb_worker_t *p, + int *states, + jk_logger_t *l) +{ + unsigned int i; + int forced = 0; + lb_sub_worker_t *w = NULL; + ajp_worker_t *aw = NULL; + JK_TRACE_ENTER(l); + + for (i = 0; i < p->num_of_workers; i++) { + w = &p->lb_workers[i]; + if (w->s->state == JK_LB_STATE_ERROR) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_INFO, + "worker %s is marked for forced recovery", + w->name); + aw = (ajp_worker_t *)w->worker->worker_private; + aw->s->reply_timeouts = 0; + w->s->state = JK_LB_STATE_FORCE; + if (states != NULL) + states[i] = JK_LB_STATE_FORCE; + forced++; + } + } + + JK_TRACE_EXIT(l); + return forced; +} + +/* Divide old load values by the decay factor, + * such that older values get less important + * for the routing decisions. + */ +static jk_uint64_t decay_load(lb_worker_t *p, + time_t exponent, + jk_logger_t *l) +{ + unsigned int i; + jk_uint64_t curmax = 0; + lb_sub_worker_t *w; + ajp_worker_t *aw; + + JK_TRACE_ENTER(l); + for (i = 0; i < p->num_of_workers; i++) { + w = &p->lb_workers[i]; + if (p->lbmethod != JK_LB_METHOD_BUSYNESS) { + w->s->lb_value >>= exponent; + if (w->s->lb_value > curmax) { + curmax = w->s->lb_value; + } + } + aw = (ajp_worker_t *)w->worker->worker_private; + aw->s->reply_timeouts >>= exponent; + } + JK_TRACE_EXIT(l); + return curmax; +} + +static int JK_METHOD maintain_workers(jk_worker_t *p, time_t now, jk_logger_t *l) +{ + unsigned int i = 0; + jk_uint64_t curmax = 0; + long delta; + + JK_TRACE_ENTER(l); + if (p && p->worker_private) { + lb_worker_t *lb = (lb_worker_t *)p->worker_private; + + for (i = 0; i < lb->num_of_workers; i++) { + if (lb->lb_workers[i].worker->maintain) { + lb->lb_workers[i].worker->maintain(lb->lb_workers[i].worker, now, l); + } + } + + jk_shm_lock(); + + /* Now we check for global maintenance (once for all processes). + * Checking workers for recovery and applying decay to the + * load values should not be done by each process individually. + * Therefore we globally sync and we use a global timestamp. + * Since it's possible that we come here a few milliseconds + * before the interval has passed, we allow a little tolerance. + */ + delta = (long)difftime(now, lb->s->last_maintain_time) + JK_LB_MAINTAIN_TOLERANCE; + if (delta >= lb->maintain_time) { + lb->s->last_maintain_time = now; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "decay with 2^%d", + JK_LB_DECAY_MULT * delta / lb->maintain_time); + curmax = decay_load(lb, JK_LB_DECAY_MULT * delta / lb->maintain_time, l); + if (!recover_workers(lb, curmax, now, l)) { + force_recovery(lb, NULL, l); + } + } + + jk_shm_unlock(); + + } + else { + JK_LOG_NULL_PARAMS(l); + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +static int find_by_session(jk_ws_service_t *s, + lb_worker_t *p, + const char *session_route, + jk_logger_t *l) +{ + + int rc = -1; + unsigned int i; + + for (i = 0; i < p->num_of_workers; i++) { + if (strcmp(p->lb_workers[i].route, session_route) == 0) { + rc = i; + break; + } + } + return rc; +} + +static int find_best_bydomain(jk_ws_service_t *s, + lb_worker_t *p, + const char *route_or_domain, + int *states, + jk_logger_t *l) +{ + unsigned int i; + int d = 0; + jk_uint64_t curmin = 0; + int candidate = -1; + int activation; + lb_sub_worker_t wr; + char *idpart = strchr(route_or_domain, '.'); + size_t domain_len = 0; + + if (idpart) { + domain_len = idpart - route_or_domain; + } + else { + domain_len = strlen(route_or_domain); + } + /* First try to see if we have available candidate */ + for (i = 0; i < p->num_of_workers; i++) { + /* Skip all workers that are not member of domain */ + wr = p->lb_workers[i]; + if (strlen(wr.domain) == 0 || + strlen(wr.domain) != domain_len || + strncmp(wr.domain, route_or_domain, domain_len)) + continue; + /* Take into calculation only the workers that are + * not in error state, stopped, disabled or busy. + */ + activation = s->extension.activation ? + s->extension.activation[i] : + JK_LB_ACTIVATION_UNSET; + if (activation == JK_LB_ACTIVATION_UNSET) + activation = wr.activation; + if (JK_WORKER_USABLE(states[wr.i], activation)) { + if (candidate < 0 || wr.distance < d || + (wr.s->lb_value < curmin && + wr.distance == d)) { + candidate = i; + curmin = wr.s->lb_value; + d = wr.distance; + } + } + } + return candidate; +} + + +static int find_best_byvalue(jk_ws_service_t *s, + lb_worker_t *p, + int *states, + jk_logger_t *l) +{ + unsigned int i; + unsigned int j; + unsigned int offset; + int d = 0; + jk_uint64_t curmin = 0; + + /* find the least busy worker */ + int candidate = -1; + int activation; + lb_sub_worker_t wr; + + offset = p->next_offset; + + /* First try to see if we have available candidate */ + for (j = offset; j < p->num_of_workers + offset; j++) { + i = j % p->num_of_workers; + wr = p->lb_workers[i]; + activation = s->extension.activation ? + s->extension.activation[i] : + JK_LB_ACTIVATION_UNSET; + if (activation == JK_LB_ACTIVATION_UNSET) + activation = wr.activation; + + /* Take into calculation only the workers that are + * not in error state, stopped, disabled or busy. + */ + if (JK_WORKER_USABLE(states[wr.i], activation)) { + if (candidate < 0 || wr.distance < d || + (wr.s->lb_value < curmin && + wr.distance == d)) { + candidate = i; + curmin = wr.s->lb_value; + d = wr.distance; + p->next_offset = i + 1; + } + } + } + return candidate; +} + +static int find_bysession_route(jk_ws_service_t *s, + lb_worker_t *p, + const char *session_route, + int *states, + jk_logger_t *l) +{ + int uses_domain = 0; + int candidate = -1; + + candidate = find_by_session(s, p, session_route, l); + if (candidate < 0) { + uses_domain = 1; + candidate = find_best_bydomain(s, p, session_route, states, l); + } + if (candidate >= 0) { + lb_sub_worker_t wr = p->lb_workers[candidate]; + int activation; + if (uses_domain) + s->route = wr.domain; + activation = s->extension.activation ? + s->extension.activation[candidate] : + JK_LB_ACTIVATION_UNSET; + if (activation == JK_LB_ACTIVATION_UNSET) + activation = wr.activation; + if (!JK_WORKER_USABLE_STICKY(states[wr.i], activation)) { + /* We have a worker that is error state or stopped. + * If it has a redirection set use that redirection worker. + * This enables to safely remove the member from the + * balancer. Of course you will need a some kind of + * session replication between those two remote. + */ + if (p->sticky_session_force) + candidate = -1; + else if (*wr.redirect) { + candidate = find_by_session(s, p, wr.redirect, l); + s->route = NULL; + } + else if (*wr.domain && !uses_domain) { + candidate = find_best_bydomain(s, p, wr.domain, states, l); + if (candidate >= 0) { + s->route = wr.domain; + } else { + s->route = NULL; + } + } + if (candidate >= 0) { + wr = p->lb_workers[candidate]; + activation = s->extension.activation ? + s->extension.activation[candidate] : + JK_LB_ACTIVATION_UNSET; + if (activation == JK_LB_ACTIVATION_UNSET) + activation = wr.activation; + if (!JK_WORKER_USABLE_STICKY(states[wr.i], activation)) + candidate = -1; + } + } + } + return candidate; +} + +static int find_failover_worker(jk_ws_service_t *s, + lb_worker_t *p, + int *states, + jk_logger_t *l) +{ + int rc = -1; + unsigned int i; + char *redirect = NULL; + + for (i = 0; i < p->num_of_workers; i++) { + if (strlen(p->lb_workers[i].redirect)) { + redirect = p->lb_workers[i].redirect; + break; + } + } + if (redirect) + rc = find_bysession_route(s, p, redirect, states, l); + return rc; +} + +static int find_best_worker(jk_ws_service_t *s, + lb_worker_t *p, + int *states, + jk_logger_t *l) +{ + int rc = -1; + + rc = find_best_byvalue(s, p, states, l); + /* By default use worker route as session route */ + if (rc < 0) + rc = find_failover_worker(s, p, states, l); + return rc; +} + +static int get_most_suitable_worker(jk_ws_service_t *s, + lb_worker_t *p, + char *sessionid, + int *states, + jk_logger_t *l) +{ + int rc = -1; + int r; + + JK_TRACE_ENTER(l); + if (p->num_of_workers == 1) { + /* No need to find the best worker + * if there is a single one + */ + int activation = s->extension.activation ? + s->extension.activation[0] : + JK_LB_ACTIVATION_UNSET; + if (activation == JK_LB_ACTIVATION_UNSET) + activation = p->lb_workers[0].activation; + if (JK_WORKER_USABLE_STICKY(states[0], activation)) { + if (activation != JK_LB_ACTIVATION_DISABLED) { + JK_TRACE_EXIT(l); + return 0; + } + } + else { + JK_TRACE_EXIT(l); + return -1; + } + } + if (p->lblock == JK_LB_LOCK_PESSIMISTIC) + r = jk_shm_lock(); + else { + JK_ENTER_CS(&(p->cs), r); + } + if (!r) { + jk_log(l, JK_LOG_ERROR, + "locking failed (errno=%d)", + errno); + } + if (sessionid) { + char *session = sessionid; + while (sessionid) { + char *next = strchr(sessionid, ';'); + char *session_route = NULL; + if (next) + *next++ = '\0'; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "searching worker for partial sessionid %s", + sessionid); + session_route = strchr(sessionid, '.'); + if (session_route) { + ++session_route; + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "searching worker for session route %s", + session_route); + + /* We have a session route. Whow! */ + rc = find_bysession_route(s, p, session_route, states, l); + if (rc >= 0) { + lb_sub_worker_t *wr = &(p->lb_workers[rc]); + if (p->lblock == JK_LB_LOCK_PESSIMISTIC) + jk_shm_unlock(); + else { + JK_LEAVE_CS(&(p->cs), r); + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "found worker %s (%s) for route %s and partial sessionid %s", + wr->name, wr->route, session_route, sessionid); + JK_TRACE_EXIT(l); + return rc; + } + } + /* Try next partial sessionid if present */ + sessionid = next; + rc = -1; + } + if (rc < 0 && p->sticky_session_force) { + if (p->lblock == JK_LB_LOCK_PESSIMISTIC) + jk_shm_unlock(); + else { + JK_LEAVE_CS(&(p->cs), r); + } + jk_log(l, JK_LOG_INFO, + "all workers are in error state for session %s", + session); + JK_TRACE_EXIT(l); + return -1; + } + } + rc = find_best_worker(s, p, states, l); + if (p->lblock == JK_LB_LOCK_PESSIMISTIC) + jk_shm_unlock(); + else { + JK_LEAVE_CS(&(p->cs), r); + } + if (rc >= 0) { + lb_sub_worker_t *wr = &(p->lb_workers[rc]); + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "found best worker %s (%s) using method '%s'", + wr->name, wr->route, jk_lb_get_method(p, l)); + JK_TRACE_EXIT(l); + return rc; + } + JK_TRACE_EXIT(l); + return -1; +} + +static void lb_add_log_items(jk_ws_service_t *s, + const char *const *log_names, + lb_sub_worker_t *w, + jk_logger_t *l) +{ + ajp_worker_t *aw = (ajp_worker_t *)w->worker->worker_private; + const char **log_values = jk_pool_alloc(s->pool, sizeof(char *) * JK_LB_NOTES_COUNT); + char *buf = jk_pool_alloc(s->pool, sizeof(char *) * JK_LB_NOTES_COUNT * JK_LB_UINT64_STR_SZ); + if (log_values && buf) { + /* JK_NOTE_LB_FIRST/LAST_NAME */ + log_values[0] = w->name; + snprintf(buf, JK_LB_UINT64_STR_SZ, "%" JK_UINT64_T_FMT, w->s->lb_value); + /* JK_NOTE_LB_FIRST/LAST_VALUE */ + log_values[1] = buf; + buf += JK_LB_UINT64_STR_SZ; + snprintf(buf, JK_LB_UINT64_STR_SZ, "%" JK_UINT64_T_FMT, aw->s->used); + /* JK_NOTE_LB_FIRST/LAST_ACCESSED */ + log_values[2] = buf; + buf += JK_LB_UINT64_STR_SZ; + snprintf(buf, JK_LB_UINT64_STR_SZ, "%" JK_UINT64_T_FMT, aw->s->readed); + /* JK_NOTE_LB_FIRST/LAST_READ */ + log_values[3] = buf; + buf += JK_LB_UINT64_STR_SZ; + snprintf(buf, JK_LB_UINT64_STR_SZ, "%" JK_UINT64_T_FMT, aw->s->transferred); + /* JK_NOTE_LB_FIRST/LAST_TRANSFERRED */ + log_values[4] = buf; + buf += JK_LB_UINT64_STR_SZ; + snprintf(buf, JK_LB_UINT64_STR_SZ, "%" JK_UINT32_T_FMT, w->s->errors); + /* JK_NOTE_LB_FIRST/LAST_ERRORS */ + log_values[5] = buf; + buf += JK_LB_UINT64_STR_SZ; + snprintf(buf, JK_LB_UINT64_STR_SZ, "%d", aw->s->busy); + /* JK_NOTE_LB_FIRST/LAST_BUSY */ + log_values[6] = buf; + /* JK_NOTE_LB_FIRST/LAST_ACTIVATION */ + log_values[7] = jk_lb_get_activation(w, l); + /* JK_NOTE_LB_FIRST/LAST_STATE */ + log_values[8] = jk_lb_get_state(w, l); + s->add_log_items(s, log_names, log_values, JK_LB_NOTES_COUNT); + } +} + +static int JK_METHOD service(jk_endpoint_t *e, + jk_ws_service_t *s, + jk_logger_t *l, int *is_error) +{ + lb_endpoint_t *p; + int attempt = 0; + lb_sub_worker_t *prec = NULL; + int num_of_workers; + int first = 1; + int was_forced = 0; + int recoverable = JK_TRUE; + int rc = JK_UNSET; + char *sessionid = NULL; + int i; + int retry = 0; + + JK_TRACE_ENTER(l); + + if (!e || !e->endpoint_private || !s || !is_error) { + JK_LOG_NULL_PARAMS(l); + if (is_error) + *is_error = JK_HTTP_SERVER_ERROR; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p = e->endpoint_private; + num_of_workers = p->worker->num_of_workers; + + /* Set returned error to OK */ + *is_error = JK_HTTP_OK; + + if (p->worker->sequence != p->worker->s->h.sequence) + jk_lb_pull(p->worker, JK_FALSE, l); + for (i = 0; i < num_of_workers; i++) { + lb_sub_worker_t *rec = &(p->worker->lb_workers[i]); + if (rec->s->state == JK_LB_STATE_BUSY) { + if (ajp_has_endpoint(rec->worker, l)) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "worker %s busy count fixed", + rec->name); + rec->s->state = JK_LB_STATE_OK; + } + } + /* Copy the shared state info */ + p->states[i] = rec->s->state; + } + + /* set the recovery post, for LB mode */ + s->reco_buf = jk_b_new(s->pool); + if (!s->reco_buf) { + *is_error = JK_HTTP_SERVER_ERROR; + jk_log(l, JK_LOG_ERROR, + "Failed allocating AJP message"); + JK_TRACE_EXIT(l); + return JK_SERVER_ERROR; + } + if (jk_b_set_buffer_size(s->reco_buf, p->worker->max_packet_size)) { + *is_error = JK_HTTP_SERVER_ERROR; + jk_log(l, JK_LOG_ERROR, + "Failed allocating AJP message buffer"); + JK_TRACE_EXIT(l); + return JK_SERVER_ERROR; + } + jk_b_reset(s->reco_buf); + s->reco_status = RECO_INITED; + + if (p->worker->sticky_session) { + /* Use sessionid only if sticky_session is + * defined for this load balancer + */ + sessionid = get_sessionid(s, p->worker, l); + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "service sticky_session=%d id='%s'", + p->worker->sticky_session, sessionid ? sessionid : "empty"); + + while (recoverable == JK_TRUE) { + if (attempt >= num_of_workers) { + retry++; + if (retry >= p->worker->retries) { + /* Done with retrying */ + break; + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "retry %d, sleeping for %d ms before retrying", + retry, p->worker->retry_interval); + jk_sleep(p->worker->retry_interval); + /* Pull shared memory if something changed during sleep */ + if (p->worker->sequence != p->worker->s->h.sequence) + jk_lb_pull(p->worker, JK_FALSE, l); + for (i = 0; i < num_of_workers; i++) { + /* Copy the shared state info */ + p->states[i] = p->worker->lb_workers[i].s->state; + } + attempt = 0; + } + rc = JK_FALSE; + *is_error = JK_HTTP_SERVER_BUSY; + i = get_most_suitable_worker(s, p->worker, sessionid, p->states, l); + if (i >= 0) { + int r; + int is_service_error = JK_HTTP_OK; + lb_sub_worker_t *rec = &(p->worker->lb_workers[i]); + ajp_worker_t *aw = (ajp_worker_t *)rec->worker->worker_private; + jk_endpoint_t *end = NULL; + int activation = s->extension.activation ? + s->extension.activation[i] : + JK_LB_ACTIVATION_UNSET; + if (activation == JK_LB_ACTIVATION_UNSET) + activation = rec->activation; + if (!s->route) + s->route = rec->route; + s->activation = jk_lb_get_activation_direct(activation, l); + prec = rec; + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "service worker=%s route=%s", + rec->name, s->route); + + if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC) + jk_shm_lock(); + if (rec->s->state == JK_LB_STATE_RECOVER) { + rec->s->state = JK_LB_STATE_PROBE; + p->states[rec->i] = JK_LB_STATE_PROBE; + } + if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC) + jk_shm_unlock(); + + r = rec->worker->get_endpoint(rec->worker, &end, l); + if (!r || !end) { + /* If we can not get the endpoint + * mark the worker as busy rather then + * as in error if the retry number is + * greater then the number of retries. + */ + if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC) + jk_shm_lock(); + if (rec->s->state != JK_LB_STATE_ERROR) { + rec->s->state = JK_LB_STATE_BUSY; + p->states[rec->i] = JK_LB_STATE_BUSY; + } + if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC) + jk_shm_unlock(); + jk_log(l, JK_LOG_INFO, + "could not get free endpoint for worker %s (%d retries)", + rec->name, retry); + } + else { + int service_stat = JK_UNSET; + jk_uint64_t rd = 0; + jk_uint64_t wr = 0; + /* Reset endpoint read and write sizes for + * this request. + */ + end->rd = end->wr = 0; + end->recoverable = JK_TRUE; + if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC) + jk_shm_lock(); + + /* Increment the number of workers serving request */ + p->worker->s->busy++; + rec->s->busy++; + if (p->worker->s->busy > p->worker->s->max_busy) + p->worker->s->max_busy = p->worker->s->busy; + if ( (p->worker->lbmethod == JK_LB_METHOD_REQUESTS) || + (p->worker->lbmethod == JK_LB_METHOD_BUSYNESS) || + (p->worker->lbmethod == JK_LB_METHOD_SESSIONS && + !sessionid) ) + rec->s->lb_value += rec->lb_mult; + if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC) + jk_shm_unlock(); + + service_stat = end->service(end, s, l, &is_service_error); + rd = end->rd; + wr = end->wr; + recoverable = end->recoverable; + *is_error = is_service_error; + end->done(&end, l); + + if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC) + jk_shm_lock(); + + /* Update partial reads and writes if any */ + if (p->worker->lbmethod == JK_LB_METHOD_TRAFFIC) { + rec->s->lb_value += (rd+wr)*rec->lb_mult; + } + else if (p->worker->lbmethod == JK_LB_METHOD_BUSYNESS) { + if (rec->s->lb_value >= rec->lb_mult) { + rec->s->lb_value -= rec->lb_mult; + } + else { + rec->s->lb_value = 0; + if (JK_IS_DEBUG_LEVEL(l)) { + jk_log(l, JK_LOG_DEBUG, + "worker %s has load value to low (%" + JK_UINT64_T_FMT + " < %" + JK_UINT64_T_FMT + ") ", + "- correcting to 0", + rec->name, + rec->s->lb_value, + rec->lb_mult); + } + } + } + + /* When have an endpoint and we ran a request, assume + * we are OK, unless we last were in error. + * We will below explicitely set OK or ERROR according + * to the returned service_stat. + */ + if (rec->s->state != JK_LB_STATE_ERROR) { + rec->s->state = JK_LB_STATE_OK; + p->states[rec->i] = JK_LB_STATE_OK; + } + /* Decrement the busy worker count. + * Check if the busy was reset to zero by graceful + * restart of the server. + */ + if (p->worker->s->busy) + p->worker->s->busy--; + if (rec->s->busy) + rec->s->busy--; + if (service_stat == JK_TRUE) { + /* + * Successful request. + */ + rec->s->state = JK_LB_STATE_OK; + p->states[rec->i] = JK_LB_STATE_OK; + rec->s->error_time = 0; + rc = JK_TRUE; + recoverable = JK_UNSET; + } + else if (service_stat == JK_CLIENT_ERROR) { + /* + * Client error !!! + * Since this is bad request do not fail over. + */ + rec->s->state = JK_LB_STATE_OK; + p->states[rec->i] = JK_LB_STATE_ERROR; + rec->s->error_time = 0; + rc = JK_CLIENT_ERROR; + recoverable = JK_FALSE; + } + else if (service_stat == JK_SERVER_ERROR) { + /* + * Internal JK server error. + * Keep previous global state. + * Do not try to reuse the same node for the same request. + * Failing over to another node could help. + */ + p->states[rec->i] = JK_LB_STATE_ERROR; + rc = JK_FALSE; + } + else if (service_stat == JK_AJP_PROTOCOL_ERROR) { + /* + * We've received a bad AJP message from the backend. + * Keep previous global state. + * Do not try to reuse the same node for the same request. + * Failing over to another node could help. + */ + p->states[rec->i] = JK_LB_STATE_ERROR; + rc = JK_FALSE; + } + else if (service_stat == JK_STATUS_ERROR) { + /* + * Status code configured as service is down. + * The node is fine. + * Do not try to reuse the same node for the same request. + * Failing over to another node could help. + */ + rec->s->state = JK_LB_STATE_OK; + p->states[rec->i] = JK_LB_STATE_ERROR; + rec->s->error_time = 0; + rc = JK_FALSE; + } + else if (service_stat == JK_STATUS_FATAL_ERROR) { + /* + * Status code configured as service is down. + * Mark the node as bad. + * Do not try to reuse the same node for the same request. + * Failing over to another node could help. + */ + rec->s->errors++; + rec->s->state = JK_LB_STATE_ERROR; + p->states[rec->i] = JK_LB_STATE_ERROR; + rec->s->error_time = time(NULL); + rc = JK_FALSE; + } + else if (service_stat == JK_REPLY_TIMEOUT) { + if (aw->s->reply_timeouts > (unsigned)p->worker->max_reply_timeouts) { + /* + * Service failed - to many reply timeouts + * Mark the node as bad. + * Do not try to reuse the same node for the same request. + * Failing over to another node could help. + */ + rec->s->errors++; + rec->s->state = JK_LB_STATE_ERROR; + p->states[rec->i] = JK_LB_STATE_ERROR; + rec->s->error_time = time(NULL); + } + else { + /* + * Reply timeout, bot not yet too many of them. + * Keep previous global state. + * Do not try to reuse the same node for the same request. + * Failing over to another node could help. + */ + p->states[rec->i] = JK_LB_STATE_ERROR; + } + rc = JK_FALSE; + } + else { + /* + * Various unspecific error cases. + * Keep previous global state, if we are not in local error since to long. + * Do not try to reuse the same node for the same request. + * Failing over to another node could help. + */ + time_t now = time(NULL); + rec->s->errors++; + if (rec->s->busy == 0 || + p->worker->error_escalation_time == 0 || + (rec->s->error_time > 0 && + (int)difftime(now, rec->s->error_time) >= p->worker->error_escalation_time)) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "worker %s escalating local error to global error", + rec->name); + rec->s->state = JK_LB_STATE_ERROR; + } + p->states[rec->i] = JK_LB_STATE_ERROR; + if (rec->s->error_time == 0) { + rec->s->error_time = now; + } + rc = JK_FALSE; + } + if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC) + jk_shm_unlock(); + if (p->states[rec->i] == JK_LB_STATE_ERROR) + jk_log(l, JK_LOG_INFO, + "service failed, worker %s is in %serror state", + rec->name, + rec->s->state == JK_LB_STATE_ERROR ? "" : "local "); + } + if (recoverable == JK_TRUE) { + /* + * Error is recoverable by submitting the request to + * another worker... Lets try to do that. + */ + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "recoverable error... will try to recover on other worker"); + } + else { + /* + * Error is not recoverable - break with an error. + */ + if (rc == JK_CLIENT_ERROR) + jk_log(l, JK_LOG_INFO, + "unrecoverable error %d, request failed." + " Client failed in the middle of request," + " we can't recover to another instance.", + *is_error); + else if (rc != JK_TRUE) + jk_log(l, JK_LOG_ERROR, + "unrecoverable error %d, request failed." + " Tomcat failed in the middle of request," + " we can't recover to another instance.", + *is_error); + } + if (first == 1 && s->add_log_items) { + first = 0; + lb_add_log_items(s, lb_first_log_names, prec, l); + } + } + else { + /* No more workers left ... */ + if (!was_forced) { + int nf; + /* Force recovery only once. + * If it still fails, Tomcat is still disconnected. + */ + jk_shm_lock(); + nf = force_recovery(p->worker, p->states, l); + jk_shm_unlock(); + was_forced = 1; + if (nf) { + /* We have forced recovery. + * Reset the service loop and go again + */ + prec = NULL; + jk_log(l, JK_LOG_INFO, + "Forcing recovery once for %d workers", nf); + continue; + } + else { + /* No workers in error state. + * Somebody set them all to disabled? + */ + jk_log(l, JK_LOG_INFO, + "All tomcat instances failed, no more workers " + "left for recovery (attempt=%d, retry=%d)", + attempt, retry); + *is_error = JK_HTTP_SERVER_BUSY; + rc = JK_FALSE; + } + } + else { + jk_log(l, JK_LOG_INFO, + "All tomcat instances failed, no more workers " + "left (attempt=%d, retry=%d)", + attempt, retry); + *is_error = JK_HTTP_SERVER_BUSY; + rc = JK_FALSE; + } + } + attempt++; + } + if (recoverable == JK_TRUE) { + jk_log(l, JK_LOG_INFO, + "All tomcat instances are busy or in error state"); + /* rc and http error must be set above */ + } + if (rc == JK_FALSE) { + jk_log(l, JK_LOG_ERROR, + "All tomcat instances failed, no more workers left"); + } + if (prec && s->add_log_items) { + lb_add_log_items(s, lb_last_log_names, prec, l); + } + + JK_TRACE_EXIT(l); + return rc; +} + +static int JK_METHOD done(jk_endpoint_t **e, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + if (e && *e && (*e)->endpoint_private) { + lb_endpoint_t *p = (*e)->endpoint_private; + free(p->states); + free(p); + *e = NULL; + JK_TRACE_EXIT(l); + return JK_TRUE; + } + + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +static int JK_METHOD validate(jk_worker_t *pThis, + jk_map_t *props, + jk_worker_env_t *we, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + if (pThis && pThis->worker_private) { + lb_worker_t *p = pThis->worker_private; + char **worker_names; + unsigned int num_of_workers; + const char *secret; + + p->sticky_session = jk_get_is_sticky_session(props, p->name); + p->sticky_session_force = jk_get_is_sticky_session_force(props, p->name); + secret = jk_get_worker_secret(props, p->name); + + if (jk_get_lb_worker_list(props, + p->name, + &worker_names, + &num_of_workers) && num_of_workers) { + unsigned int i = 0; + unsigned int j = 0; + p->max_packet_size = DEF_BUFFER_SZ; + p->lb_workers = jk_pool_alloc(&p->p, + num_of_workers * + sizeof(lb_sub_worker_t)); + if (!p->lb_workers) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + memset(p->lb_workers, 0, num_of_workers * sizeof(lb_sub_worker_t)); + for (i = 0; i < num_of_workers; i++) { + p->lb_workers[i].s = jk_shm_alloc_lb_sub_worker(&p->p); + if (p->lb_workers[i].s == NULL) { + jk_log(l, JK_LOG_ERROR, + "allocating lb sub worker record from shared memory"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + + for (i = 0; i < num_of_workers; i++) { + const char *s; + unsigned int ms; + + p->lb_workers[i].i = i; + strncpy(p->lb_workers[i].name, worker_names[i], + JK_SHM_STR_SIZ); + strncpy(p->lb_workers[i].s->h.name, worker_names[i], + JK_SHM_STR_SIZ); + p->lb_workers[i].sequence = 0; + p->lb_workers[i].s->h.sequence = 0; + p->lb_workers[i].lb_factor = + jk_get_lb_factor(props, worker_names[i]); + if (p->lb_workers[i].lb_factor < 1) { + p->lb_workers[i].lb_factor = 1; + } + /* Calculate the maximum packet size from all workers + * for the recovery buffer. + */ + ms = jk_get_max_packet_size(props, worker_names[i]); + if (ms > p->max_packet_size) + p->max_packet_size = ms; + p->lb_workers[i].distance = + jk_get_distance(props, worker_names[i]); + if ((s = jk_get_worker_route(props, worker_names[i], NULL))) + strncpy(p->lb_workers[i].route, s, JK_SHM_STR_SIZ); + else + strncpy(p->lb_workers[i].route, worker_names[i], JK_SHM_STR_SIZ); + if ((s = jk_get_worker_domain(props, worker_names[i], NULL))) + strncpy(p->lb_workers[i].domain, s, JK_SHM_STR_SIZ); + if ((s = jk_get_worker_redirect(props, worker_names[i], NULL))) + strncpy(p->lb_workers[i].redirect, s, JK_SHM_STR_SIZ); + + p->lb_workers[i].s->lb_value = 0; + p->lb_workers[i].s->state = JK_LB_STATE_IDLE; + p->lb_workers[i].s->error_time = 0; + p->lb_workers[i].activation = + jk_get_worker_activation(props, worker_names[i]); + if (!wc_create_worker(p->lb_workers[i].name, 0, + props, + &(p->lb_workers[i].worker), + we, l) || !p->lb_workers[i].worker) { + break; + } + if (secret && (p->lb_workers[i].worker->type == JK_AJP13_WORKER_TYPE || + p->lb_workers[i].worker->type == JK_AJP14_WORKER_TYPE)) { + ajp_worker_t *aw = (ajp_worker_t *)p->lb_workers[i].worker->worker_private; + if (!aw->secret) + aw->secret = secret; + } + if (p->lb_workers[i].worker->type == JK_AJP13_WORKER_TYPE || + p->lb_workers[i].worker->type == JK_AJP14_WORKER_TYPE) { + ajp_worker_t *aw = (ajp_worker_t *)p->lb_workers[i].worker->worker_private; + if (aw->port == 0) { + p->lb_workers[i].activation = JK_LB_ACTIVATION_STOPPED; + } + } + } + + if (i != num_of_workers) { + jk_log(l, JK_LOG_ERROR, + "Failed creating worker %s", + p->lb_workers[i].name); + close_workers(p, i, l); + } + else { + /* Update domain names if route contains period '.' */ + for (i = 0; i < num_of_workers; i++) { + if (!p->lb_workers[i].domain[0]) { + char *id_domain = strchr(p->lb_workers[i].route, '.'); + if (id_domain) { + *id_domain = '\0'; + strcpy(p->lb_workers[i].domain, p->lb_workers[i].route); + *id_domain = '.'; + } + } + if (JK_IS_DEBUG_LEVEL(l)) { + jk_log(l, JK_LOG_DEBUG, + "Balanced worker %i has name %s and route %s in domain %s", + i, + p->lb_workers[i].name, + p->lb_workers[i].route, + p->lb_workers[i].domain); + } + } + p->num_of_workers = num_of_workers; + update_mult(p, l); + for (i = 0; i < num_of_workers; i++) { + for (j = 0; j < i; j++) { + if (strcmp(p->lb_workers[i].route, p->lb_workers[j].route) == 0) { + jk_log(l, JK_LOG_ERROR, + "Balanced workers number %i (%s) and %i (%s) share the same route %s - aborting configuration!", + i, + p->lb_workers[i].name, + j, + p->lb_workers[j].name, + p->lb_workers[i].route); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + } + JK_TRACE_EXIT(l); + return JK_TRUE; + } + } + } + + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +static int JK_METHOD init(jk_worker_t *pThis, + jk_map_t *props, + jk_worker_env_t *we, jk_logger_t *log) +{ + int i; + + lb_worker_t *p = (lb_worker_t *)pThis->worker_private; + JK_TRACE_ENTER(log); + + p->worker.we = we; + p->retries = jk_get_worker_retries(props, p->name, + JK_RETRIES); + p->retry_interval = + jk_get_worker_retry_interval(props, p->name, + JK_SLEEP_DEF); + p->recover_wait_time = jk_get_worker_recover_timeout(props, p->name, + WAIT_BEFORE_RECOVER); + if (p->recover_wait_time < 1) + p->recover_wait_time = 1; + p->error_escalation_time = jk_get_worker_error_escalation_time(props, p->name, + p->recover_wait_time / 2); + p->max_reply_timeouts = jk_get_worker_max_reply_timeouts(props, p->name, + 0); + p->maintain_time = jk_get_worker_maintain_time(props); + if(p->maintain_time < 0) + p->maintain_time = 0; + p->s->last_maintain_time = time(NULL); + p->s->last_reset = p->s->last_maintain_time; + + p->lbmethod = jk_get_lb_method(props, p->name); + p->lblock = jk_get_lb_lock(props, p->name); + strncpy(p->session_cookie, + jk_get_lb_session_cookie(props, p->name, JK_SESSION_IDENTIFIER), + JK_SHM_STR_SIZ); + strncpy(p->session_path, + jk_get_lb_session_path(props, p->name, JK_PATH_SESSION_IDENTIFIER), + JK_SHM_STR_SIZ); + strcpy(p->s->session_cookie, p->session_cookie); + strcpy(p->s->session_path, p->session_path); + + JK_INIT_CS(&(p->cs), i); + if (i == JK_FALSE) { + jk_log(log, JK_LOG_ERROR, + "creating thread lock (errno=%d)", + errno); + JK_TRACE_EXIT(log); + return JK_FALSE; + } + + p->sequence++; + jk_lb_push(p, JK_FALSE, log); + + JK_TRACE_EXIT(log); + return JK_TRUE; +} + +static int JK_METHOD get_endpoint(jk_worker_t *pThis, + jk_endpoint_t **pend, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + if (pThis && pThis->worker_private && pend) { + lb_endpoint_t *p = (lb_endpoint_t *) malloc(sizeof(lb_endpoint_t)); + p->worker = pThis->worker_private; + p->endpoint.endpoint_private = p; + p->endpoint.service = service; + p->endpoint.done = done; + p->states = (int *)malloc((p->worker->num_of_workers + 1) * sizeof(int)); + if (!p->states) { + free(p); + jk_log(l, JK_LOG_ERROR, + "Failed allocating private worker state memory"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + *pend = &p->endpoint; + JK_TRACE_EXIT(l); + return JK_TRUE; + } + else { + JK_LOG_NULL_PARAMS(l); + } + + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +static int JK_METHOD destroy(jk_worker_t **pThis, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + if (pThis && *pThis && (*pThis)->worker_private) { + unsigned int i; + lb_worker_t *private_data = (*pThis)->worker_private; + + close_workers(private_data, private_data->num_of_workers, l); + JK_DELETE_CS(&(private_data->cs), i); + jk_close_pool(&private_data->p); + free(private_data); + + JK_TRACE_EXIT(l); + return JK_TRUE; + } + + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +int JK_METHOD lb_worker_factory(jk_worker_t **w, + const char *name, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + if (NULL != name && NULL != w) { + lb_worker_t *private_data = + (lb_worker_t *) calloc(1, sizeof(lb_worker_t)); + + + jk_open_pool(&private_data->p, + private_data->buf, + sizeof(jk_pool_atom_t) * TINY_POOL_SIZE); + + private_data->s = jk_shm_alloc_lb_worker(&private_data->p); + if (!private_data->s) { + free(private_data); + JK_TRACE_EXIT(l); + return 0; + } + strncpy(private_data->name, name, JK_SHM_STR_SIZ); + strncpy(private_data->s->h.name, name, JK_SHM_STR_SIZ); + 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; + private_data->worker.maintain = maintain_workers; + private_data->recover_wait_time = WAIT_BEFORE_RECOVER; + private_data->error_escalation_time = private_data->recover_wait_time / 2; + private_data->max_reply_timeouts = 0; + private_data->sequence = 0; + private_data->s->h.sequence = 0; + private_data->next_offset = 0; + *w = &private_data->worker; + JK_TRACE_EXIT(l); + return JK_LB_WORKER_TYPE; + } + else { + JK_LOG_NULL_PARAMS(l); + } + + JK_TRACE_EXIT(l); + return 0; +} diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_lb_worker.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_lb_worker.h new file mode 100644 index 00000000..f0885e24 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_lb_worker.h @@ -0,0 +1,222 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: load balance worker header file * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Author: Rainer Jung <rjung@apache.org> * + * Version: $Revision: 751916 $ * + ***************************************************************************/ + +#ifndef JK_LB_WORKER_H +#define JK_LB_WORKER_H + +#include "jk_logger.h" +#include "jk_service.h" +#include "jk_mt.h" +#include "jk_shm.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#define JK_LB_WORKER_NAME ("lb") +#define JK_LB_WORKER_TYPE (5) +#define JK_LB_SUB_WORKER_TYPE (7) +#define JK_LB_DEF_DOMAIN_NAME ("unknown") + +#define JK_LB_METHOD_REQUESTS (0) +#define JK_LB_METHOD_TRAFFIC (1) +#define JK_LB_METHOD_BUSYNESS (2) +#define JK_LB_METHOD_SESSIONS (3) +#define JK_LB_METHOD_DEF (JK_LB_METHOD_REQUESTS) +#define JK_LB_METHOD_MAX (JK_LB_METHOD_SESSIONS) +#define JK_LB_METHOD_TEXT_REQUESTS ("Request") +#define JK_LB_METHOD_TEXT_TRAFFIC ("Traffic") +#define JK_LB_METHOD_TEXT_BUSYNESS ("Busyness") +#define JK_LB_METHOD_TEXT_SESSIONS ("Sessions") +#define JK_LB_METHOD_TEXT_DEF (JK_LB_METHOD_TEXT_REQUESTS) +#define JK_LB_LOCK_OPTIMISTIC (0) +#define JK_LB_LOCK_PESSIMISTIC (1) +#define JK_LB_LOCK_DEF (JK_LB_LOCK_OPTIMISTIC) +#define JK_LB_LOCK_MAX (JK_LB_LOCK_PESSIMISTIC) +#define JK_LB_LOCK_TEXT_OPTIMISTIC ("Optimistic") +#define JK_LB_LOCK_TEXT_PESSIMISTIC ("Pessimistic") +#define JK_LB_LOCK_TEXT_DEF (JK_LB_LOCK_TEXT_OPTIMISTIC) +/* + * The following definitions for state and activation + * need to be kept in sync with the two macros + * JK_WORKER_USABLE() and JK_WORKER_USABLE_STICKY() in jk_lb_worker.c. + * Since we use ordered comparisons there instead of multiple + * equal/unequal compares, order of the values is critical here. + */ +#define JK_LB_STATE_IDLE (0) +#define JK_LB_STATE_OK (1) +#define JK_LB_STATE_RECOVER (2) +#define JK_LB_STATE_FORCE (3) +#define JK_LB_STATE_BUSY (4) +#define JK_LB_STATE_ERROR (5) +#define JK_LB_STATE_PROBE (6) +#define JK_LB_STATE_DEF (JK_LB_STATE_IDLE) +#define JK_LB_STATE_TEXT_IDLE ("OK/IDLE") +#define JK_LB_STATE_TEXT_OK ("OK") +#define JK_LB_STATE_TEXT_RECOVER ("ERR/REC") +#define JK_LB_STATE_TEXT_FORCE ("ERR/FRC") +#define JK_LB_STATE_TEXT_BUSY ("OK/BUSY") +#define JK_LB_STATE_TEXT_ERROR ("ERR") +#define JK_LB_STATE_TEXT_PROBE ("ERR/PRB") +#define JK_LB_STATE_TEXT_MAX (JK_LB_STATE_PROBE) +#define JK_LB_STATE_TEXT_DEF (JK_LB_STATE_TEXT_IDLE) +/* All JK_LB_ACTIVATION_* values must be single digit. */ +/* Otherwise the string encoding of the activation array */ +/* fails e.g. in the isapi redirector. */ +/* JK_LB_ACTIVATION_UNSET is not allowed as an actual worker state. */ +/* It will not work e.g. when the status worker tries to show the state. */ +/* It is only used in rule extension data to indicate, that the */ +/* activation state should not be overwritten. */ +#define JK_LB_ACTIVATION_ACTIVE (0) +#define JK_LB_ACTIVATION_DISABLED (1) +#define JK_LB_ACTIVATION_STOPPED (2) +#define JK_LB_ACTIVATION_UNSET (9) +#define JK_LB_ACTIVATION_DEF (JK_LB_ACTIVATION_ACTIVE) +#define JK_LB_ACTIVATION_MAX (JK_LB_ACTIVATION_STOPPED) +#define JK_LB_ACTIVATION_TEXT_ACTIVE ("ACT") +#define JK_LB_ACTIVATION_TEXT_DISABLED ("DIS") +#define JK_LB_ACTIVATION_TEXT_STOPPED ("STP") +#define JK_LB_ACTIVATION_TEXT_DEF (JK_LB_ACTIVATION_TEXT_ACTIVE) + +#define JK_LB_UINT64_STR_SZ (21) +#define JK_LB_NOTES_COUNT (9) +#define JK_NOTE_LB_FIRST_NAME ("JK_LB_FIRST_NAME") +#define JK_NOTE_LB_FIRST_VALUE ("JK_LB_FIRST_VALUE") +#define JK_NOTE_LB_FIRST_ACCESSED ("JK_LB_FIRST_ACCESSED") +#define JK_NOTE_LB_FIRST_READ ("JK_LB_FIRST_READ") +#define JK_NOTE_LB_FIRST_TRANSFERRED ("JK_LB_FIRST_TRANSFERRED") +#define JK_NOTE_LB_FIRST_ERRORS ("JK_LB_FIRST_ERRORS") +#define JK_NOTE_LB_FIRST_BUSY ("JK_LB_FIRST_BUSY") +#define JK_NOTE_LB_FIRST_ACTIVATION ("JK_LB_FIRST_ACTIVATION") +#define JK_NOTE_LB_FIRST_STATE ("JK_LB_FIRST_STATE") +#define JK_NOTE_LB_LAST_NAME ("JK_LB_LAST_NAME") +#define JK_NOTE_LB_LAST_VALUE ("JK_LB_LAST_VALUE") +#define JK_NOTE_LB_LAST_ACCESSED ("JK_LB_LAST_ACCESSED") +#define JK_NOTE_LB_LAST_READ ("JK_LB_LAST_READ") +#define JK_NOTE_LB_LAST_TRANSFERRED ("JK_LB_LAST_TRANSFERRED") +#define JK_NOTE_LB_LAST_ERRORS ("JK_LB_LAST_ERRORS") +#define JK_NOTE_LB_LAST_BUSY ("JK_LB_LAST_BUSY") +#define JK_NOTE_LB_LAST_ACTIVATION ("JK_LB_LAST_ACTIVATION") +#define JK_NOTE_LB_LAST_STATE ("JK_LB_LAST_STATE") + +/* Time to wait before retry. */ +#define WAIT_BEFORE_RECOVER (60) +/* We accept doing global maintenance if we are */ +/* JK_LB_MAINTAIN_TOLERANCE seconds early. */ +#define JK_LB_MAINTAIN_TOLERANCE (2) +/* We divide load values by 2^x during global maintenance. */ +/* The exponent x is JK_LB_DECAY_MULT*#MAINT_INTV_SINCE_LAST_MAINT */ +#define JK_LB_DECAY_MULT (1) + +struct lb_sub_worker +{ + jk_worker_t *worker; + /* Shared memory worker data */ + jk_shm_lb_sub_worker_t *s; + + char name[JK_SHM_STR_SIZ+1]; + /* Sequence counter starting at 0 and increasing + * every time we change the config + */ + volatile unsigned int sequence; + + /* route */ + char route[JK_SHM_STR_SIZ+1]; + /* worker domain */ + char domain[JK_SHM_STR_SIZ+1]; + /* worker redirect route */ + char redirect[JK_SHM_STR_SIZ+1]; + /* worker distance */ + int distance; + /* current activation state (config) of the worker */ + int activation; + /* Current lb factor */ + int lb_factor; + /* Current worker index */ + int i; + /* Current lb reciprocal factor */ + jk_uint64_t lb_mult; +}; +typedef struct lb_sub_worker lb_sub_worker_t; + +struct lb_worker +{ + jk_worker_t worker; + /* Shared memory worker data */ + jk_shm_lb_worker_t *s; + + char name[JK_SHM_STR_SIZ+1]; + /* Sequence counter starting at 0 and increasing + * every time we change the config + */ + volatile unsigned int sequence; + + jk_pool_t p; + jk_pool_atom_t buf[TINY_POOL_SIZE]; + + JK_CRIT_SEC cs; + + lb_sub_worker_t *lb_workers; + unsigned int num_of_workers; + int sticky_session; + int sticky_session_force; + int recover_wait_time; + int error_escalation_time; + int max_reply_timeouts; + int retries; + int retry_interval; + int lbmethod; + int lblock; + int maintain_time; + unsigned int max_packet_size; + unsigned int next_offset; + /* Session cookie */ + char session_cookie[JK_SHM_STR_SIZ+1]; + /* Session path */ + char session_path[JK_SHM_STR_SIZ+1]; +}; +typedef struct lb_worker lb_worker_t; + +int JK_METHOD lb_worker_factory(jk_worker_t **w, + const char *name, jk_logger_t *l); + +const char *jk_lb_get_lock(lb_worker_t *p, jk_logger_t *l); +int jk_lb_get_lock_code(const char *v); +const char *jk_lb_get_method(lb_worker_t *p, jk_logger_t *l); +int jk_lb_get_method_code(const char *v); +const char *jk_lb_get_state(lb_sub_worker_t *p, jk_logger_t *l); +int jk_lb_get_state_code(const char *v); +const char *jk_lb_get_activation_direct(int activation, jk_logger_t *l); +const char *jk_lb_get_activation(lb_sub_worker_t *p, jk_logger_t *l); +int jk_lb_get_activation_code(const char *v); +void reset_lb_values(lb_worker_t *p, jk_logger_t *l); +void jk_lb_pull(lb_worker_t * p, int locked, jk_logger_t *l); +void jk_lb_push(lb_worker_t * p, int locked, jk_logger_t *l); +void update_mult(lb_worker_t * p, jk_logger_t *l); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* JK_LB_WORKER_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_lb_worker.lo b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_lb_worker.lo new file mode 100644 index 00000000..1a84f8f0 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_lb_worker.lo @@ -0,0 +1,12 @@ +# jk_lb_worker.lo - a libtool object file +# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/jk_lb_worker.o' + +# Name of the non-PIC object. +non_pic_object='jk_lb_worker.o' + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_lb_worker.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_lb_worker.o Binary files differnew file mode 100644 index 00000000..d8b71999 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_lb_worker.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_logger.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_logger.h new file mode 100644 index 00000000..b3ba7c99 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_logger.h @@ -0,0 +1,139 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Logger object definitions * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Version: $Revision: 1001219 $ * + ***************************************************************************/ + +#ifndef JK_LOGGER_H +#define JK_LOGGER_H + +#include "jk_global.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define JK_TIME_MAX_SIZE (64) + +typedef struct jk_logger jk_logger_t; +struct jk_logger +{ + void *logger_private; + int level; + const char *log_fmt; /* the configured timestamp format for logging */ + char log_fmt_subsec[JK_TIME_MAX_SIZE]; /* like log_fmt, but milli/micro seconds marker + replaced, because strftime() doesn't handle those */ + int log_fmt_type; /* do we want milli or microseconds */ + size_t log_fmt_offset; /* at which position should we insert */ + size_t log_fmt_size; /* how long is this format string */ + + int (JK_METHOD * log) (jk_logger_t *l, int level, int used, char *what); + +}; + +typedef struct jk_file_logger_t jk_file_logger_t; +struct jk_file_logger_t +{ + FILE *logfile; + /* For Apache 2 APR piped logging */ + void *jklogfp; + /* For Apache 1.3 piped logging */ + int log_fd; +}; + +/* Level like Java tracing, but available only + at compile time on DEBUG preproc define. + */ +#define JK_LOG_TRACE_LEVEL 0 +#define JK_LOG_DEBUG_LEVEL 1 +#define JK_LOG_INFO_LEVEL 2 +#define JK_LOG_WARNING_LEVEL 3 +#define JK_LOG_ERROR_LEVEL 4 +#define JK_LOG_EMERG_LEVEL 5 +#define JK_LOG_REQUEST_LEVEL 6 +#define JK_LOG_DEF_LEVEL JK_LOG_INFO_LEVEL + +#define JK_LOG_TRACE_VERB "trace" +#define JK_LOG_DEBUG_VERB "debug" +#define JK_LOG_INFO_VERB "info" +#define JK_LOG_WARN_VERB "warn" +#define JK_LOG_ERROR_VERB "error" +#define JK_LOG_EMERG_VERB "emerg" +#define JK_LOG_DEF_VERB JK_LOG_INFO_VERB + +#if defined(__GNUC__) || (defined(_MSC_VER) && (_MSC_VER > 1200)) +#define JK_LOG_TRACE __FILE__,__LINE__,__FUNCTION__,JK_LOG_TRACE_LEVEL +#define JK_LOG_DEBUG __FILE__,__LINE__,__FUNCTION__,JK_LOG_DEBUG_LEVEL +#define JK_LOG_ERROR __FILE__,__LINE__,__FUNCTION__,JK_LOG_ERROR_LEVEL +#define JK_LOG_EMERG __FILE__,__LINE__,__FUNCTION__,JK_LOG_EMERG_LEVEL +#define JK_LOG_INFO __FILE__,__LINE__,__FUNCTION__,JK_LOG_INFO_LEVEL +#define JK_LOG_WARNING __FILE__,__LINE__,__FUNCTION__,JK_LOG_WARNING_LEVEL +#else +#define JK_LOG_TRACE __FILE__,__LINE__,NULL,JK_LOG_TRACE_LEVEL +#define JK_LOG_DEBUG __FILE__,__LINE__,NULL,JK_LOG_DEBUG_LEVEL +#define JK_LOG_ERROR __FILE__,__LINE__,NULL,JK_LOG_ERROR_LEVEL +#define JK_LOG_EMERG __FILE__,__LINE__,NULL,JK_LOG_EMERG_LEVEL +#define JK_LOG_INFO __FILE__,__LINE__,NULL,JK_LOG_INFO_LEVEL +#define JK_LOG_WARNING __FILE__,__LINE__,NULL,JK_LOG_WARNING_LEVEL +#endif + +#define JK_LOG_REQUEST __FILE__,0,NULL,JK_LOG_REQUEST_LEVEL + +#if defined(JK_PRODUCTION) +/* TODO: all DEBUG messages should be compiled out + * when this define is in place. + */ +#define JK_IS_PRODUCTION 1 +#define JK_TRACE_ENTER(l) +#define JK_TRACE_EXIT(l) +#else +#define JK_IS_PRODUCTION 0 +#define JK_TRACE_ENTER(l) \ + do { \ + if ((l) && (l)->level == JK_LOG_TRACE_LEVEL) { \ + int tmp_errno = errno; \ + jk_log((l), JK_LOG_TRACE, "enter"); \ + errno = tmp_errno; \ + } } while (0) + +#define JK_TRACE_EXIT(l) \ + do { \ + if ((l) && (l)->level == JK_LOG_TRACE_LEVEL) { \ + int tmp_errno = errno; \ + jk_log((l), JK_LOG_TRACE, "exit"); \ + errno = tmp_errno; \ + } } while (0) + +#endif /* JK_PRODUCTION */ + +#define JK_LOG_NULL_PARAMS(l) jk_log((l), JK_LOG_ERROR, "NULL parameters") + +/* Debug level macro + * It is more efficient to check the level prior + * calling function that will not execute anyhow because of level + */ +#define JK_IS_DEBUG_LEVEL(l) ((l) && (l)->level < JK_LOG_INFO_LEVEL) + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* JK_LOGGER_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_map.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_map.c new file mode 100644 index 00000000..4b025425 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_map.c @@ -0,0 +1,889 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: General purpose map object * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Author: Mladen Turk <mturk@apache.org> * + * Version: $Revision: 1042364 $ * + ***************************************************************************/ +#if defined(AS400) && !defined(AS400_UTF8) +#include "apr_xlate.h" +#endif + +#include "jk_global.h" +#include "jk_pool.h" +#include "jk_util.h" +#include "jk_map.h" + +#define CAPACITY_INC_SIZE (50) +#define LENGTH_OF_LINE (8192) +#define JK_MAP_RECURSION (20) +#define JK_MAP_REFERENCE (".reference") +#define JK_MAP_REFERENCE_SZ (strlen(JK_MAP_REFERENCE)) + +/* Compute the "checksum" for a key, consisting of the first + * 4 bytes, packed into an int. + * This checksum allows us to do a single integer + * comparison as a fast check to determine whether we can + * skip a strcmp + */ +#define COMPUTE_KEY_CHECKSUM(key, checksum) \ +{ \ + const char *k = (key); \ + unsigned int c = (unsigned int)*k; \ + (checksum) = c; \ + (checksum) <<= 8; \ + if (c) { \ + c = (unsigned int)*++k; \ + checksum |= c; \ + } \ + (checksum) <<= 8; \ + if (c) { \ + c = (unsigned int)*++k; \ + checksum |= c; \ + } \ + (checksum) <<= 8; \ + if (c) { \ + c = (unsigned int)*++k; \ + checksum |= c; \ + } \ +} + +struct jk_map +{ + jk_pool_t p; + jk_pool_atom_t buf[SMALL_POOL_SIZE]; + + const char **names; + const void **values; + unsigned int *keys; + + unsigned int capacity; + unsigned int size; +}; + +static void trim_prp_comment(char *prp); +static size_t trim(char *s); +static int map_realloc(jk_map_t *m); +static char *jk_map_replace_properties(jk_map_t *m, jk_map_t *env, char *value); + +int jk_map_alloc(jk_map_t **m) +{ + if (m) { + return jk_map_open(*m = (jk_map_t *)malloc(sizeof(jk_map_t))); + } + + return JK_FALSE; +} + +int jk_map_free(jk_map_t **m) +{ + int rc = JK_FALSE; + + if (m && *m) { + jk_map_close(*m); + free(*m); + *m = NULL; + } + + return rc; +} + +int jk_map_open(jk_map_t *m) +{ + int rc = JK_FALSE; + + if (m) { + jk_open_pool(&m->p, m->buf, sizeof(jk_pool_atom_t) * SMALL_POOL_SIZE); + m->capacity = 0; + m->size = 0; + m->keys = NULL; + m->names = NULL; + m->values = NULL; + rc = JK_TRUE; + } + + return rc; +} + +int jk_map_close(jk_map_t *m) +{ + int rc = JK_FALSE; + + if (m) { + jk_close_pool(&m->p); + rc = JK_TRUE; + } + + return rc; +} + +void *jk_map_get(jk_map_t *m, const char *name, const void *def) +{ + const void *rc = (void *)def; + + if (m && name) { + unsigned int i; + unsigned int key; + COMPUTE_KEY_CHECKSUM(name, key) + for (i = 0; i < m->size; i++) { + if (m->keys[i] == key && strcmp(m->names[i], name) == 0) { + rc = m->values[i]; + break; + } + } + } + + return (void *)rc; /* DIRTY */ +} + +int jk_map_get_id(jk_map_t *m, const char *name) +{ + int rc = -1; + if (m && name) { + unsigned int i; + unsigned int key; + COMPUTE_KEY_CHECKSUM(name, key) + for (i = 0; i < m->size; i++) { + if (m->keys[i] == key && strcmp(m->names[i], name) == 0) { + rc = i; + break; + } + } + } + + return rc; +} + +const char *jk_map_get_string(jk_map_t *m, const char *name, const char *def) +{ + const char *rc = def; + + if (m && name) { + unsigned int i; + unsigned int key; + COMPUTE_KEY_CHECKSUM(name, key) + for (i = 0; i < m->size; i++) { + if (m->keys[i] == key && strcmp(m->names[i], name) == 0) { + rc = m->values[i]; + break; + } + } + } + + return rc; +} + + +int jk_map_get_int(jk_map_t *m, const char *name, int def) +{ + char buf[100]; + const char *rc; + size_t len; + int int_res; + int multit = 1; + + sprintf(buf, "%d", def); + rc = jk_map_get_string(m, name, buf); + + len = strlen(rc); + if (len) { + char *lastchar = &buf[0] + len - 1; + strcpy(buf, rc); + if ('m' == *lastchar || 'M' == *lastchar) { + *lastchar = '\0'; + multit = 1024 * 1024; + } + else if ('k' == *lastchar || 'K' == *lastchar) { + *lastchar = '\0'; + multit = 1024; + } + int_res = atoi(buf); + } + else + int_res = def; + + return int_res * multit; +} + +double jk_map_get_double(jk_map_t *m, const char *name, double def) +{ + char buf[100]; + const char *rc; + + sprintf(buf, "%f", def); + rc = jk_map_get_string(m, name, buf); + + return atof(rc); +} + +int jk_map_get_bool(jk_map_t *m, const char *name, int def) +{ + char buf[100]; + const char *rc; + + sprintf(buf, "%d", def); + rc = jk_map_get_string(m, name, buf); + + return jk_get_bool_code(rc, def); +} + +char **jk_map_get_string_list(jk_map_t *m, + const char *name, + unsigned int *list_len, const char *def) +{ + const char *l = jk_map_get_string(m, name, def); + char **ar = NULL; + +#ifdef _MT_CODE_PTHREAD + char *lasts; +#endif + + *list_len = 0; + + if (l) { + unsigned capacity = 0; + unsigned idex = 0; + char *p; + char *v = jk_pool_strdup(&m->p, l); + + if (!v) { + return NULL; + } + + /* + * GS, in addition to VG's patch, we now need to + * strtok also by a "*" + */ +#ifdef _MT_CODE_PTHREAD + for (p = strtok_r(v, " \t,", &lasts); + p; p = strtok_r(NULL, " \t,", &lasts)) +#else + for (p = strtok(v, " \t,"); p; p = strtok(NULL, " \t,")) +#endif + + { + + if (idex == capacity) { + ar = jk_pool_realloc(&m->p, + sizeof(char *) * (capacity + 5), + ar, sizeof(char *) * capacity); + if (!ar) { + return JK_FALSE; + } + capacity += 5; + } + ar[idex] = jk_pool_strdup(&m->p, p); + idex++; + } + + *list_len = idex; + } + + return ar; +} + +int jk_map_get_int_list(jk_map_t *m, + const char *name, + int *list, + unsigned int list_len, + const char *def) +{ + const char *l = jk_map_get_string(m, name, def); + +#ifdef _MT_CODE_PTHREAD + char *lasts; +#endif + + if (!list_len) + return 0; + + if (l) { + unsigned int capacity = list_len; + unsigned int index = 0; + char *p; + char *v = jk_pool_strdup(&m->p, l); + + if (!v) { + return 0; + } + + /* + * GS, in addition to VG's patch, we now need to + * strtok also by a "*" + */ +#ifdef _MT_CODE_PTHREAD + for (p = strtok_r(v, " \t,", &lasts); + p; p = strtok_r(NULL, " \t,", &lasts)) +#else + for (p = strtok(v, " \t,"); p; p = strtok(NULL, " \t,")) +#endif + + { + if (index < capacity) { + list[index] = atoi(p); + index++; + } + else + break; + } + return index; + } + return 0; +} + +int jk_map_add(jk_map_t *m, const char *name, const void *value) +{ + int rc = JK_FALSE; + + if (m && name) { + unsigned int key; + COMPUTE_KEY_CHECKSUM(name, key) + map_realloc(m); + + if (m->size < m->capacity) { + m->values[m->size] = value; + m->names[m->size] = jk_pool_strdup(&m->p, name); + m->keys[m->size] = key; + m->size++; + rc = JK_TRUE; + } + } + + return rc; +} + +int jk_map_put(jk_map_t *m, const char *name, const void *value, void **old) +{ + int rc = JK_FALSE; + + if (m && name) { + unsigned int i; + unsigned int key; + COMPUTE_KEY_CHECKSUM(name, key) + for (i = 0; i < m->size; i++) { + if (m->keys[i] == key && strcmp(m->names[i], name) == 0) { + break; + } + } + + if (i < m->size) { + if (old) + *old = (void *)m->values[i]; /* DIRTY */ + m->values[i] = value; + rc = JK_TRUE; + } + else { + rc = jk_map_add(m, name, value); + } + } + + return rc; +} + + +static int jk_map_validate_property(char *prp, jk_logger_t *l) +{ + /* check the worker properties */ + if (!jk_is_valid_property(prp)) { + jk_log(l, JK_LOG_ERROR, + "The attribute '%s' is not supported - please check" + " the documentation for the supported attributes.", + prp); + return JK_FALSE; + } + if (jk_is_deprecated_property(prp)) { + jk_log(l, JK_LOG_WARNING, + "The attribute '%s' is deprecated - please check" + " the documentation for the correct replacement.", + prp); + } + return JK_TRUE; +} + +static int jk_map_handle_duplicates(jk_map_t *m, const char *prp, char **v, + int treatment, jk_logger_t *l) +{ + const char *oldv = jk_map_get_string(m, prp, NULL); + if (oldv) { + if ((treatment == JK_MAP_HANDLE_DUPLICATES) + && jk_is_unique_property(prp) == JK_FALSE) { + char *tmpv = jk_pool_alloc(&m->p, + strlen(*v) + strlen(oldv) + 3); + if (tmpv) { + char sep = '*'; + if (jk_is_path_property(prp)) + sep = PATH_SEPERATOR; + else if (jk_is_cmd_line_property(prp)) + sep = ' '; + else if (jk_is_list_property(prp)) + sep = ','; + sprintf(tmpv, "%s%c%s", oldv, sep, *v); + } + *v = tmpv; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Concatenated value is: %s -> %s", + prp, *v); + return JK_FALSE; + } + else { + jk_log(l, JK_LOG_WARNING, + "Duplicate key '%s' detected - previous value '%s'" + " will be overwritten with '%s'.", + prp, oldv ? oldv : "(null)", v ? *v : "(null)"); + return JK_TRUE; + } + } + else { + return JK_TRUE; + } +} + +int jk_map_read_property(jk_map_t *m, jk_map_t *env, const char *str, + int treatment, jk_logger_t *l) +{ + int rc = JK_TRUE; + char buf[LENGTH_OF_LINE + 1]; + char *prp = &buf[0]; + + if (strlen(str) > LENGTH_OF_LINE) { + jk_log(l, JK_LOG_WARNING, + "Line to long (%d > %d), ignoring entry", + strlen(str), LENGTH_OF_LINE); + return JK_FALSE; + } + + strcpy(prp, str); + if (trim(prp)) { + char *v = strchr(prp, '='); + if (v) { + *v = '\0'; + v++; + if (trim(v) && trim(prp)) { + if (treatment == JK_MAP_HANDLE_RAW) { + v = jk_pool_strdup(&m->p, v); + } + else { + if (jk_map_validate_property(prp, l) == JK_FALSE) + return JK_FALSE; + v = jk_map_replace_properties(m, env, v); + if (jk_map_handle_duplicates(m, prp, &v, treatment, l) == JK_TRUE) + v = jk_pool_strdup(&m->p, v); + } + if (v) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Adding property '%s' with value '%s' to map.", + prp, v); + jk_map_put(m, prp, v, NULL); + } + else { + JK_LOG_NULL_PARAMS(l); + rc = JK_FALSE; + } + } + } + } + return rc; +} + + +int jk_map_read_properties(jk_map_t *m, jk_map_t *env, const char *f, time_t *modified, + int treatment, jk_logger_t *l) +{ + int rc = JK_FALSE; + + if (m && f) { + struct stat statbuf; + FILE *fp; + if (jk_stat(f, &statbuf) == -1) + return JK_FALSE; +#if defined(AS400) && !defined(AS400_UTF8) + fp = fopen(f, "r, o_ccsid=0"); +#else + fp = fopen(f, "r"); +#endif + + if (fp) { + char buf[LENGTH_OF_LINE + 1]; + char *prp; + + rc = JK_TRUE; + + while (NULL != (prp = fgets(buf, LENGTH_OF_LINE, fp))) { + trim_prp_comment(prp); + if (*prp) { + if ((rc = jk_map_read_property(m, env, prp, treatment, l)) == JK_FALSE) + break; + } + } + fclose(fp); + if (modified) + *modified = statbuf.st_mtime; + } + } + + return rc; +} + + +int jk_map_size(jk_map_t *m) +{ + if (m) { + return m->size; + } + + return -1; +} + +const char *jk_map_name_at(jk_map_t *m, int idex) +{ + if (m && idex >= 0) { + return m->names[idex]; /* DIRTY */ + } + + return NULL; +} + +void *jk_map_value_at(jk_map_t *m, int idex) +{ + if (m && idex >= 0) { + return (void *)m->values[idex]; /* DIRTY */ + } + + return NULL; +} + +void jk_map_dump(jk_map_t *m, jk_logger_t *l) +{ + if (m) { + int s = jk_map_size(m); + int i; + for (i=0;i<s;i++) { + if (!jk_map_name_at(m, i)) { + jk_log(l, JK_LOG_WARNING, + "Map contains empty name at index %d\n", i); + } + if (!jk_map_value_at(m, i)) { + jk_log(l, JK_LOG_WARNING, + "Map contains empty value for name '%s' at index %d\n", + jk_map_name_at(m, i), i); + } + if (JK_IS_DEBUG_LEVEL(l)) { + jk_log(l, JK_LOG_DEBUG, + "Dump of map: '%s' -> '%s'", + jk_map_name_at(m, i) ? jk_map_name_at(m, i) : "(null)", + jk_map_value_at(m, i) ? jk_map_value_at(m, i) : "(null)"); + } + } + } +} + +int jk_map_copy(jk_map_t *src, jk_map_t *dst) +{ + int sz = jk_map_size(src); + int i; + for (i = 0; i < sz; i++) { + const char *name = jk_map_name_at(src, i); + if (jk_map_get(dst, name, NULL) == NULL) { + if (!jk_map_put(dst, name, + jk_pool_strdup(&dst->p, jk_map_get_string(src, name, NULL)), + NULL)) { + return JK_FALSE; + } + } + } + return JK_TRUE; +} + + +static void trim_prp_comment(char *prp) +{ +#if defined(AS400) && !defined(AS400_UTF8) + char *comment; + /* lots of lines that translate a '#' realtime deleted */ + comment = strchr(prp, *APR_NUMBERSIGN); +#else + char *comment = strchr(prp, '#'); +#endif + if (comment) { + *comment = '\0'; + } +} + +static size_t trim(char *s) +{ + size_t first; + size_t len; + + /* check for empty strings */ + if (!(len = strlen(s))) + return 0; + for (len = len - 1; (len > 0) && + isspace((int)((unsigned char)s[len])); len--); + if ((len > 0) || !isspace((int)((unsigned char)s[len]))) { + len++; + } + + s[len] = '\0'; + len++; + + for (first = 0; (s[first] != '\0') && + isspace((int)((unsigned char)s[first])); first++); + + if (first > 0) { + memmove(s, s + first, len - first); + } + + return len; +} + +static int map_realloc(jk_map_t *m) +{ + if (m->size == m->capacity) { + char **names; + void **values; + unsigned int *keys; + int capacity = m->capacity + CAPACITY_INC_SIZE; + + names = (char **)jk_pool_alloc(&m->p, sizeof(char *) * capacity); + values = (void **)jk_pool_alloc(&m->p, sizeof(void *) * capacity); + keys = (unsigned int *)jk_pool_alloc(&m->p, sizeof(unsigned int) * capacity); + + if (values && names) { + if (m->capacity && m->names) + memcpy(names, m->names, sizeof(char *) * m->capacity); + + if (m->capacity && m->values) + memcpy(values, m->values, sizeof(void *) * m->capacity); + + if (m->capacity && m->keys) + memcpy(keys, m->keys, sizeof(unsigned int) * m->capacity); + + m->names = (const char **)names; + m->values = (const void **)values; + m->keys = keys; + m->capacity = capacity; + + return JK_TRUE; + } + } + + return JK_FALSE; +} + +/** + * Replace $(property) in value. + * + */ +static char *jk_map_replace_properties(jk_map_t *m, jk_map_t *env, char *value) +{ + char *rc = value; + char *env_start = rc; + int rec = 0; + + while ((env_start = strstr(env_start, "$(")) != NULL) { + char *env_end = strstr(env_start, ")"); + if (rec++ > 20) + return rc; + if (env_end) { + char env_name[LENGTH_OF_LINE + 1] = ""; + const char *env_value; +#if defined(WIN32) + char env_buf[LENGTH_OF_LINE + 1]; +#endif + *env_end = '\0'; + strcpy(env_name, env_start + 2); + *env_end = ')'; + + env_value = jk_map_get_string(m, env_name, NULL); + if (!env_value) { + env_value = getenv(env_name); + } + if (!env_value && env) { + /* Search inside local environment table */ + env_value = jk_map_get_string(env, env_name, NULL); + } + +#if defined(WIN32) + if (!env_value) { + /* Try the env block from calling process */ + if (GetEnvironmentVariable(env_name, env_buf, + sizeof(env_buf))) + env_value = &env_buf[0]; + } +#endif + if (env_value) { + size_t offset = 0; + char *new_value = jk_pool_alloc(&m->p, + (sizeof(char) * + (strlen(rc) + + strlen(env_value)))); + if (!new_value) { + break; + } + *env_start = '\0'; + strcpy(new_value, rc); + strcat(new_value, env_value); + strcat(new_value, env_end + 1); + offset = env_start - rc + strlen(env_value); + rc = new_value; + /* Avoid recursive subst */ + env_start = rc + offset; + } + else { + env_start = env_end; + } + } + else { + break; + } + } + + return rc; +} + +/** + * Resolve references + * + */ +int jk_map_resolve_references(jk_map_t *m, const char *prefix, + int wildcard, int depth, jk_logger_t *l) +{ + int rc = JK_FALSE; + + JK_TRACE_ENTER(l); + + if (m && prefix) { + if (depth <= JK_MAP_RECURSION) { + size_t prelen = strlen(prefix); + unsigned int i; + rc = JK_TRUE; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Checking for references with prefix %s with%s wildcard (recursion %d)", + prefix, wildcard? "" : "out", depth); + for (i = 0; i < m->size; i++) { + char *v = (char *)m->values[i]; + if (v && *v && + !strncmp(m->names[i], prefix, prelen)) { + size_t remain = strlen(m->names[i]) - prelen; + if ((remain == JK_MAP_REFERENCE_SZ ) || (wildcard && remain > JK_MAP_REFERENCE_SZ)) { + remain = strlen(m->names[i]) - JK_MAP_REFERENCE_SZ; + if (!strncmp(m->names[i] + remain, JK_MAP_REFERENCE, JK_MAP_REFERENCE_SZ)) { + char *from = jk_pool_alloc(&m->p, + (sizeof(char) * + (strlen(v) + 2))); + char *to = jk_pool_alloc(&m->p, + (sizeof(char) * + (remain + 2))); + if (!from || !to) { + jk_log(l, JK_LOG_ERROR, + "Error in string allocation"); + rc = JK_FALSE; + break; + } + strcpy(from, v); + *(from+strlen(v)) = '.'; + *(from+strlen(v)+1) = '\0'; + strncpy(to, m->names[i], remain); + *(to+remain) = '.'; + *(to+remain+1) = '\0'; + + rc = jk_map_resolve_references(m, v, 0, depth+1, l); + if (rc == JK_FALSE) { + break; + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Copying values from %s to %s", + from, to); + rc = jk_map_inherit_properties(m, from, to, l); + if (rc == JK_FALSE) { + break; + } + } + } + } + } + } + else { + jk_log(l, JK_LOG_ERROR, + "Recursion limit %d for worker references with prefix '%s' reached", + JK_MAP_RECURSION, prefix); + } + } + else { + JK_LOG_NULL_PARAMS(l); + } + JK_TRACE_EXIT(l); + return rc; +} + +/** + * Inherit properties + * + */ +int jk_map_inherit_properties(jk_map_t *m, const char *from, const char *to, jk_logger_t *l) +{ + int rc = JK_FALSE; + const char *prp; + char *to_prp; + + if (m && from && to) { + unsigned int i; + for (i = 0; i < m->size; i++) { + if (!strncmp(m->names[i], from, strlen(from))) { + rc = JK_TRUE; + prp = m->names[i] + strlen(from); + to_prp = jk_pool_alloc(&m->p, + (sizeof(char) * + (strlen(to) + + strlen(prp) + 1))); + if (!to_prp) { + jk_log(l, JK_LOG_ERROR, + "Error in string allocation for attribute '%s.%s'", + to, prp); + rc = JK_FALSE; + break; + } + strcpy(to_prp, to); + strcat(to_prp, prp); + if (jk_map_get_id(m, to_prp) < 0 ) { + rc = jk_map_add(m, to_prp, m->values[i]); + if (rc == JK_FALSE) { + jk_log(l, JK_LOG_ERROR, + "Error when adding attribute '%s'", + to_prp); + break; + } + } + } + } + if ( rc == JK_FALSE) { + jk_log(l, JK_LOG_ERROR, + "Reference '%s' not found", + from); + } + } + else { + JK_LOG_NULL_PARAMS(l); + } + return rc; +} diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_map.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_map.h new file mode 100644 index 00000000..6e88861d --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_map.h @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Map object header file * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Version: $Revision: 756058 $ * + ***************************************************************************/ + +#ifndef JK_MAP_H +#define JK_MAP_H + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#define JK_MAP_HANDLE_NORMAL 0 +#define JK_MAP_HANDLE_DUPLICATES 1 +#define JK_MAP_HANDLE_RAW 2 + +struct jk_map; +typedef struct jk_map jk_map_t; + +int jk_map_alloc(jk_map_t **m); + +int jk_map_free(jk_map_t **m); + +int jk_map_open(jk_map_t *m); + +int jk_map_close(jk_map_t *m); + +void *jk_map_get(jk_map_t *m, const char *name, const void *def); + +int jk_map_get_id(jk_map_t *m, const char *name); + +int jk_map_get_int(jk_map_t *m, const char *name, int def); + +double jk_map_get_double(jk_map_t *m, const char *name, double def); + +int jk_map_get_bool(jk_map_t *m, const char *name, int def); + +const char *jk_map_get_string(jk_map_t *m, const char *name, const char *def); + +char **jk_map_get_string_list(jk_map_t *m, + const char *name, + unsigned *list_len, const char *def); + +int jk_map_get_int_list(jk_map_t *m, + const char *name, + int *list, unsigned int list_len, + const char *def); + +int jk_map_add(jk_map_t *m, const char *name, const void *value); + +int jk_map_put(jk_map_t *m, const char *name, const void *value, void **old); + +int jk_map_read_property(jk_map_t *m, jk_map_t *env, const char *str, int treatment, jk_logger_t *l); + +int jk_map_read_properties(jk_map_t *m, jk_map_t *env, const char *f, time_t *modified, int treatment, jk_logger_t *l); + +int jk_map_size(jk_map_t *m); + +const char *jk_map_name_at(jk_map_t *m, int idex); + +void *jk_map_value_at(jk_map_t *m, int idex); + +void jk_map_dump(jk_map_t *m, jk_logger_t *l); + +int jk_map_copy(jk_map_t *src, jk_map_t *dst); + +int jk_map_resolve_references(jk_map_t *m, const char *prefix, int wildcard, int depth, jk_logger_t *l); + +int jk_map_inherit_properties(jk_map_t *m, const char *from, const char *to, jk_logger_t *l); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* JK_MAP_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_map.lo b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_map.lo new file mode 100644 index 00000000..137e8eac --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_map.lo @@ -0,0 +1,12 @@ +# jk_map.lo - a libtool object file +# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/jk_map.o' + +# Name of the non-PIC object. +non_pic_object='jk_map.o' + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_map.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_map.o Binary files differnew file mode 100644 index 00000000..5274ff78 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_map.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_md5.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_md5.c new file mode 100644 index 00000000..1edcd073 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_md5.c @@ -0,0 +1,475 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This is work is derived from material Copyright RSA Data Security, Inc. + * + * The RSA copyright statement and Licence for that original material is + * included below. This is followed by the Apache copyright statement and + * licence for the modifications made to that material. + */ + +/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD5 Message-Digest + Algorithm" in all material mentioning or referencing this software + or this function. + + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD5 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. + */ + +/* + * The ap_MD5Encode() routine uses much code obtained from the FreeBSD 3.0 + * MD5 crypt() function, which is licenced as follows: + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + */ + +/*************************************************************************** + * Description: MD5 encoding wrapper * + * Author: Henri Gomez <hgomez@apache.org> * + * Version: $Revision: 466585 $ * + ***************************************************************************/ + +/* + * JK MD5 Encoding function (jk_MD5Encode) + * + * Jk delegate MD5 encoding to ap_MD5Encode when used in Apache Web-Server. + * When another web-server is used like NES/IIS, we should use corresponding calls. + * NES/IIS specialists will add the necessary code but until that, I reused the code + * from Apache HTTP server. + * + * Nota: If you use an EBCDIC system without Apache, you'll have to use MD5 encoding + * corresponding call or have a ebcdic2ascii() functions somewhere. + * For example current AS/400 have MD5 encoding support APIs but olders not.... + */ + +#include "jk_global.h" +#include "jk_md5.h" + +char *JK_METHOD jk_hextocstr(unsigned char *org, char *dst, int n) +{ + char *os = dst; + unsigned char v; + static unsigned char zitohex[] = "0123456789ABCDEF"; + + while (--n >= 0) { + v = *org++; + *dst++ = zitohex[v >> 4]; + *dst++ = zitohex[v & 0x0f]; + } + *dst = 0; + + return (os); +} + +#ifndef USE_APACHE_MD5 + +/* Constants for MD5Transform routine. + */ + +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static void MD5Transform(jk_uint32_t state[4], const unsigned char block[64]); +static void Encode(unsigned char *output, const jk_uint32_t * input, size_t len); +static void Decode(jk_uint32_t * output, const unsigned char *input, size_t len); +static void jk_MD5Init(JK_MD5_CTX * context); +static void jk_MD5Update(JK_MD5_CTX * context, const unsigned char *input, + size_t inputLen); +/*static void jk_MD5Final(unsigned char digest[JK_MD5_DIGESTSIZE], JK_MD5_CTX *context);*/ + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. + Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (jk_uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (jk_uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (jk_uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (jk_uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/* MD5 initialization. Begins an MD5 operation, writing a new context. + */ +static void jk_MD5Init(JK_MD5_CTX * context) +{ + context->count[0] = context->count[1] = 0; + /* Load magic initialization constants. */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. + */ +static void jk_MD5Update(JK_MD5_CTX * context, const unsigned char *input, + size_t inputLen) +{ + size_t i, idx, partLen; + + /* Compute number of bytes mod 64 */ + idx = (size_t) ((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((jk_uint32_t) inputLen << 3)) + < ((jk_uint32_t) inputLen << 3)) { + context->count[1]++; + } + context->count[1] += (jk_uint32_t) inputLen >> 29; + + partLen = 64 - idx; + + /* Transform as many times as possible. */ +#ifndef CHARSET_EBCDIC + if (inputLen >= partLen) { + memcpy(&context->buffer[idx], input, partLen); + MD5Transform(context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) { + MD5Transform(context->state, &input[i]); + } + + idx = 0; + } + else { + i = 0; + } + + /* Buffer remaining input */ + memcpy(&context->buffer[idx], &input[i], inputLen - i); +#else /*CHARSET_EBCDIC */ + if (inputLen >= partLen) { + ebcdic2ascii(&context->buffer[idx], input, partLen); + MD5Transform(context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) { + unsigned char inp_tmp[64]; + ebcdic2ascii(inp_tmp, &input[i], 64); + MD5Transform(context->state, inp_tmp); + } + + idx = 0; + } + else { + i = 0; + } + + /* Buffer remaining input */ + ebcdic2ascii(&context->buffer[idx], &input[i], inputLen - i); +#endif /*CHARSET_EBCDIC */ +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. + */ +static void JK_METHOD jk_MD5Final(unsigned char digest[16], JK_MD5_CTX * context) +{ + unsigned char bits[8]; + size_t idx, padLen; + + + /* Save number of bits */ + Encode(bits, context->count, 8); + +#ifdef CHARSET_EBCDIC + /* XXX: @@@: In order to make this no more complex than necessary, + * this kludge converts the bits[] array using the ascii-to-ebcdic + * table, because the following jk_MD5Update() re-translates + * its input (ebcdic-to-ascii). + * Otherwise, we would have to pass a "conversion" flag to jk_MD5Update() + */ + ascii2ebcdic(bits, bits, 8); + + /* Since everything is converted to ascii within jk_MD5Update(), + * the initial 0x80 (PADDING[0]) must be stored as 0x20 + */ + ascii2ebcdic(PADDING, PADDING, 1); +#endif /*CHARSET_EBCDIC */ + + /* Pad out to 56 mod 64. */ + idx = (size_t) ((context->count[0] >> 3) & 0x3f); + padLen = (idx < 56) ? (56 - idx) : (120 - idx); + jk_MD5Update(context, (const unsigned char *)PADDING, padLen); + + /* Append length (before padding) */ + jk_MD5Update(context, (const unsigned char *)bits, 8); + + /* Store state in digest */ + Encode(digest, context->state, 16); + + /* Zeroize sensitive information. */ + memset(context, 0, sizeof(*context)); +} + +/* MD5 basic transformation. Transforms state based on block. */ +static void MD5Transform(jk_uint32_t state[4], const unsigned char block[64]) +{ + jk_uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode(x, block, 64); + + /* Round 1 */ + FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ + FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ + FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */ + FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ + FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ + FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ + FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ + FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ + FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ + FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ + FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ + GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ + GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ + GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ + GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ + GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ + GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ + GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ + GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ + GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ + GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ + HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ + HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ + HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ + HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ + HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ + HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ + HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ + HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ + HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */ + II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ + II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ + II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ + II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ + II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ + II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ + II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ + II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ + II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. */ + memset(x, 0, sizeof(x)); +} + +/* Encodes input (jk_uint32_t) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void Encode(unsigned char *output, const jk_uint32_t * input, size_t len) +{ + size_t i, j; + jk_uint32_t k; + + for (i = 0, j = 0; j < len; i++, j += 4) { + k = input[i]; + output[j] = (unsigned char)(k & 0xff); + output[j + 1] = (unsigned char)((k >> 8) & 0xff); + output[j + 2] = (unsigned char)((k >> 16) & 0xff); + output[j + 3] = (unsigned char)((k >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (jk_uint32_t). Assumes len is + * a multiple of 4. + */ +static void Decode(jk_uint32_t * output, const unsigned char *input, size_t len) +{ + size_t i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((jk_uint32_t) input[j]) | (((jk_uint32_t) input[j + 1]) << 8) | + (((jk_uint32_t) input[j + 2]) << 16) | (((jk_uint32_t) input[j + 3]) << + 24); +} + +char *JK_METHOD jk_md5(const unsigned char *org, const unsigned char *org2, + char *dst) +{ + JK_MD5_CTX ctx; + char buf[JK_MD5_DIGESTSIZE + 1]; + + jk_MD5Init(&ctx); + jk_MD5Update(&ctx, org, strlen((const char *)org)); + + if (org2 != NULL) + jk_MD5Update(&ctx, org2, strlen((const char *)org2)); + + jk_MD5Final((unsigned char *)buf, &ctx); + return (jk_hextocstr((unsigned char *)buf, dst, JK_MD5_DIGESTSIZE)); +} + +#else /* USE_APACHE_MD5 */ + +#include "httpd.h" +#include "http_config.h" + +#ifdef STANDARD20_MODULE_STUFF + +#include "apr_md5.h" +#define AP_MD5_CTX apr_md5_ctx_t +#define ap_MD5Init apr_md5_init +#define ap_MD5Update apr_md5_update +#define ap_MD5Final apr_md5_final + +#else /* STANDARD20_MODULE_STUFF */ + +#include "ap_md5.h" + +#endif /* STANDARD20_MODULE_STUFF */ + +char *JK_METHOD jk_md5(const unsigned char *org, const unsigned char *org2, + char *dst) +{ + AP_MD5_CTX ctx; + char buf[JK_MD5_DIGESTSIZE + 1]; + + ap_MD5Init(&ctx); + ap_MD5Update(&ctx, org, strlen((const char *)org)); + + if (org2 != NULL) + ap_MD5Update(&ctx, org2, strlen((const char *)org2)); + + ap_MD5Final((unsigned char *)buf, &ctx); + return (jk_hextocstr((unsigned char *)buf, dst, JK_MD5_DIGESTSIZE)); +} + +#endif /* USE_APACHE_MD5 */ + +/* Test values: + * "" D4 1D 8C D9 8F 00 B2 04 E9 80 09 98 EC F8 42 7E + * "a" 0C C1 75 B9 C0 F1 B6 A8 31 C3 99 E2 69 77 26 61 + * "abc 90 01 50 98 3C D2 4F B0 D6 96 3F 7D 28 E1 7F 72 + * "message digest" F9 6B 69 7D 7C B7 93 8D 52 5A 2F 31 AA F1 61 D0 + * + */ + +#ifdef TEST_JKMD5 + +main(int argc, char **argv) +{ + char xxx[(2 * JK_MD5_DIGESTSIZE) + 1]; + + if (argc > 1) + printf("%s => %s\n", argv[1], jk_md5(argv[1], NULL, xxx)); +} + +#endif diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_md5.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_md5.h new file mode 100644 index 00000000..f740048b --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_md5.h @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This is work is derived from material Copyright RSA Data Security, Inc. + * + * The RSA copyright statement and Licence for that original material is + * included below. This is followed by the Apache copyright statement and + * licence for the modifications made to that material. + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD5 Message-Digest + Algorithm" in all material mentioning or referencing this software + or this function. + + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD5 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. +*/ + +#ifndef JK_APACHE_MD5_H +#define JK_APACHE_MD5_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* MD5.H - header file for MD5.C */ + +#define JK_MD5_DIGESTSIZE 16 + +/* MD5 context. */ +typedef struct +{ + jk_uint32_t state[4]; /* state (ABCD) */ + jk_uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} JK_MD5_CTX; + +/* + * Define the Magic String prefix that identifies a password as being + * hashed using our algorithm. + */ +#define JK_MD5PW_ID "$apr1$" +#define JK_MD5PW_IDLEN 6 + +char *JK_METHOD jk_hextocstr(unsigned char *org, char *dst, int n); +char *JK_METHOD jk_md5(const unsigned char *org, + const unsigned char *org2, char *dst); + + +#ifdef __cplusplus +} +#endif + +#endif /* !JK_APACHE_MD5_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_md5.lo b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_md5.lo new file mode 100644 index 00000000..c6617e56 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_md5.lo @@ -0,0 +1,12 @@ +# jk_md5.lo - a libtool object file +# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/jk_md5.o' + +# Name of the non-PIC object. +non_pic_object='jk_md5.o' + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_md5.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_md5.o Binary files differnew file mode 100644 index 00000000..d3a98259 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_md5.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_msg_buff.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_msg_buff.c new file mode 100644 index 00000000..955fd5ab --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_msg_buff.c @@ -0,0 +1,382 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Data marshaling. XDR like * + * Author: Costin <costin@costin.dnt.ro> * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Author: Henri Gomez <hgomez@apache.org> * + * Version: $Revision: 705882 $ * + ***************************************************************************/ + +#include "jk_pool.h" +#include "jk_connect.h" +#include "jk_util.h" +#include "jk_sockbuf.h" +#include "jk_msg_buff.h" +#include "jk_logger.h" + +static char *jk_HEX = "0123456789ABCDEFX"; + +/* + * Simple marshaling code. + */ + +void jk_b_reset(jk_msg_buf_t *msg) +{ + msg->len = 4; + msg->pos = 4; + if (msg->buf && msg->maxlen) { + /* Clear the message buffer */ + memset(msg->buf, 0, msg->maxlen); + } +} + +int jk_b_append_long(jk_msg_buf_t *msg, unsigned long val) +{ + if (msg->len + 4 > msg->maxlen) { + return -1; + } + + msg->buf[msg->len++] = (unsigned char)((val >> 24) & 0xFF); + msg->buf[msg->len++] = (unsigned char)((val >> 16) & 0xFF); + msg->buf[msg->len++] = (unsigned char)((val >> 8) & 0xFF); + msg->buf[msg->len++] = (unsigned char)((val) & 0xFF); + + return 0; +} + + +int jk_b_append_int(jk_msg_buf_t *msg, unsigned short val) +{ + if (msg->len + 2 > msg->maxlen) { + return -1; + } + + msg->buf[msg->len++] = (unsigned char)((val >> 8) & 0xFF); + msg->buf[msg->len++] = (unsigned char)((val) & 0xFF); + + return 0; +} + + +int jk_b_append_byte(jk_msg_buf_t *msg, unsigned char val) +{ + if (msg->len + 1 > msg->maxlen) { + return -1; + } + + msg->buf[msg->len++] = val; + + return 0; +} + + +void jk_b_end(jk_msg_buf_t *msg, int protoh) +{ + /* + * Ugly way to set the size in the right position + */ + int hlen = msg->len - 4; + + msg->buf[0] = (unsigned char)((protoh >> 8) & 0xFF); + msg->buf[1] = (unsigned char)((protoh) & 0xFF); + msg->buf[2] = (unsigned char)((hlen >> 8) & 0xFF); + msg->buf[3] = (unsigned char)((hlen) & 0xFF); + +} + + +jk_msg_buf_t *jk_b_new(jk_pool_t *p) +{ + jk_msg_buf_t *msg = + (jk_msg_buf_t *)jk_pool_alloc(p, sizeof(jk_msg_buf_t)); + + if (!msg) { + return NULL; + } + memset(msg, 0, sizeof(jk_msg_buf_t)); + msg->pool = p; + + return msg; +} + +int jk_b_set_buffer(jk_msg_buf_t *msg, unsigned char *data, int buffSize) +{ + if (!msg) { + return -1; + } + + msg->len = 0; + msg->buf = data; + msg->maxlen = buffSize; + + return 0; +} + + +int jk_b_set_buffer_size(jk_msg_buf_t *msg, int buffSize) +{ + unsigned char *data = (unsigned char *)jk_pool_alloc(msg->pool, buffSize); + + if (!data) { + return -1; + } + + jk_b_set_buffer(msg, data, buffSize); + return 0; +} + +#if defined(AS400) && !defined(AS400_UTF8) +int jk_b_append_asciistring(jk_msg_buf_t *msg, const char *param) +{ + int len; + + if (!param) { + jk_b_append_int(msg, 0xFFFF); + return 0; + } + + len = strlen(param); + if (msg->len + len + 2 > msg->maxlen) { + return -1; + } + + /* ignore error - we checked once */ + jk_b_append_int(msg, (unsigned short)len); + + /* We checked for space !! */ + strncpy((char *)msg->buf + msg->len, param, len + 1); /* including \0 */ + msg->len += len + 1; + + return 0; +} +#endif + +int jk_b_append_string(jk_msg_buf_t *msg, const char *param) +{ + unsigned short len; + + if (!param) { + jk_b_append_int(msg, 0xFFFF); + return 0; + } + + len = (unsigned short)strlen(param); + if (msg->len + len + 3 > msg->maxlen) { + return -1; + } + + /* ignore error - we checked once */ + jk_b_append_int(msg, len); + + /* We checked for space !! */ + memcpy(msg->buf + msg->len, param, len + 1); /* including \0 */ +#if (defined(AS400) && !defined(AS400_UTF8)) || defined(_OSD_POSIX) + /* convert from EBCDIC if needed */ + jk_xlate_to_ascii((char *)msg->buf + msg->len, len + 1); +#endif + msg->len += len + 1; + + return 0; +} + + +int jk_b_append_bytes(jk_msg_buf_t *msg, const unsigned char *param, int len) +{ + if (!len) { + return 0; + } + + if (msg->len + len > msg->maxlen) { + return -1; + } + + /* We checked for space !! */ + memcpy((char *)msg->buf + msg->len, param, len); + msg->len += len; + + return 0; +} + +unsigned long jk_b_get_long(jk_msg_buf_t *msg) +{ + unsigned long i; + if (msg->pos + 3 > msg->len) { + return 0xFFFFFFFF; + } + i = ((msg->buf[(msg->pos++)] & 0xFF) << 24); + i |= ((msg->buf[(msg->pos++)] & 0xFF) << 16); + i |= ((msg->buf[(msg->pos++)] & 0xFF) << 8); + i |= ((msg->buf[(msg->pos++)] & 0xFF)); + return i; +} + +unsigned long jk_b_pget_long(jk_msg_buf_t *msg, int pos) +{ + unsigned long i; + i = ((msg->buf[(pos++)] & 0xFF) << 24); + i |= ((msg->buf[(pos++)] & 0xFF) << 16); + i |= ((msg->buf[(pos++)] & 0xFF) << 8); + i |= ((msg->buf[(pos)] & 0xFF)); + return i; +} + + +unsigned short jk_b_get_int(jk_msg_buf_t *msg) +{ + unsigned short i; + if (msg->pos + 1 > msg->len) { + return 0xFFFF; + } + i = ((msg->buf[(msg->pos++)] & 0xFF) << 8); + i += ((msg->buf[(msg->pos++)] & 0xFF)); + return i; +} + +unsigned short jk_b_pget_int(jk_msg_buf_t *msg, int pos) +{ + unsigned short i; + i = ((msg->buf[pos++] & 0xFF) << 8); + i += ((msg->buf[pos] & 0xFF)); + return i; +} + +unsigned char jk_b_get_byte(jk_msg_buf_t *msg) +{ + unsigned char rc; + if (msg->pos > msg->len) { + return 0xFF; + } + rc = msg->buf[msg->pos++]; + + return rc; +} + +unsigned char jk_b_pget_byte(jk_msg_buf_t *msg, int pos) +{ + return msg->buf[pos]; +} + + +unsigned char *jk_b_get_string(jk_msg_buf_t *msg) +{ + unsigned short size = jk_b_get_int(msg); + int start = msg->pos; + + if ((size == 0xFFFF) || (size + start > msg->maxlen)) { + /* Error of overflow in AJP packet. + * The complete message is probably invalid. + */ + return NULL; + } + + msg->pos += size; + msg->pos++; /* terminating NULL */ + + return (unsigned char *)(msg->buf + start); +} + +int jk_b_get_bytes(jk_msg_buf_t *msg, unsigned char *buf, int len) +{ + int start = msg->pos; + + if ((len < 0) || (len + start > msg->maxlen)) { + return (-1); + } + + memcpy(buf, msg->buf + start, len); + msg->pos += len; + return (len); +} + + + +/** Helpie dump function + */ +void jk_dump_buff(jk_logger_t *l, + const char *file, + int line, const char *funcname, + int level, char *what, jk_msg_buf_t *msg) +{ + int i = 0; + char lb[80]; + char *current; + int j; + int len = msg->len; + + if (l == NULL) + return; + if (l->level != JK_LOG_TRACE_LEVEL && len > 1024) + len = 1024; + + jk_log(l, file, line, funcname, level, + "%s pos=%d len=%d max=%d", + what, msg->pos, msg->len, msg->maxlen); + + for (i = 0; i < len; i += 16) { + current = &lb[0]; + + for (j = 0; j < 16; j++) { + unsigned char x = (msg->buf[i + j]); + if ((i + j) >= len) + x = 0; + *current++ = jk_HEX[x >> 4]; + *current++ = jk_HEX[x & 0x0f]; + *current++ = ' '; + } + *current++ = ' '; + *current++ = '-'; + *current++ = ' '; + for (j = 0; j < 16; j++) { + unsigned char x = msg->buf[i + j]; + if ((i + j) >= len) + x = 0; + if (x > 0x20 && x < 0x7F) { +#ifdef USE_CHARSET_EBCDIC + *current = x; + jk_xlate_from_ascii(current, 1); + current++; +#else + *current++ = x; +#endif + } + else { + *current++ = '.'; + } + } + *current++ = '\0'; + + jk_log(l, file, line, funcname, level, + "%.4x %s", i, lb); + } +} + + +int jk_b_copy(jk_msg_buf_t *smsg, jk_msg_buf_t *dmsg) +{ + if (smsg == NULL || dmsg == NULL) + return (-1); + + if (dmsg->maxlen < smsg->len) + return (-2); + + memcpy(dmsg->buf, smsg->buf, smsg->len); + dmsg->len = smsg->len; + + return (smsg->len); +} diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_msg_buff.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_msg_buff.h new file mode 100644 index 00000000..3fdc006b --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_msg_buff.h @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Data marshaling. XDR like * + * Author: Costin <costin@costin.dnt.ro> * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Version: $Revision: 530674 $ * + ***************************************************************************/ + +#ifndef JK_MSG_BUF_H +#define JK_MSG_BUF_H + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#define DEF_BUFFER_SZ (8 * 1024) + +/* XXX replace all return values with error codes */ +#define ERR_BAD_PACKET -5 + +/* +RPC details: + + - one parameter - use a structure for more. The method + is encoded as part of the request + - one or no result + - + + + + */ + +typedef struct jk_msg_buf_t jk_msg_buf_t; +struct jk_msg_buf_t +{ + jk_pool_t *pool; + unsigned char *buf; + int pos; + int len; + int maxlen; +}; + + +/* -------------------- Setup routines -------------------- */ + +/** Allocate a buffer. + */ +jk_msg_buf_t *jk_b_new(jk_pool_t *p); + +/** Set up a buffer with an existing buffer + */ +int jk_b_set_buffer(jk_msg_buf_t *msg, unsigned char *data, int buffSize); + +/* + * Set up a buffer with a new buffer of buffSize + */ +int jk_b_set_buffer_size(jk_msg_buf_t *msg, int buffSize); + +/* + * Finalize the buffer before sending - set length fields, etc + */ +void jk_b_end(jk_msg_buf_t *msg, int protoh); + +/* + * Recycle the buffer - z for a new invocation + */ +void jk_b_reset(jk_msg_buf_t *msg); + +/* -------------------- Real encoding -------------------- */ + +int jk_b_append_byte(jk_msg_buf_t *msg, unsigned char val); + +int jk_b_append_bytes(jk_msg_buf_t *msg, + const unsigned char *param, int len); + +int jk_b_append_int(jk_msg_buf_t *msg, unsigned short val); + +int jk_b_append_long(jk_msg_buf_t *msg, unsigned long val); + +int jk_b_append_string(jk_msg_buf_t *msg, const char *param); + +#if defined(AS400) && !defined(AS400_UTF8) +int jk_b_append_asciistring(jk_msg_buf_t *msg, const char *param); +#endif + +int jk_b_append_bytes(jk_msg_buf_t *msg, + const unsigned char *param, int len); + +/* -------------------- Decoding -------------------- */ + +/** Get a byte from the current position + */ +unsigned char jk_b_get_byte(jk_msg_buf_t *msg); + +/** Get an int from the current position + */ +unsigned short jk_b_get_int(jk_msg_buf_t *msg); + +/** Get a long from the current position + */ +unsigned long jk_b_get_long(jk_msg_buf_t *msg); + +/** Get a String from the current position + */ +unsigned char *jk_b_get_string(jk_msg_buf_t *msg); + +/** Get Bytes from the current position + */ +int jk_b_get_bytes(jk_msg_buf_t *msg, unsigned char *buf, int len); + +/** Get a byte from an arbitrary position + */ +unsigned char jk_b_pget_byte(jk_msg_buf_t *msg, int pos); + +/** Get an int from an arbitrary position + */ +unsigned short jk_b_pget_int(jk_msg_buf_t *msg, int pos); + +/** Get a long from an arbitrary position + */ +unsigned long jk_b_pget_long(jk_msg_buf_t *msg, int pos); + +/* --------------------- Help ------------------------ */ +void jk_dump_buff(jk_logger_t *l, + const char *file, + int line, const char *funcname, + int level, char *what, jk_msg_buf_t *msg); + +/** Copy a msg buf into another one + */ +int jk_b_copy(jk_msg_buf_t *smsg, jk_msg_buf_t *dmsg); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* JK_MSG_BUF_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_msg_buff.lo b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_msg_buff.lo new file mode 100644 index 00000000..8ea86702 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_msg_buff.lo @@ -0,0 +1,12 @@ +# jk_msg_buff.lo - a libtool object file +# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/jk_msg_buff.o' + +# Name of the non-PIC object. +non_pic_object='jk_msg_buff.o' + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_msg_buff.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_msg_buff.o Binary files differnew file mode 100644 index 00000000..3f0a0391 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_msg_buff.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_mt.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_mt.h new file mode 100644 index 00000000..b5525bb7 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_mt.h @@ -0,0 +1,150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Multi thread portability code for JK * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Version: $Revision: 918711 $ * + ***************************************************************************/ + +#ifndef _JK_MT_H +#define _JK_MT_H + +#include "jk_global.h" + + +#if defined(WIN32) +#define jk_gettid() ((jk_uint32_t)GetCurrentThreadId()) +#elif defined(NETWARE) && !defined(__NOVELL_LIBC__) +#define getpid() ((int)GetThreadGroupID()) +#endif + +#ifdef JK_PREFORK +#define _MT_CODE 0 +#else +#define _MT_CODE 1 +#endif + +/* + * Marks execution under MT compilation + */ +#if _MT_CODE +#ifdef WIN32 +#include <windows.h> + +typedef CRITICAL_SECTION JK_CRIT_SEC; +#define JK_INIT_CS(x, rc) InitializeCriticalSection(x); rc = JK_TRUE +#define JK_DELETE_CS(x, rc) DeleteCriticalSection(x); rc = JK_TRUE +#define JK_ENTER_CS(x, rc) EnterCriticalSection(x); rc = JK_TRUE +#define JK_LEAVE_CS(x, rc) LeaveCriticalSection(x); rc = JK_TRUE + +#else /* !WIN32 */ +#define _MT_CODE_PTHREAD +#include <pthread.h> +#include <unistd.h> +#include <fcntl.h> + +typedef pthread_mutex_t JK_CRIT_SEC; +#define JK_INIT_CS(x, rc)\ + if(pthread_mutex_init(x, NULL)) rc = JK_FALSE; else rc = JK_TRUE + +#define JK_DELETE_CS(x, rc)\ + if(pthread_mutex_destroy(x)) rc = JK_FALSE; else rc = JK_TRUE + +#define JK_ENTER_CS(x, rc)\ + if(pthread_mutex_lock(x)) rc = JK_FALSE; else rc = JK_TRUE + +#define JK_LEAVE_CS(x, rc)\ + if(pthread_mutex_unlock(x)) rc = JK_FALSE; else rc = JK_TRUE + +#if defined(AS400) || defined(NETWARE) +#define jk_pthread_t jk_uint32_t +#endif /* AS400 || NETWARE */ +jk_pthread_t jk_gettid(void); +#endif /* WIN32 */ + +#else /* !_MT_CODE */ + +typedef void *JK_CRIT_SEC; +#define JK_INIT_CS(x, rc) rc = JK_TRUE +#define JK_DELETE_CS(x, rc) rc = JK_TRUE +#define JK_ENTER_CS(x, rc) rc = JK_TRUE +#define JK_LEAVE_CS(x, rc) rc = JK_TRUE +#define jk_gettid() 0 +#endif /* MT_CODE */ + +#if !defined(WIN32) && !defined(NETWARE) +#include <unistd.h> +#include <fcntl.h> + + +#define USE_FLOCK_LK 0 +#if HAVE_FLOCK +#ifdef JK_USE_FLOCK +#define USE_FLOCK_LK 1 +#endif +#endif + +#if USE_FLOCK_LK +#include <sys/file.h> + +#define JK_ENTER_LOCK(x, rc) \ + do { \ + while ((rc = flock((x), LOCK_EX) < 0) && (errno == EINTR)); \ + rc = rc == 0 ? JK_TRUE : JK_FALSE; \ + } while (0) + +#define JK_LEAVE_LOCK(x, rc) \ + do { \ + while ((rc = flock((x), LOCK_UN) < 0) && (errno == EINTR)); \ + rc = rc == 0 ? JK_TRUE : JK_FALSE; \ + } while (0) + +#else /* !USE_FLOCK_LK */ + +#define JK_ENTER_LOCK(x, rc) \ + do { \ + struct flock _fl; \ + _fl.l_type = F_WRLCK; \ + _fl.l_whence = SEEK_SET; \ + _fl.l_start = 0; \ + _fl.l_len = 1L; \ + _fl.l_pid = 0; \ + while ((rc = fcntl((x), F_SETLKW, &_fl) < 0) && (errno == EINTR)); \ + rc = rc == 0 ? JK_TRUE : JK_FALSE; \ + } while (0) + +#define JK_LEAVE_LOCK(x, rc) \ + do { \ + struct flock _fl; \ + _fl.l_type = F_UNLCK; \ + _fl.l_whence = SEEK_SET; \ + _fl.l_start = 0; \ + _fl.l_len = 1L; \ + _fl.l_pid = 0; \ + while ((rc = fcntl((x), F_SETLKW, &_fl) < 0) && (errno == EINTR)); \ + rc = rc == 0 ? JK_TRUE : JK_FALSE; \ + } while (0) + +#endif /* USE_FLOCK_LK */ + +#else /* WIN32 || NETWARE */ +#define JK_ENTER_LOCK(x, rc) rc = JK_TRUE +#define JK_LEAVE_LOCK(x, rc) rc = JK_TRUE +#endif + +#endif /* _JK_MT_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_nwmain.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_nwmain.c new file mode 100644 index 00000000..804de00d --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_nwmain.c @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Netware Wrapper * + * Author: Mike Anderson <mmander@novell.com> * + * Version: $Revision: 466585 $ * + ***************************************************************************/ + +#ifdef NETWARE +/* + * NATIVE_MAIN + */ + +/* + * INCLUDES + */ + +#include <stdio.h> + +/* Apache 2/APR uses NOVELL_LIBC which has a different way of handling + * "library" nlms. If we aren't on LIBC, use the old method + */ + +#ifndef __NOVELL_LIBC__ +#include <nwthread.h> +#include <netdb.h> + +NETDB_DEFINE_CONTEXT +/* + * main () + * + * Main entry point -- don't do much more than I've provided + * + * Entry: + * + * Exit: + * Nothing + */ +void main() +{ + ExitThread(TSR_THREAD, 0); +} +#else /* __NOVELL_LIBC__ */ + +/* Since we are on LibC, we need to handle our own startup and shutdown */ + +#include <netware.h> +#include "novsock2.h" + +int _NonAppStart + (void *NLMHandle, + void *errorScreen, + const char *cmdLine, + const char *loadDirPath, + size_t uninitializedDataLength, + void *NLMFileHandle, + int (*readRoutineP) (int conn, void *fileHandle, size_t offset, + size_t nbytes, size_t * bytesRead, void *buffer), + size_t customDataOffset, + size_t customDataSize, int messageCount, const char **messages) +{ +#pragma unused(cmdLine) +#pragma unused(loadDirPath) +#pragma unused(uninitializedDataLength) +#pragma unused(NLMFileHandle) +#pragma unused(readRoutineP) +#pragma unused(customDataOffset) +#pragma unused(customDataSize) +#pragma unused(messageCount) +#pragma unused(messages) + + WSADATA wsaData; + + return WSAStartup((WORD) MAKEWORD(2, 0), &wsaData); +} + +void _NonAppStop(void) +{ + WSACleanup(); +} + +int _NonAppCheckUnload(void) +{ + return 0; +} +#endif /* __NOVELL_LIBC__ */ + +#endif diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_pool.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_pool.c new file mode 100644 index 00000000..685f75c6 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_pool.c @@ -0,0 +1,165 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Simple memory pool * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Version: $Revision: 466585 $ * + ***************************************************************************/ + +#include "jk_pool.h" + +#define DEFAULT_DYNAMIC 10 + + +static void *jk_pool_dyn_alloc(jk_pool_t *p, size_t size); + + +void jk_open_pool(jk_pool_t *p, jk_pool_atom_t *buf, size_t size) +{ + p->pos = 0; + p->size = size; + p->buf = (char *)buf; + + p->dyn_pos = 0; + p->dynamic = NULL; + p->dyn_size = 0; +} + +void jk_close_pool(jk_pool_t *p) +{ + jk_reset_pool(p); + if (p->dynamic) { + free(p->dynamic); + } +} + +void jk_reset_pool(jk_pool_t *p) +{ + if (p->dyn_pos && p->dynamic) { + size_t i; + for (i = 0; i < p->dyn_pos; i++) { + if (p->dynamic[i]) { + free(p->dynamic[i]); + } + } + } + + p->dyn_pos = 0; + p->pos = 0; +} + +void *jk_pool_alloc(jk_pool_t *p, size_t size) +{ + void *rc = NULL; + + size = JK_ALIGN_DEFAULT(size); + if ((p->size - p->pos) >= size) { + rc = &(p->buf[p->pos]); + p->pos += size; + } + else { + rc = jk_pool_dyn_alloc(p, size); + } + + return rc; +} + +void *jk_pool_realloc(jk_pool_t *p, size_t sz, const void *old, size_t old_sz) +{ + void *rc; + + if (!p || (!old && old_sz)) { + return NULL; + } + + rc = jk_pool_alloc(p, sz); + if (rc) { + memcpy(rc, old, old_sz); + } + + return rc; +} + +void *jk_pool_strdup(jk_pool_t *p, const char *s) +{ + void *rc = NULL; + if (s && p) { + size_t size = strlen(s); + + if (!size) { + return ""; + } + + size++; + rc = jk_pool_alloc(p, size); + if (rc) { + memcpy(rc, s, size); + } + } + + return rc; +} + +#if defined (DEBUG) || defined(_DEBUG) +static void jk_dump_pool(jk_pool_t *p, FILE * f) +{ + fprintf(f, "Dumping for pool [%p]\n", p); + fprintf(f, "size [%ld]\n", p->size); + fprintf(f, "pos [%ld]\n", p->pos); + fprintf(f, "buf [%p]\n", p->buf); + fprintf(f, "dyn_size [%ld]\n", p->dyn_size); + fprintf(f, "dyn_pos [%ld]\n", p->dyn_pos); + fprintf(f, "dynamic [%p]\n", p->dynamic); + + fflush(f); +} +#endif + +static void *jk_pool_dyn_alloc(jk_pool_t *p, size_t size) +{ + void *rc; + + if (p->dyn_size == p->dyn_pos) { + size_t new_dyn_size = p->dyn_size * 2 + DEFAULT_DYNAMIC; + void **new_dynamic = (void **)malloc(new_dyn_size * sizeof(void *)); + if (new_dynamic) { + if (p->dynamic) { + /* Copy old dynamic slots */ + memcpy(new_dynamic, p->dynamic, p->dyn_size * sizeof(void *)); + + free(p->dynamic); + } + + p->dynamic = new_dynamic; + p->dyn_size = new_dyn_size; + } + else { +#if defined (DEBUG) || defined(_DEBUG) + jk_dump_pool(p, stderr); +#endif + return NULL; + } + } + + rc = p->dynamic[p->dyn_pos] = malloc(size); + if (p->dynamic[p->dyn_pos]) { + p->dyn_pos++; + } + + return rc; +} diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_pool.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_pool.h new file mode 100644 index 00000000..b4c582df --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_pool.h @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Memory Pool object header file * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Version: $Revision: 466585 $ * + ***************************************************************************/ +#ifndef _JK_POOL_H +#define _JK_POOL_H + +#include "jk_global.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** + * @file jk_pool.h + * @brief Jk memory allocation + * + * Similar with apr_pools, but completely unsynchronized. + * XXX use same names + * + */ + +/* + * The pool atom (basic pool alocation unit) is an 8 byte long. + * Each allocation (even for 1 byte) will return a round up to the + * number of atoms. + * + * This is to help in alignment of 32/64 bit machines ... + * G.S + */ +#ifdef WIN32 + typedef __int64 jk_pool_atom_t; +#elif defined(AIX) + typedef long long jk_pool_atom_t; +#elif defined(SOLARIS) + typedef long long jk_pool_atom_t; +#elif defined(LINUX) + typedef long long jk_pool_atom_t; +#elif defined(FREEBSD) + typedef long long jk_pool_atom_t; +#elif defined(OS2) + typedef long long jk_pool_atom_t; +#elif defined(NETWARE) + typedef long long jk_pool_atom_t; +#elif defined(HPUX11) + typedef long long jk_pool_atom_t; +#elif defined(IRIX) + typedef long long jk_pool_atom_t; +#elif defined(AS400) + typedef void *jk_pool_atom_t; +#else + typedef long long jk_pool_atom_t; +#endif + +/** + * Alignment macros + */ + +/* JK_ALIGN() is only to be used to align on a power of 2 boundary */ +#define JK_ALIGN(size, boundary) \ + (((size) + ((boundary) - 1)) & ~((boundary) - 1)) + +/** Default alignment */ +#ifdef AS400 +#define JK_ALIGN_DEFAULT(size) JK_ALIGN(size, 16) +#else +#define JK_ALIGN_DEFAULT(size) JK_ALIGN(size, 8) +#endif + +/* + * Pool size in number of pool atoms. + */ +#define TINY_POOL_SIZE 256 /* Tiny 1/4K atom pool. */ +#define SMALL_POOL_SIZE 512 /* Small 1/2K atom pool. */ +#define BIG_POOL_SIZE 2*SMALL_POOL_SIZE /* Bigger 1K atom pool. */ +#define HUGE_POOL_SIZE 2*BIG_POOL_SIZE /* Huge 2K atom pool. */ + +/** jk pool structure */ +struct jk_pool +{ + size_t size; + size_t pos; + char *buf; + size_t dyn_size; + size_t dyn_pos; + void **dynamic; +}; + +typedef struct jk_pool jk_pool_t; + +void jk_open_pool(jk_pool_t *p, jk_pool_atom_t *buf, size_t size); + +void jk_close_pool(jk_pool_t *p); + +void jk_reset_pool(jk_pool_t *p); + +void *jk_pool_alloc(jk_pool_t *p, size_t sz); + +void *jk_pool_realloc(jk_pool_t *p, + size_t sz, const void *old, size_t old_sz); + +void *jk_pool_strdup(jk_pool_t *p, const char *s); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _JK_POOL_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_pool.lo b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_pool.lo new file mode 100644 index 00000000..490290d5 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_pool.lo @@ -0,0 +1,12 @@ +# jk_pool.lo - a libtool object file +# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/jk_pool.o' + +# Name of the non-PIC object. +non_pic_object='jk_pool.o' + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_pool.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_pool.o Binary files differnew file mode 100644 index 00000000..e2e72173 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_pool.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_service.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_service.h new file mode 100644 index 00000000..e99e774b --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_service.h @@ -0,0 +1,546 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Definitions of the objects used during the service step. * + * These are the web server (ws) the worker and the connection* + * JVM connection point * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Author: Dan Milstein <danmil@shore.net> * + * Author: Henri Gomez <hgomez@apache.org> * + * Version: $Revision: 1078846 $ * + ***************************************************************************/ + +#ifndef JK_SERVICE_H +#define JK_SERVICE_H + +#include "jk_global.h" +#include "jk_logger.h" +#include "jk_pool.h" +#include "jk_map.h" +#include "jk_uri_worker_map.h" +#include "jk_msg_buff.h" + +#define JK_RETRIES 2 + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* + * Env Information to be provided to worker at init time + * With AJP14 support we need to have access to many informations + * about web-server, uri to worker map.... + */ + +struct jk_worker_env +{ + + /* The original configuration map */ + jk_map_t *init_data; + + /* The URI to WORKER map, will be feeded by AJP14 autoconf feature */ + jk_uri_worker_map_t *uri_to_worker; + + unsigned int num_of_workers; + char **worker_list; + + /* Web-Server we're running on (Apache/IIS/NES) */ + char *server_name; + + /* Virtual server handled - "*" is all virtual */ + char *virtual; + + /* Optional APR pool used for configuration */ + void *pool; +}; +typedef struct jk_worker_env jk_worker_env_t; + +struct jk_ws_service; +struct jk_endpoint; +struct jk_worker; +typedef struct jk_ws_service jk_ws_service_t; +typedef struct jk_endpoint jk_endpoint_t; +typedef struct jk_worker jk_worker_t; + +struct svc_extension +{ + /* reply_timeout overwrite */ + int reply_timeout; + /* activation state overwrites for load balancers */ + /* Dynamically allocated array with one entry per lb member. */ + int *activation; + /* fail_on_status overwrites */ + /* Number of elements in the array fail_on_status. */ + int fail_on_status_size; + /* Dynamically allocated array with one entry per status. */ + int *fail_on_status; + /* Use server error pages for responses >= 400. */ + int use_server_error_pages; +}; +typedef struct svc_extension svc_extension_t; + +/* + * The web server service 'class'. An instance of this class is created + * for each request which is forwarded from the web server to the servlet + * container. Contains the basic information about the request + * (e.g. protocol, req_uri, etc), and also contains a series of methods + * which provide access to core web server functionality (start_response, + * read, write). This class might be more accurately called ws_request. + * + * As with all the core jk classes, this is essentially an abstract base + * class which is implemented/extended by classes which are specific to a + * particular web server. By using an abstract base class in this manner, + * workers can be written for different protocols (e.g. ajp12, ajp13, ajp14) + * without the workers having to worry about which web server they are + * talking to. + * + * This particular OO-in-C system uses a 'ws_private' pointer to point to + * the platform-specific data. So in the subclasses, the methods do most + * of their work by getting their hands on the ws_private pointer and then + * using that to get at the correctly formatted data and functions for + * their platform. + * + * Try imagining this as a 'public abstract class', and the ws_private + * pointer as a sort of extra 'this' reference. Or imagine that you are + * seeing the internal vtables of your favorite OO language. Whatever + * works for you. + * + * See apache1.3/mod_jk.c and iis/jk_isapi_plugin.c for examples. + */ +struct jk_ws_service +{ + + /* + * A 'this' pointer which is used by the subclasses of this class to + * point to data which is specific to a given web server platform + * (e.g. Apache or IIS). + */ + void *ws_private; + + /* + * Provides memory management. All data specific to this request is + * allocated within this pool, which can then be reclaimed at the end + * of the request handling cycle. + * + * Alive as long as the request is alive. + */ + jk_pool_t *pool; + + /* + * CGI Environment needed by servlets + */ + const char *method; + const char *protocol; + char *req_uri; + const char *remote_addr; + const char *remote_port; + const char *remote_host; + const char *remote_user; + const char *auth_type; + const char *query_string; + const char *server_name; + unsigned server_port; + char *server_software; + jk_uint64_t content_length; /* 64 bit integer that represents the content */ + /* length should be 0 if unknown. */ + unsigned is_chunked; /* 1 if content length is unknown (chunked rq) */ + unsigned no_more_chunks; /* 1 if last chunk has been read */ + jk_uint64_t content_read; /* number of bytes read */ + + /* + * SSL information + * + * is_ssl - True if request is in ssl connection + * ssl_cert - If available, base64 ASN.1 encoded client certificates. + * ssl_cert_len - Length of ssl_cert, 0 if certificates are not available. + * ssl_cipher - The ssl cipher suite in use. + * ssl_session - The ssl session string + * + * In some servers it is impossible to extract all this information, in this + * case, we are passing NULL. + */ + int is_ssl; + char *ssl_cert; + unsigned ssl_cert_len; + char *ssl_cipher; + char *ssl_session; + + /* + * SSL extra information for Servlet 2.3 API + * + * ssl_key_size - ssl key size in use + */ + int ssl_key_size; + + /* + * Headers, names and values. + */ + char **headers_names; /* Names of the request headers */ + char **headers_values; /* Values of the request headers */ + unsigned num_headers; /* Number of request headers */ + + + /* + * Request attributes. + * + * These attributes that were extracted from the web server and are + * sent to Tomcat. + * + * The developer should be able to read them from the ServletRequest + * attributes. Tomcat is required to append org.apache.tomcat. to + * these attrinbute names. + */ + char **attributes_names; /* Names of the request attributes */ + char **attributes_values; /* Values of the request attributes */ + unsigned num_attributes; /* Number of request attributes */ + + /* + * The route is in use when the adapter load balance among + * several workers. It is the ID of a specific target in the load balance + * group. We are using this variable to implement target session + * affinity + */ + const char *route; + + /* + * Activation state of the worker in the load balancer. + * Will be forwarded as a request attribute. + */ + const char *activation; + + /* Temp solution for auth. For native1 it'll be sent on each request, + if an option is present. For native2 it'll be sent with the first + request. On java side, both cases will work. For tomcat3.2 or + a version that doesn't support secret - don't set the secret, + and it'll work. + */ + const char *secret; + + /* + * Area to get POST data for fail-over recovery in POST + */ + jk_msg_buf_t *reco_buf; + int reco_status; + + /* + * If set call flush after each write + */ + int flush_packets; + + /* + * If set call flush after AJP13_SEND_HEADERS. + */ + int flush_header; + + /* + * service extensions + */ + svc_extension_t extension; + + /* + * JK_TRUE if response headers have been sent back + */ + int response_started; + + /* + * JK_TRUE if response should not be send to the client + */ + int response_blocked; + + /* + * HTTP status sent from container. + */ + int http_response_status; + + /* Uri worker map. Added for virtual host support + */ + jk_uri_worker_map_t *uw_map; + + /* + * Callbacks into the web server. For each, the first argument is + * essentially a 'this' pointer. All return JK_TRUE on success + * and JK_FALSE on failure. + */ + /* + * Send the response headers to the browser. + */ + int (JK_METHOD * start_response) (jk_ws_service_t *s, + int status, + const char *reason, + const char *const *header_names, + const char *const *header_values, + unsigned num_of_headers); + + /* + * Read a chunk of the request body into a buffer. Attempt to read len + * bytes into the buffer. Write the number of bytes actually read into + * actually_read. + */ + int (JK_METHOD * read) (jk_ws_service_t *s, + void *buffer, + unsigned len, unsigned *actually_read); + + /* + * Write a chunk of response data back to the browser. + */ + int (JK_METHOD * write) (jk_ws_service_t *s, + const void *buffer, unsigned len); + + /* + * Flush a chunk of response data back to the browser. + */ + void (JK_METHOD * flush) (jk_ws_service_t *s); + + /* + * Done with sending response back to the browser. + */ + void (JK_METHOD * done) (jk_ws_service_t *s); + + /* + * If set do not reuse socket after each full response + */ + int disable_reuse; + + /* + * Add more data to log facilities. + */ + void (JK_METHOD * add_log_items) (jk_ws_service_t *s, + const char *const *log_names, + const char *const *log_values, + unsigned num_of_items); + + /* + * Iterate through all vhosts + */ + void *(JK_METHOD * next_vhost) (void *d); + + /* + * String representation of a vhost + */ + void (JK_METHOD * vhost_to_text) (void *d, char *buf, size_t len); + + /* + * Get uw_map associated with a vhost + */ + jk_uri_worker_map_t *(JK_METHOD * vhost_to_uw_map) (void *d); +}; + +/* + * The endpoint 'class', which represents one end of a connection to the + * servlet engine. Basically, supports nothing other than forwarding the + * request to the servlet engine. Endpoints can be persistent (as with + * ajp13/ajp14, where a single connection is reused many times), or can last for a + * single request (as with ajp12, where a new connection is created for + * every request). + * + * An endpoint for a given protocol is obtained by the web server plugin + * from a worker object for that protocol. See below for details. + * + * As with all the core jk classes, this is essentially an abstract base + * class which is implemented/extended by classes which are specific to a + * particular protocol. By using an abstract base class in this manner, + * plugins can be written for different servers (e.g. IIS, Apache) without + * the plugins having to worry about which protocol they are talking. + * + * This particular OO-in-C system uses a 'endpoint_private' pointer to + * point to the protocol-specific data/functions. So in the subclasses, the + * methods do most of their work by getting their hands on the + * endpoint_private pointer and then using that to get at the functions for + * their protocol. + * + * Try imagining this as a 'public abstract class', and the + * endpoint_private pointer as a sort of extra 'this' reference. Or + * imagine that you are seeing the internal vtables of your favorite OO + * language. Whatever works for you. + * + * See jk_ajp13_worker.c/jk_ajp14_worker.c and jk_ajp12_worker.c for examples. + */ +struct jk_endpoint +{ + jk_uint64_t rd; + jk_uint64_t wr; + + /* + * Flag to pass back recoverability status from + * a load balancer member to the load balancer itself. + * Depending on the configuration and request status + * recovery is not allowed. + */ + int recoverable; + + /* + * A 'this' pointer which is used by the subclasses of this class to + * point to data/functions which are specific to a given protocol + * (e.g. ajp12 or ajp13 or ajp14). + */ + void *endpoint_private; + + /* + * Forward a request to the servlet engine. The request is described + * by the jk_ws_service_t object. + * is_error is either 0 meaning recoverable or set to + * the HTTP error code. + */ + int (JK_METHOD * service) (jk_endpoint_t *e, + jk_ws_service_t *s, + jk_logger_t *l, int *is_error); + + /* + * Called when this particular endpoint has finished processing a + * request. For some protocols (e.g. ajp12), this frees the memory + * associated with the endpoint. For others (e.g. ajp13/ajp14), this can + * return the endpoint to a cache of already opened endpoints. + * + * Note that the first argument is *not* a 'this' pointer, but is + * rather a pointer to a 'this' pointer. This is necessary, because + * we may need to free this object. + */ + int (JK_METHOD * done) (jk_endpoint_t **p, jk_logger_t *l); +}; + +/* + * The worker 'class', which represents something to which the web server + * can delegate requests. + * + * This can mean communicating with a particular servlet engine instance, + * using a particular protocol. A single web server instance may have + * multiple workers communicating with a single servlet engine (it could be + * using ajp12 for some requests and ajp13/ajp14 for others). Or, a single web + * server instance could have multiple workers communicating with different + * servlet engines using the same protocol (it could be load balancing + * among many engines, using ajp13/ajp14 for all communication). + * + * There is also a load balancing worker (jk_lb_worker.c), which itself + * manages a group of workers. + * + * Web servers are configured to forward requests to a given worker. To + * handle those requests, the worker's get_endpoint method is called, and + * then the service() method of that endpoint is called. + * + * As with all the core jk classes, this is essentially an abstract base + * class which is implemented/extended by classes which are specific to a + * particular protocol (or request-handling system). By using an abstract + * base class in this manner, plugins can be written for different servers + * (e.g. IIS, Apache) without the plugins having to worry about which + * protocol they are talking. + * + * This particular OO-in-C system uses a 'worker_private' pointer to + * point to the protocol-specific data/functions. So in the subclasses, the + * methods do most of their work by getting their hands on the + * worker_private pointer and then using that to get at the functions for + * their protocol. + * + * Try imagining this as a 'public abstract class', and the + * worker_private pointer as a sort of extra 'this' reference. Or + * imagine that you are seeing the internal vtables of your favorite OO + * language. Whatever works for you. + * + * See jk_ajp14_worker.c, jk_ajp13_worker.c and jk_ajp12_worker.c for examples. + */ +struct jk_worker +{ + + jk_worker_env_t *we; + + /* + * A 'this' pointer which is used by the subclasses of this class to + * point to data/functions which are specific to a given protocol + * (e.g. ajp12 or ajp13 or ajp14). + */ + void *worker_private; + + int type; + /* + * For all of the below (except destroy), the first argument is + * essentially a 'this' pointer. + */ + + /* + * Given a worker which is in the process of being created, and a list + * of configuration options (or 'properties'), check to see if it the + * options are. This will always be called before the init() method. + * The init/validate distinction is a bit hazy to me. + * See jk_ajp13_worker.c/jk_ajp14_worker.c and jk_worker.c->wc_create_worker() + */ + int (JK_METHOD * validate) (jk_worker_t *w, + jk_map_t *props, + jk_worker_env_t *we, jk_logger_t *l); + + /* + * Update worker either from jk_status or reloading from workers.properties + */ + int (JK_METHOD * update) (jk_worker_t *w, + jk_map_t *props, + jk_worker_env_t *we, jk_logger_t *l); + + /* + * Do whatever initialization needs to be done to start this worker up. + * Configuration options are passed in via the props parameter. + */ + int (JK_METHOD * init) (jk_worker_t *w, + jk_map_t *props, + jk_worker_env_t *we, jk_logger_t *l); + + + /* + * Obtain an endpoint to service a particular request. A pointer to + * the endpoint is stored in pend. + */ + int (JK_METHOD * get_endpoint) (jk_worker_t *w, + jk_endpoint_t **pend, jk_logger_t *l); + + /* + * Shutdown this worker. The first argument is not a 'this' pointer, + * but rather a pointer to 'this', so that the object can be free'd (I + * think -- though that doesn't seem to be happening. Hmmm). + */ + int (JK_METHOD * destroy) (jk_worker_t **w, jk_logger_t *l); + + /* + * Maintain this worker. + */ + int (JK_METHOD * maintain) (jk_worker_t *w, time_t now, jk_logger_t *l); + +}; + +/* + * Essentially, an abstract base class (or factory class) with a single + * method -- think of it as createWorker() or the Factory Method Design + * Pattern. There is a different worker_factory function for each of the + * different types of workers. The set of all these functions is created + * at startup from the list in jk_worker_list.h, and then the correct one + * is chosen in jk_worker.c->wc_create_worker(). See jk_worker.c and + * jk_ajp13_worker.c/jk_ajp14_worker.c for examples. + * + * This allows new workers to be written without modifing the plugin code + * for the various web servers (since the only link is through + * jk_worker_list.h). + */ +typedef int (JK_METHOD * worker_factory) (jk_worker_t **w, + const char *name, + jk_logger_t *l); + +void jk_init_ws_service(jk_ws_service_t *s); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* JK_SERVICE_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_shm.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_shm.c new file mode 100644 index 00000000..1640f474 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_shm.c @@ -0,0 +1,812 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Shared Memory support * + * Author: Mladen Turk <mturk@jboss.com> * + * Author: Rainer Jung <rjung@apache.org> * + * Version: $Revision: 704548 $ * + ***************************************************************************/ + +#include "jk_global.h" +#include "jk_pool.h" +#include "jk_util.h" +#include "jk_mt.h" +#include "jk_lb_worker.h" +#include "jk_ajp13_worker.h" +#include "jk_ajp14_worker.h" +#include "jk_shm.h" + +/** jk shm header core data structure */ +struct jk_shm_header_data +{ + /* Shared memory magic JK_SHM_MAGIC */ + char magic[JK_SHM_MAGIC_SIZ]; + size_t size; + size_t pos; + unsigned int childs; + unsigned int workers; + time_t modified; +}; + +typedef struct jk_shm_header_data jk_shm_header_data_t; + +/** jk shm header record structure */ +struct jk_shm_header +{ + union { + jk_shm_header_data_t data; + char alignbuf[JK_SHM_ALIGN(sizeof(jk_shm_header_data_t))]; + } h; + char buf[1]; +}; + +typedef struct jk_shm_header jk_shm_header_t; + +/** jk shm structure */ +struct jk_shm +{ + size_t size; + unsigned ajp_workers; + unsigned lb_sub_workers; + unsigned lb_workers; + char *filename; + char *lockname; + int fd; + int fd_lock; + int attached; + jk_shm_header_t *hdr; + JK_CRIT_SEC cs; +}; + +typedef struct jk_shm jk_shm_t; + +static const char shm_signature[] = { JK_SHM_MAGIC }; +static jk_shm_t jk_shmem = { 0, 0, 0, 0, NULL, NULL, -1, -1, 0, NULL}; +static time_t jk_workers_modified_time = 0; +static time_t jk_workers_access_time = 0; +#if defined (WIN32) +static HANDLE jk_shm_map = NULL; +static HANDLE jk_shm_hlock = NULL; +#endif + +/* Calculate needed shm size */ +size_t jk_shm_calculate_size(jk_map_t *init_data, jk_logger_t *l) +{ + char **worker_list; + unsigned i; + unsigned num_of_workers; + int num_of_ajp_workers = 0; + int num_of_lb_sub_workers = 0; + int num_of_lb_workers = 0; + + JK_TRACE_ENTER(l); + + if (jk_get_worker_list(init_data, &worker_list, + &num_of_workers) == JK_FALSE) { + jk_log(l, JK_LOG_ERROR, + "Could not get worker list from map"); + JK_TRACE_EXIT(l); + return 0; + } + + for (i = 0; i < num_of_workers; i++) { + const char *type = jk_get_worker_type(init_data, worker_list[i]); + + if (!strcmp(type, JK_AJP13_WORKER_NAME) || + !strcmp(type, JK_AJP14_WORKER_NAME)) { + num_of_ajp_workers++; + } + else if (!strcmp(type, JK_LB_WORKER_NAME)) { + char **member_list; + unsigned num_of_members; + num_of_lb_workers++; + if (jk_get_lb_worker_list(init_data, worker_list[i], + &member_list, &num_of_members) == JK_FALSE) { + jk_log(l, JK_LOG_ERROR, + "Could not get member list for lb worker from map"); + } + else { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, "worker %s of type %s has %u members", + worker_list[i], JK_LB_WORKER_NAME, num_of_members); + num_of_lb_sub_workers += num_of_members; + } + } + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, "shared memory will contain %d ajp workers of size %d and %d lb workers of size %d with %d members of size %d+%d", + num_of_ajp_workers, JK_SHM_AJP_SIZE(1), + num_of_lb_workers, JK_SHM_LB_SIZE(1), + num_of_lb_sub_workers, JK_SHM_LB_SUB_SIZE(1), JK_SHM_AJP_SIZE(1)); + jk_shmem.ajp_workers = num_of_ajp_workers; + jk_shmem.lb_sub_workers = num_of_lb_sub_workers; + jk_shmem.lb_workers = num_of_lb_workers; + JK_TRACE_EXIT(l); + return JK_SHM_AJP_SIZE(jk_shmem.ajp_workers) + + JK_SHM_LB_SUB_SIZE(jk_shmem.lb_sub_workers) + + JK_SHM_AJP_SIZE(jk_shmem.lb_sub_workers) + + JK_SHM_LB_SIZE(jk_shmem.lb_workers); +} + + +#if defined (WIN32) || defined(NETWARE) + +/* Use plain memory */ +int jk_shm_open(const char *fname, size_t sz, jk_logger_t *l) +{ + int rc; + int attached = 0; + char lkname[MAX_PATH]; + JK_TRACE_ENTER(l); + if (jk_shmem.hdr) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, "Shared memory is already opened"); + JK_TRACE_EXIT(l); + return 0; + } + + jk_shmem.size = JK_SHM_ALIGN(sizeof(jk_shm_header_t) + sz); + +#if defined (WIN32) + if (fname) { + jk_shm_map = CreateFileMapping(INVALID_HANDLE_VALUE, + NULL, + PAGE_READWRITE, + 0, + (DWORD)(sizeof(jk_shm_header_t) + sz), + fname); + if (GetLastError() == ERROR_ALREADY_EXISTS) { + attached = 1; + if (jk_shm_map == NULL || jk_shm_map == INVALID_HANDLE_VALUE) { + jk_shm_map = OpenFileMapping(PAGE_READWRITE, FALSE, fname); + } + } + if (jk_shm_map == NULL || jk_shm_map == INVALID_HANDLE_VALUE) { + JK_TRACE_EXIT(l); + return -1; + } + sprintf(lkname, "Global\\%s_MUTEX", fname); + if (attached) { + jk_shm_hlock = OpenMutex(MUTEX_ALL_ACCESS, FALSE, lkname); + } + else { + jk_shm_hlock = CreateMutex(NULL, FALSE, lkname); + } + if (jk_shm_hlock == NULL || jk_shm_hlock == INVALID_HANDLE_VALUE) { + CloseHandle(jk_shm_map); + jk_shm_map = NULL; + JK_TRACE_EXIT(l); + return -1; + } + jk_shmem.hdr = (jk_shm_header_t *)MapViewOfFile(jk_shm_map, + FILE_MAP_ALL_ACCESS, + 0, + 0, + 0); + } + else +#endif + jk_shmem.hdr = (jk_shm_header_t *)calloc(1, jk_shmem.size); + if (!jk_shmem.hdr) { +#if defined (WIN32) + if (jk_shm_map) { + CloseHandle(jk_shm_map); + jk_shm_map = NULL; + } + if (jk_shm_hlock) { + CloseHandle(jk_shm_hlock); + jk_shm_hlock = NULL; + } +#endif + JK_TRACE_EXIT(l); + return -1; + } + if (!jk_shmem.filename) { + if (fname) + jk_shmem.filename = strdup(fname); + else + jk_shmem.filename = strdup("memory"); + } + jk_shmem.fd = 0; + jk_shmem.attached = attached; + if (!attached) { + memcpy(jk_shmem.hdr->h.data.magic, shm_signature, + JK_SHM_MAGIC_SIZ); + jk_shmem.hdr->h.data.size = sz; + jk_shmem.hdr->h.data.childs = 1; + } + else { + jk_shmem.hdr->h.data.childs++; + /* + * Reset the shared memory so that + * alloc works even for attached memory. + * XXX: This might break already used memory + * if the number of workers change between + * open and attach or between two attach operations. + */ + if (jk_shmem.hdr->h.data.childs > 1) { + if (JK_IS_DEBUG_LEVEL(l)) { + jk_log(l, JK_LOG_DEBUG, + "Resetting the shared memory for child %d", + jk_shmem.hdr->h.data.childs); + } + } + jk_shmem.hdr->h.data.pos = 0; + jk_shmem.hdr->h.data.workers = 0; + } + JK_INIT_CS(&(jk_shmem.cs), rc); + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "%s shared memory %s size=%u free=%u addr=%#lx", + attached ? "Attached" : "Initialized", + jk_shm_name(), jk_shmem.size, + jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos, + jk_shmem.hdr); + JK_TRACE_EXIT(l); + return 0; +} + +int jk_shm_attach(const char *fname, size_t sz, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + if (!jk_shm_open(fname, sz, l)) { + if (!jk_shmem.attached) { + jk_shmem.attached = 1; + if (JK_IS_DEBUG_LEVEL(l)) { + jk_log(l, JK_LOG_DEBUG, + "Attached shared memory %s [%d] size=%u free=%u addr=%#lx", + jk_shm_name(), jk_shmem.hdr->h.data.childs, jk_shmem.size, + jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos, + jk_shmem.hdr); + } + } + JK_TRACE_EXIT(l); + return 0; + } + else { + JK_TRACE_EXIT(l); + return -1; + } +} + +void jk_shm_close() +{ + if (jk_shmem.hdr) { + int rc; +#if defined (WIN32) + if (jk_shm_hlock) { + CloseHandle(jk_shm_hlock); + jk_shm_hlock = NULL; + } + if (jk_shm_map) { + --jk_shmem.hdr->h.data.childs; + UnmapViewOfFile(jk_shmem.hdr); + CloseHandle(jk_shm_map); + jk_shm_map = NULL; + } + else +#endif + free(jk_shmem.hdr); + JK_DELETE_CS(&(jk_shmem.cs), rc); + } + jk_shmem.hdr = NULL; + if (jk_shmem.filename) { + free(jk_shmem.filename); + jk_shmem.filename = NULL; + } +} + +#else + +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/uio.h> + +#ifndef MAP_FAILED +#define MAP_FAILED (-1) +#endif + +#ifndef MAP_FILE +#define MAP_FILE (0) +#endif + +static int do_shm_open_lock(const char *fname, int attached, jk_logger_t *l) +{ + int rc; + char flkname[256]; +#ifdef AS400_UTF8 + char *wptr; +#endif + + JK_TRACE_ENTER(l); + + if (attached && jk_shmem.lockname) { +#ifdef JK_SHM_LOCK_REOPEN + jk_shmem.fd_lock = open(jk_shmem.lockname, O_RDWR, 0666); +#else + errno = EINVAL; +#endif + if (jk_shmem.fd_lock == -1) { + rc = errno; + JK_TRACE_EXIT(l); + return rc; + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Duplicated shared memory lock %s", jk_shmem.lockname); + JK_TRACE_EXIT(l); + return 0; + } + + if (!jk_shmem.lockname) { +#ifdef JK_SHM_LOCK_REOPEN + int i; + jk_shmem.fd_lock = -1; + mode_t mask = umask(0); + for (i = 0; i < 8; i++) { + strcpy(flkname, "/tmp/jkshmlock.XXXXXX"); + if (mktemp(flkname)) { + jk_shmem.fd_lock = open(flkname, O_RDWR|O_CREAT|O_TRUNC, 0666); + if (jk_shmem.fd_lock >= 0) + break; + } + } + umask(mask); +#else + strcpy(flkname, fname); + strcat(flkname, ".lock"); +#ifdef AS400_UTF8 + wptr = (char *)malloc(strlen(flkname) + 1); + jk_ascii2ebcdic((char *)flkname, wptr); + jk_shmem.fd_lock = open(wptr, O_RDWR|O_CREAT|O_TRUNC, 0666); + free(wptr); +#else + jk_shmem.fd_lock = open(flkname, O_RDWR|O_CREAT|O_TRUNC, 0666); +#endif +#endif + if (jk_shmem.fd_lock == -1) { + rc = errno; + JK_TRACE_EXIT(l); + return rc; + } + jk_shmem.lockname = strdup(flkname); + } + else { + /* Nothing to do */ + JK_TRACE_EXIT(l); + return 0; + } + + if (ftruncate(jk_shmem.fd_lock, 1)) { + rc = errno; + close(jk_shmem.fd_lock); + jk_shmem.fd_lock = -1; + JK_TRACE_EXIT(l); + return rc; + } + if (lseek(jk_shmem.fd_lock, 0, SEEK_SET) != 0) { + rc = errno; + close(jk_shmem.fd_lock); + jk_shmem.fd_lock = -1; + return rc; + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Opened shared memory lock %s", jk_shmem.lockname); + JK_TRACE_EXIT(l); + return 0; +} + +static int do_shm_open(const char *fname, int attached, + size_t sz, jk_logger_t *l) +{ + int rc; + int fd; + void *base; +#ifdef AS400_UTF8 + char *wptr; +#endif + + JK_TRACE_ENTER(l); + if (jk_shmem.hdr) { + /* Probably a call from vhost */ + if (!attached) + attached = 1; + } + else if (attached) { + /* We should already have a header + * Use memory if we don't + */ + JK_TRACE_EXIT(l); + return 0; + } + jk_shmem.size = JK_SHM_ALIGN(sizeof(jk_shm_header_t) + sz); + + if (!fname) { + /* Use plain memory in case there is no file name */ + if (!jk_shmem.filename) + jk_shmem.filename = strdup("memory"); + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Using process memory as shared memory"); + JK_TRACE_EXIT(l); + return 0; + } + + if (!jk_shmem.filename) { + jk_shmem.filename = (char *)malloc(strlen(fname) + 32); + sprintf(jk_shmem.filename, "%s.%" JK_PID_T_FMT, fname, getpid()); + } + if (!attached) { + size_t size; + jk_shmem.attached = 0; +#ifdef AS400_UTF8 + wptr = (char *)malloc(strlen(jk_shmem.filename) + 1); + jk_ascii2ebcdic((char *)jk_shmem.filename, wptr); + fd = open(wptr, O_RDWR|O_CREAT|O_TRUNC, 0666); + free(wptr); +#else + fd = open(jk_shmem.filename, O_RDWR|O_CREAT|O_TRUNC, 0666); +#endif + if (fd == -1) { + jk_shmem.size = 0; + JK_TRACE_EXIT(l); + return errno; + } + size = lseek(fd, 0, SEEK_END); + if (size < jk_shmem.size) { + size = jk_shmem.size; + if (ftruncate(fd, jk_shmem.size)) { + rc = errno; + close(fd); +#ifdef AS400_UTF8 + wptr = (char *)malloc(strlen(jk_shmem.filename) + 1); + jk_ascii2ebcdic((char *)jk_shmem.filename, wptr); + unlink(wptr); + free(wptr); +#else + unlink(jk_shmem.filename); +#endif + jk_shmem.size = 0; + JK_TRACE_EXIT(l); + return rc; + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Truncated shared memory to %u", size); + } + if (lseek(fd, 0, SEEK_SET) != 0) { + rc = errno; + close(fd); +#ifdef AS400_UTF8 + wptr = (char *)malloc(strlen(jk_shmem.filename) + 1); + jk_ascii2ebcdic((char *)jk_shmem.filename, wptr); + unlink(wptr); + free(wptr); +#else + unlink(jk_shmem.filename); +#endif + jk_shmem.size = 0; + JK_TRACE_EXIT(l); + return rc; + } + + base = mmap((caddr_t)0, jk_shmem.size, + PROT_READ | PROT_WRITE, + MAP_FILE | MAP_SHARED, + fd, 0); + if (base == (caddr_t)MAP_FAILED || base == (caddr_t)0) { + rc = errno; + close(fd); +#ifdef AS400_UTF8 + wptr = (char *)malloc(strlen(jk_shmem.filename) + 1); + jk_ascii2ebcdic((char *)jk_shmem.filename, wptr); + unlink(wptr); + free(wptr); +#else + unlink(jk_shmem.filename); +#endif + jk_shmem.size = 0; + JK_TRACE_EXIT(l); + return rc; + } + jk_shmem.hdr = base; + jk_shmem.fd = fd; + memset(jk_shmem.hdr, 0, jk_shmem.size); + memcpy(jk_shmem.hdr->h.data.magic, shm_signature, JK_SHM_MAGIC_SIZ); + jk_shmem.hdr->h.data.size = sz; + jk_shmem.hdr->h.data.childs = 1; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Initialized shared memory %s size=%u free=%u addr=%#lx", + jk_shm_name(), jk_shmem.size, + jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos, + jk_shmem.hdr); + } + else { + unsigned int nchild; + jk_shmem.hdr->h.data.childs++; + jk_shmem.attached = (int)getpid(); + nchild = jk_shmem.hdr->h.data.childs; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Attached shared memory %s [%d] size=%u free=%u addr=%#lx", + jk_shm_name(), nchild, jk_shmem.size, + jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos, + jk_shmem.hdr); + /* + * Reset the shared memory so that + * alloc works even for attached memory. + * XXX: This might break already used memory + * if the number of workers change between + * open and attach or between two attach operations. + */ + if (nchild > 1) { + if (JK_IS_DEBUG_LEVEL(l)) { + jk_log(l, JK_LOG_DEBUG, + "Resetting the shared memory for child %d", + nchild); + } + } + jk_shmem.hdr->h.data.pos = 0; + jk_shmem.hdr->h.data.workers = 0; + } + JK_INIT_CS(&(jk_shmem.cs), rc); + if ((rc = do_shm_open_lock(jk_shmem.filename, attached, l))) { + if (!attached) { + munmap((void *)jk_shmem.hdr, jk_shmem.size); + close(jk_shmem.fd); +#ifdef AS400_UTF8 + wptr = (char *)malloc(strlen(jk_shmem.filename) + 1); + jk_ascii2ebcdic((char *)jk_shmem.filename, wptr); + unlink(wptr); + free(wptr); +#else + unlink(jk_shmem.filename); +#endif + } + jk_shmem.hdr = NULL; + jk_shmem.fd = -1; + JK_TRACE_EXIT(l); + return rc; + } + JK_TRACE_EXIT(l); + return 0; +} + +int jk_shm_open(const char *fname, size_t sz, jk_logger_t *l) +{ + return do_shm_open(fname, 0, sz, l); +} + +int jk_shm_attach(const char *fname, size_t sz, jk_logger_t *l) +{ + return do_shm_open(fname, 1, sz, l); +} + +void jk_shm_close() +{ + int rc; +#ifdef AS400_UTF8 + char *wptr; +#endif + + if (jk_shmem.hdr) { + --jk_shmem.hdr->h.data.childs; + +#ifdef JK_SHM_LOCK_REOPEN + if (jk_shmem.fd_lock >= 0) { + close(jk_shmem.fd_lock); + jk_shmem.fd_lock = -1; + } +#endif + JK_DELETE_CS(&(jk_shmem.cs), rc); + if (jk_shmem.attached) { + int p = (int)getpid(); + if (p == jk_shmem.attached) { + /* In case this is a forked child + * do not close the shared memory. + * It will be closed by the parent. + */ + jk_shmem.size = 0; + jk_shmem.hdr = NULL; + jk_shmem.fd = -1; + return; + } + } + if (jk_shmem.fd >= 0) { + munmap((void *)jk_shmem.hdr, jk_shmem.size); + close(jk_shmem.fd); + } + if (jk_shmem.fd_lock >= 0) + close(jk_shmem.fd_lock); + if (jk_shmem.lockname) { +#ifdef AS400_UTF8 + wptr = (char *)malloc(strlen(jk_shmem.lockname) + 1); + jk_ascii2ebcdic((char *)jk_shmem.lockname, wptr); + unlink(wptr); + free(wptr); +#else + unlink(jk_shmem.lockname); +#endif + free(jk_shmem.lockname); + jk_shmem.lockname = NULL; + } + if (jk_shmem.filename) { +#ifdef AS400_UTF8 + wptr = (char *)malloc(strlen(jk_shmem.filename) + 1); + jk_ascii2ebcdic((char *)jk_shmem.filename, wptr); + unlink(wptr); + free(wptr); +#else + unlink(jk_shmem.filename); +#endif + free(jk_shmem.filename); + jk_shmem.filename = NULL; + } + } + jk_shmem.size = 0; + jk_shmem.hdr = NULL; + jk_shmem.fd = -1; + jk_shmem.fd_lock = -1; +} + + +#endif + +void *jk_shm_alloc(jk_pool_t *p, size_t size) +{ + void *rc = NULL; + + if (jk_shmem.hdr) { + size = JK_SHM_ALIGN(size); + if ((jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos) >= size) { + rc = &(jk_shmem.hdr->buf[jk_shmem.hdr->h.data.pos]); + jk_shmem.hdr->h.data.pos += size; + } + } + else if (p) + rc = jk_pool_alloc(p, size); + + return rc; +} + +const char *jk_shm_name() +{ + return jk_shmem.filename; +} + + +time_t jk_shm_get_workers_time() +{ + if (jk_shmem.hdr) + return jk_shmem.hdr->h.data.modified; + else + return jk_workers_modified_time; +} + +void jk_shm_set_workers_time(time_t t) +{ + if (jk_shmem.hdr) + jk_shmem.hdr->h.data.modified = t; + else + jk_workers_modified_time = t; + jk_workers_access_time = t; +} + +int jk_shm_is_modified() +{ + time_t m = jk_shm_get_workers_time(); + if (m != jk_workers_access_time) + return 1; + else + return 0; +} + +void jk_shm_sync_access_time() +{ + jk_workers_access_time = jk_shm_get_workers_time(); +} + +int jk_shm_lock() +{ + int rc; + JK_ENTER_CS(&(jk_shmem.cs), rc); +#if defined (WIN32) + if (rc == JK_TRUE && jk_shm_hlock != NULL) { + DWORD rv = WaitForSingleObject(jk_shm_hlock, INFINITE); + if (rv == WAIT_OBJECT_0 || rv == WAIT_ABANDONED) + rc = JK_TRUE; + else + rc = JK_FALSE; + } +#else + if (rc == JK_TRUE && jk_shmem.fd_lock != -1) { + JK_ENTER_LOCK(jk_shmem.fd_lock, rc); + } +#endif + return rc; +} + +int jk_shm_unlock() +{ + int rc; + JK_LEAVE_CS(&(jk_shmem.cs), rc); +#if defined (WIN32) + if (rc == JK_TRUE && jk_shm_hlock != NULL) { + if (!ReleaseMutex(jk_shm_hlock)) + rc = JK_FALSE; + } +#else + if (rc == JK_TRUE && jk_shmem.fd_lock != -1) { + JK_LEAVE_LOCK(jk_shmem.fd_lock, rc); + } +#endif + return rc; +} + +jk_shm_ajp_worker_t *jk_shm_alloc_ajp_worker(jk_pool_t *p) +{ + jk_shm_ajp_worker_t *w = (jk_shm_ajp_worker_t *)jk_shm_alloc(p, JK_SHM_AJP_WORKER_SIZE); + if (w) { + memset(w, 0, JK_SHM_AJP_WORKER_SIZE); + if (jk_shmem.hdr) { + jk_shmem.hdr->h.data.workers++; + w->h.id = jk_shmem.hdr->h.data.workers; + w->h.type = JK_AJP13_WORKER_TYPE; + } + else + w->h.id = -1; + } + return w; +} + +jk_shm_lb_sub_worker_t *jk_shm_alloc_lb_sub_worker(jk_pool_t *p) +{ + jk_shm_lb_sub_worker_t *w = (jk_shm_lb_sub_worker_t *)jk_shm_alloc(p, JK_SHM_LB_SUB_WORKER_SIZE); + if (w) { + memset(w, 0, JK_SHM_LB_SUB_WORKER_SIZE); + if (jk_shmem.hdr) { + jk_shmem.hdr->h.data.workers++; + w->h.id = jk_shmem.hdr->h.data.workers; + w->h.type = JK_LB_SUB_WORKER_TYPE; + } + else + w->h.id = -1; + } + return w; +} + +jk_shm_lb_worker_t *jk_shm_alloc_lb_worker(jk_pool_t *p) +{ + jk_shm_lb_worker_t *w = (jk_shm_lb_worker_t *)jk_shm_alloc(p, JK_SHM_LB_WORKER_SIZE); + if (w) { + memset(w, 0, JK_SHM_LB_WORKER_SIZE); + if (jk_shmem.hdr) { + jk_shmem.hdr->h.data.workers++; + w->h.id = jk_shmem.hdr->h.data.workers; + w->h.type = JK_LB_WORKER_TYPE; + } + else + w->h.id = -1; + } + return w; +} diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_shm.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_shm.h new file mode 100644 index 00000000..f8d54a45 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_shm.h @@ -0,0 +1,258 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Shared Memory object header file * + * Author: Mladen Turk <mturk@jboss.com> * + * Author: Rainer Jung <rjung@apache.org> * + * Version: $Revision: 893253 $ * + ***************************************************************************/ +#ifndef _JK_SHM_H +#define _JK_SHM_H + +#include "jk_global.h" +#include "jk_pool.h" +#include "jk_util.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** + * @file jk_shm.h + * @brief Jk shared memory management + * + * + */ + +#define JK_SHM_MAJOR '1' +#define JK_SHM_MINOR '3' +#define JK_SHM_STR_SIZ 63 +#define JK_SHM_URI_SIZ 127 +#define JK_SHM_DYNAMIC 16 +#define JK_SHM_MAGIC '!', 'J', 'K', 'S', 'H', 'M', JK_SHM_MAJOR, JK_SHM_MINOR +#define JK_SHM_MAGIC_SIZ 8 + +/* Really huge numbers, but 64 workers should be enough */ +#define JK_SHM_MAX_WORKERS 64 +#define JK_SHM_ALIGNMENT 64 +#define JK_SHM_ALIGN(x) JK_ALIGN((x), JK_SHM_ALIGNMENT) +#define JK_SHM_AJP_WORKER_SIZE JK_SHM_ALIGN(sizeof(jk_shm_ajp_worker_t)) +#define JK_SHM_LB_SUB_WORKER_SIZE JK_SHM_ALIGN(sizeof(jk_shm_lb_sub_worker_t)) +#define JK_SHM_LB_WORKER_SIZE JK_SHM_ALIGN(sizeof(jk_shm_lb_worker_t)) +#define JK_SHM_AJP_SIZE(x) ((x) * JK_SHM_AJP_WORKER_SIZE) +#define JK_SHM_LB_SUB_SIZE(x) ((x) * JK_SHM_LB_SUB_WORKER_SIZE) +#define JK_SHM_LB_SIZE(x) ((x) * JK_SHM_LB_WORKER_SIZE) +#define JK_SHM_DEF_SIZE JK_SHM_AJP_SIZE(JK_SHM_MAX_WORKERS) + JK_SHM_LB_SUB_SIZE(JK_SHM_MAX_WORKERS) + JK_SHM_LB_SIZE(JK_SHM_MAX_WORKERS) + +/** jk shm generic worker record structure */ +struct jk_shm_worker_header +{ + int id; + int type; + /* worker name */ + char name[JK_SHM_STR_SIZ+1]; + /* Sequence counter starting at 0 and increasing + * every time we change the config + */ + volatile unsigned int sequence; +}; +typedef struct jk_shm_worker_header jk_shm_worker_header_t; + +/** jk shm ajp13/ajp14 worker record structure */ +struct jk_shm_ajp_worker +{ + jk_shm_worker_header_t h; + char host[JK_SHM_STR_SIZ+1]; + int port; + volatile int addr_sequence; + + /* Configuration data mirrored from ajp_worker */ + int cache_timeout; + int connect_timeout; + int ping_timeout; + int reply_timeout; + int prepost_timeout; + unsigned int recovery_opts; + int retries; + int retry_interval; + unsigned int max_packet_size; + /* current error state (runtime) of the worker */ + volatile int state; + /* Statistical data */ + /* Number of currently connected channels */ + volatile int connected; + /* Number of currently busy channels */ + volatile int busy; + /* Maximum number of busy channels */ + volatile int max_busy; + volatile time_t error_time; + /* Number of bytes read from remote */ + volatile jk_uint64_t readed; + /* Number of bytes transferred to remote */ + volatile jk_uint64_t transferred; + /* Number of times the worker was used */ + volatile jk_uint64_t used; + /* Number of times the worker was used - snapshot during maintenance */ + volatile jk_uint64_t used_snapshot; + /* Number of non 200 responses */ + volatile jk_uint32_t errors; + /* Decayed number of reply_timeout errors */ + volatile jk_uint32_t reply_timeouts; + /* Number of client errors */ + volatile jk_uint32_t client_errors; + /* Last reset time */ + volatile time_t last_reset; + volatile time_t last_maintain_time; +}; +typedef struct jk_shm_ajp_worker jk_shm_ajp_worker_t; + +/** jk shm lb sub worker record structure */ +struct jk_shm_lb_sub_worker +{ + jk_shm_worker_header_t h; + + /* route */ + char route[JK_SHM_STR_SIZ+1]; + /* worker domain */ + char domain[JK_SHM_STR_SIZ+1]; + /* worker redirect route */ + char redirect[JK_SHM_STR_SIZ+1]; + /* Number of currently busy channels */ + volatile int busy; + /* worker distance */ + volatile int distance; + /* current activation state (config) of the worker */ + volatile int activation; + /* current error state (runtime) of the worker */ + volatile int state; + /* Current lb factor */ + volatile int lb_factor; + /* Current lb reciprocal factor */ + volatile jk_uint64_t lb_mult; + /* Current lb value */ + volatile jk_uint64_t lb_value; + /* Statistical data */ + volatile time_t error_time; + /* Number of times the worker was elected - snapshot during maintenance */ + volatile jk_uint64_t elected_snapshot; + /* Number of non 200 responses */ + volatile jk_uint32_t errors; +}; +typedef struct jk_shm_lb_sub_worker jk_shm_lb_sub_worker_t; + +/** jk shm lb worker record structure */ +struct jk_shm_lb_worker +{ + jk_shm_worker_header_t h; + + /* Number of currently busy channels */ + volatile int busy; + /* Maximum number of busy channels */ + volatile int max_busy; + int sticky_session; + int sticky_session_force; + int recover_wait_time; + int error_escalation_time; + int max_reply_timeouts; + int retries; + int retry_interval; + int lbmethod; + int lblock; + unsigned int max_packet_size; + /* Last reset time */ + volatile time_t last_reset; + volatile time_t last_maintain_time; + /* Session cookie */ + char session_cookie[JK_SHM_STR_SIZ+1]; + /* Session path */ + char session_path[JK_SHM_STR_SIZ+1]; + +}; +typedef struct jk_shm_lb_worker jk_shm_lb_worker_t; + +const char *jk_shm_name(void); + +/* Calculate needed shm size */ +size_t jk_shm_calculate_size(jk_map_t *init_data, jk_logger_t *l); + +/* Open the shared memory creating file if needed + */ +int jk_shm_open(const char *fname, size_t sz, jk_logger_t *l); + +/* Close the shared memory + */ +void jk_shm_close(void); + +/* Attach the shared memory in child process. + * File has to be opened in parent. + */ +int jk_shm_attach(const char *fname, size_t sz, jk_logger_t *l); + +/* allocate shm memory + * If there is no shm present the pool will be used instead + */ +void *jk_shm_alloc(jk_pool_t *p, size_t size); + +/* allocate shm ajp worker record + * If there is no shm present the pool will be used instead + */ +jk_shm_ajp_worker_t *jk_shm_alloc_ajp_worker(jk_pool_t *p); + +/* allocate shm lb sub worker record + * If there is no shm present the pool will be used instead + */ +jk_shm_lb_sub_worker_t *jk_shm_alloc_lb_sub_worker(jk_pool_t *p); + +/* allocate shm lb worker record + * If there is no shm present the pool will be used instead + */ +jk_shm_lb_worker_t *jk_shm_alloc_lb_worker(jk_pool_t *p); + +/* Return workers.properties last modified time + */ +time_t jk_shm_get_workers_time(void); + +/* Set workers.properties last modified time + */ +void jk_shm_set_workers_time(time_t t); + +/* Check if the shared memory has been modified + * by some other process. + */ +int jk_shm_is_modified(void); + +/* Synchronize access and modification time. + * This function should be called when the shared memory + * is modified and after we update the config acording + * to the current shared memory data. + */ +void jk_shm_sync_access_time(void); + + +/* Lock shared memory for thread safe access */ +int jk_shm_lock(void); + +/* Unlock shared memory for thread safe access */ +int jk_shm_unlock(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _JK_SHM_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_shm.lo b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_shm.lo new file mode 100644 index 00000000..44e59ec0 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_shm.lo @@ -0,0 +1,12 @@ +# jk_shm.lo - a libtool object file +# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/jk_shm.o' + +# Name of the non-PIC object. +non_pic_object='jk_shm.o' + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_shm.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_shm.o Binary files differnew file mode 100644 index 00000000..8f02d766 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_shm.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_sockbuf.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_sockbuf.c new file mode 100644 index 00000000..da956258 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_sockbuf.c @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Simple buffer object to handle buffered socket IO * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Version: $Revision: 466585 $ * + ***************************************************************************/ + +#include "jk_global.h" +#include "jk_sockbuf.h" + +static int fill_buffer(jk_sockbuf_t *sb); + +int jk_sb_open(jk_sockbuf_t *sb, jk_sock_t sd) +{ + if (sb && sd >= 0) { + sb->end = 0; + sb->start = 0; + sb->sd = sd; + return JK_TRUE; + } + + return JK_FALSE; +} + +int jk_sb_write(jk_sockbuf_t *sb, const void *buf, unsigned sz) +{ + if (sb && buf && sz) { + if ((SOCKBUF_SIZE - sb->end) >= sz) { + memcpy(sb->buf + sb->end, buf, sz); + sb->end += sz; + } + else { + if (!jk_sb_flush(sb)) { + return JK_FALSE; + } + if (sz > SOCKBUF_SIZE) { + return (send(sb->sd, (char *)buf, sz, 0) == (int)sz); + } + + memcpy(sb->buf + sb->end, buf, sz); + sb->end += sz; + } + + return JK_TRUE; + } + + return JK_FALSE; +} + +int jk_sb_flush(jk_sockbuf_t *sb) +{ + if (sb) { + int save_out = sb->end; + sb->end = sb->start = 0; + if (save_out) { + return send(sb->sd, sb->buf, save_out, 0) == save_out; + } + return JK_TRUE; + } + + return JK_FALSE; +} + + +int jk_sb_read(jk_sockbuf_t *sb, char **buf, unsigned sz, unsigned *ac) +{ + if (sb && buf && ac) { + unsigned avail; + + *ac = 0; + *buf = NULL; + + if (sb->end == sb->start) { + sb->end = sb->start = 0; + if (fill_buffer(sb) < 0) { + return JK_FALSE; + } + } + + *buf = sb->buf + sb->start; + avail = sb->end - sb->start; + if (avail > sz) { + *ac = sz; + } + else { + *ac = avail; + } + sb->start += *ac; + + return JK_TRUE; + } + + return JK_FALSE; +} + +int jk_sb_gets(jk_sockbuf_t *sb, char **ps) +{ + int ret; + if (sb) { + while (1) { + unsigned i; + for (i = sb->start; i < sb->end; i++) { + if (JK_LF == sb->buf[i]) { + if (i > sb->start && JK_CR == sb->buf[i - 1]) { + sb->buf[i - 1] = '\0'; + } + else { + sb->buf[i] = '\0'; + } + *ps = sb->buf + sb->start; + sb->start = (i + 1); + return JK_TRUE; + } + } + if ((ret = fill_buffer(sb)) < 0) { + return JK_FALSE; + } + else if (ret == 0) { + *ps = sb->buf + sb->start; + if ((SOCKBUF_SIZE - sb->end) > 0) { + sb->buf[sb->end] = '\0'; + } + else { + sb->buf[sb->end - 1] = '\0'; + } + return JK_TRUE; + } + } + } + + return JK_FALSE; +} + +/* + * Read data from the socket into the associated buffer, and update the + * start and end indices. May move the data currently in the buffer. If + * new data is read into the buffer (or if it is already full), returns 1. + * If EOF is received on the socket, returns 0. In case of error returns + * -1. + */ +static int fill_buffer(jk_sockbuf_t *sb) +{ + int ret; + + /* + * First move the current data to the beginning of the buffer + */ + if (sb->start < sb->end) { + if (sb->start > 0) { + unsigned to_copy = sb->end - sb->start; + memmove(sb->buf, sb->buf + sb->start, to_copy); + sb->start = 0; + sb->end = to_copy; + } + } + else { + sb->start = sb->end = 0; + } + + /* + * In the unlikely case where the buffer is already full, we won't be + * reading anything and we'd be calling recv with a 0 count. + */ + if ((SOCKBUF_SIZE - sb->end) > 0) { + /* + * Now, read more data + */ + ret = recv(sb->sd, sb->buf + sb->end, SOCKBUF_SIZE - sb->end, 0); + + /* 0 is EOF/SHUTDOWN, -1 is SOCK_ERROR */ + if (ret <= 0) { + return ret; + } + + sb->end += ret; + } + + return 1; +} diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_sockbuf.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_sockbuf.h new file mode 100644 index 00000000..4ed75141 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_sockbuf.h @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Socket buffer header file * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Version: $Revision: 466585 $ * + ***************************************************************************/ + +#include "jk_global.h" + +#define SOCKBUF_SIZE (8*1024) + +struct jk_sockbuf +{ + char buf[SOCKBUF_SIZE]; + unsigned int start; + unsigned int end; + jk_sock_t sd; +}; +typedef struct jk_sockbuf jk_sockbuf_t; + +int jk_sb_open(jk_sockbuf_t *sb, jk_sock_t sd); + +int jk_sb_write(jk_sockbuf_t *sb, const void *buf, unsigned sz); + +int jk_sb_read(jk_sockbuf_t *sb, char **buf, unsigned sz, unsigned *ac); + +int jk_sb_flush(jk_sockbuf_t *sb); + +int jk_sb_gets(jk_sockbuf_t *sb, char **ps); diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_sockbuf.lo b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_sockbuf.lo new file mode 100644 index 00000000..81ac7e40 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_sockbuf.lo @@ -0,0 +1,12 @@ +# jk_sockbuf.lo - a libtool object file +# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/jk_sockbuf.o' + +# Name of the non-PIC object. +non_pic_object='jk_sockbuf.o' + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_sockbuf.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_sockbuf.o Binary files differnew file mode 100644 index 00000000..53350c5d --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_sockbuf.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_status.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_status.c new file mode 100644 index 00000000..d9c0a6ad --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_status.c @@ -0,0 +1,5200 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Status worker, display and manages JK workers * + * Author: Mladen Turk <mturk@jboss.com> * + * Author: Rainer Jung <rjung@apache.org> * + * Version: $Revision: 1054603 $ * + ***************************************************************************/ + +#include "jk_pool.h" +#include "jk_service.h" +#include "jk_util.h" +#include "jk_worker.h" +#include "jk_status.h" +#include "jk_mt.h" +#include "jk_shm.h" +#include "jk_ajp_common.h" +#include "jk_lb_worker.h" +#include "jk_ajp13_worker.h" +#include "jk_ajp14_worker.h" +#include "jk_connect.h" +#include "jk_uri_worker_map.h" + +#define HUGE_BUFFER_SIZE (8*1024) + +/** + * Command line reference: + * cmd=list (default) display configuration + * cmd=show display detailed configuration + * cmd=edit form to change configuration + * cmd=update commit update configuration + * cmd=reset reset lb runtime states, or lb member runtime states + * cmd=version show only software version + * Query arguments: + * re=n (refresh time in seconds, n=0: disabled) + * w=worker (cmd should be executed for worker "worker") + * sw=sub_worker (cmd should be executed for "sub_worker" of worker "worker") + * from=lastcmd (the last viewing command was "lastcmd") + * opt=option (changes meaning of edit and list/show) + */ + +#define JK_STATUS_ARG_CMD "cmd" +#define JK_STATUS_ARG_MIME "mime" +#define JK_STATUS_ARG_FROM "from" +#define JK_STATUS_ARG_REFRESH "re" +#define JK_STATUS_ARG_WORKER "w" +#define JK_STATUS_ARG_SUB_WORKER "sw" +#define JK_STATUS_ARG_PREV_SUB_WORKER "psw" +#define JK_STATUS_ARG_ATTRIBUTE "att" +#define JK_STATUS_ARG_MULT_VALUE_BASE "val" +#define JK_STATUS_ARG_OPTIONS "opt" + +#define JK_STATUS_ARG_OPTION_NO_MEMBERS 0x0001 +#define JK_STATUS_ARG_OPTION_NO_MAPS 0x0002 +#define JK_STATUS_ARG_OPTION_NO_LEGEND 0x0004 +#define JK_STATUS_ARG_OPTION_NO_LB 0x0008 +#define JK_STATUS_ARG_OPTION_NO_AJP 0x0010 +#define JK_STATUS_ARG_OPTION_READ_ONLY 0x0020 +#define JK_STATUS_ARG_OPTION_NO_LB_CONF 0x0040 +#define JK_STATUS_ARG_OPTION_NO_LB_SUMMARY 0x0080 +#define JK_STATUS_ARG_OPTION_NO_AJP_CONF 0x0100 + +#define JK_STATUS_ARG_LB_RETRIES ("vlr") +#define JK_STATUS_ARG_LB_RETRY_INT ("vlri") +#define JK_STATUS_ARG_LB_RECOVER_TIME ("vlt") +#define JK_STATUS_ARG_LB_ERROR_ESCALATION_TIME ("vlee") +#define JK_STATUS_ARG_LB_MAX_REPLY_TIMEOUTS ("vlx") +#define JK_STATUS_ARG_LB_STICKY ("vls") +#define JK_STATUS_ARG_LB_STICKY_FORCE ("vlf") +#define JK_STATUS_ARG_LB_METHOD ("vlm") +#define JK_STATUS_ARG_LB_LOCK ("vll") + +#define JK_STATUS_ARG_LB_TEXT_RETRIES "Retries" +#define JK_STATUS_ARG_LB_TEXT_RETRY_INT "Retry Interval" +#define JK_STATUS_ARG_LB_TEXT_RECOVER_TIME "Recover Wait Time" +#define JK_STATUS_ARG_LB_TEXT_ERROR_ESCALATION_TIME "Error Escalation Time" +#define JK_STATUS_ARG_LB_TEXT_MAX_REPLY_TIMEOUTS "Max Reply Timeouts" +#define JK_STATUS_ARG_LB_TEXT_STICKY "Sticky Sessions" +#define JK_STATUS_ARG_LB_TEXT_STICKY_FORCE "Force Sticky Sessions" +#define JK_STATUS_ARG_LB_TEXT_METHOD "LB Method" +#define JK_STATUS_ARG_LB_TEXT_LOCK "Locking" + +#define JK_STATUS_ARG_LBM_ACTIVATION ("vwa") +#define JK_STATUS_ARG_LBM_FACTOR ("vwf") +#define JK_STATUS_ARG_LBM_ROUTE ("vwn") +#define JK_STATUS_ARG_LBM_REDIRECT ("vwr") +#define JK_STATUS_ARG_LBM_DOMAIN ("vwc") +#define JK_STATUS_ARG_LBM_DISTANCE ("vwd") + +#define JK_STATUS_ARG_LBM_TEXT_ACTIVATION "Activation" +#define JK_STATUS_ARG_LBM_TEXT_FACTOR "LB Factor" +#define JK_STATUS_ARG_LBM_TEXT_ROUTE "Route" +#define JK_STATUS_ARG_LBM_TEXT_REDIRECT "Redirect Route" +#define JK_STATUS_ARG_LBM_TEXT_DOMAIN "Cluster Domain" +#define JK_STATUS_ARG_LBM_TEXT_DISTANCE "Distance" + +#define JK_STATUS_ARG_AJP_CACHE_TO "vacpt" +#define JK_STATUS_ARG_AJP_PING_TO "vapng" +#define JK_STATUS_ARG_AJP_CONNECT_TO "vact" +#define JK_STATUS_ARG_AJP_PREPOST_TO "vapt" +#define JK_STATUS_ARG_AJP_REPLY_TO "vart" +#define JK_STATUS_ARG_AJP_RETRIES "var" +#define JK_STATUS_ARG_AJP_RETRY_INT "vari" +#define JK_STATUS_ARG_AJP_REC_OPTS "varo" +#define JK_STATUS_ARG_AJP_MAX_PK_SZ "vamps" +#define JK_STATUS_ARG_AJP_CPING_INT "vacpi" +#define JK_STATUS_ARG_AJP_HOST_STR "vahst" +#define JK_STATUS_ARG_AJP_PORT "vaprt" + +#define JK_STATUS_ARG_AJP_TEXT_CACHE_TO "Connection Pool Timeout" +#define JK_STATUS_ARG_AJP_TEXT_PING_TO "Ping Timeout" +#define JK_STATUS_ARG_AJP_TEXT_CONNECT_TO "Connect Timeout" +#define JK_STATUS_ARG_AJP_TEXT_PREPOST_TO "Prepost Timeout" +#define JK_STATUS_ARG_AJP_TEXT_REPLY_TO "Reply Timeout" +#define JK_STATUS_ARG_AJP_TEXT_RETRIES "Retries" +#define JK_STATUS_ARG_AJP_TEXT_RETRY_INT "Retry Interval" +#define JK_STATUS_ARG_AJP_TEXT_REC_OPTS "Recovery Options" +#define JK_STATUS_ARG_AJP_TEXT_MAX_PK_SZ "Max Packet Size" +#define JK_STATUS_ARG_AJP_TEXT_CPING_INT "Connection Ping Interval" +#define JK_STATUS_ARG_AJP_TEXT_HOST_STR "Hostname" +#define JK_STATUS_ARG_AJP_TEXT_PORT "Port" +#define JK_STATUS_ARG_AJP_TEXT_ADDR_STR "Address:Port" + +#define JK_STATUS_CMD_UNKNOWN (0) +#define JK_STATUS_CMD_LIST (1) +#define JK_STATUS_CMD_SHOW (2) +#define JK_STATUS_CMD_EDIT (3) +#define JK_STATUS_CMD_UPDATE (4) +#define JK_STATUS_CMD_RESET (5) +#define JK_STATUS_CMD_VERSION (6) +#define JK_STATUS_CMD_RECOVER (7) +#define JK_STATUS_CMD_DUMP (8) +#define JK_STATUS_CMD_DEF (JK_STATUS_CMD_LIST) +#define JK_STATUS_CMD_MAX (JK_STATUS_CMD_DUMP) +#define JK_STATUS_CMD_TEXT_UNKNOWN ("unknown") +#define JK_STATUS_CMD_TEXT_LIST ("list") +#define JK_STATUS_CMD_TEXT_SHOW ("show") +#define JK_STATUS_CMD_TEXT_EDIT ("edit") +#define JK_STATUS_CMD_TEXT_UPDATE ("update") +#define JK_STATUS_CMD_TEXT_RESET ("reset") +#define JK_STATUS_CMD_TEXT_VERSION ("version") +#define JK_STATUS_CMD_TEXT_RECOVER ("recover") +#define JK_STATUS_CMD_TEXT_DUMP ("dump") +#define JK_STATUS_CMD_TEXT_DEF (JK_STATUS_CMD_TEXT_LIST) + +#define JK_STATUS_CMD_PROP_CHECK_WORKER 0x00000001 +#define JK_STATUS_CMD_PROP_READONLY 0x00000002 +#define JK_STATUS_CMD_PROP_HEAD 0x00000004 +#define JK_STATUS_CMD_PROP_REFRESH 0x00000008 +#define JK_STATUS_CMD_PROP_BACK_LINK 0x00000010 +#define JK_STATUS_CMD_PROP_BACK_LIST 0x00000020 +#define JK_STATUS_CMD_PROP_FMT 0x00000040 +#define JK_STATUS_CMD_PROP_SWITCH_RO 0x00000080 +#define JK_STATUS_CMD_PROP_DUMP_LINK 0x00000100 +#define JK_STATUS_CMD_PROP_LINK_HELP 0x00000200 +#define JK_STATUS_CMD_PROP_LEGEND 0x00000400 +#define JK_STATUS_CMD_PROP_WILDCARD 0x00000800 + +#define JK_STATUS_MIME_UNKNOWN (0) +#define JK_STATUS_MIME_HTML (1) +#define JK_STATUS_MIME_XML (2) +#define JK_STATUS_MIME_TXT (3) +#define JK_STATUS_MIME_PROP (4) +#define JK_STATUS_MIME_DEF (JK_STATUS_MIME_HTML) +#define JK_STATUS_MIME_MAX (JK_STATUS_MIME_PROP) +#define JK_STATUS_MIME_TEXT_UNKNOWN ("unknown") +#define JK_STATUS_MIME_TEXT_HTML ("html") +#define JK_STATUS_MIME_TEXT_XML ("xml") +#define JK_STATUS_MIME_TEXT_TXT ("txt") +#define JK_STATUS_MIME_TEXT_PROP ("prop") +#define JK_STATUS_MIME_TEXT_DEF (JK_STATUS_MIME_TEXT_HTML) + +#define JK_STATUS_MASK_ACTIVE 0x000000FF +#define JK_STATUS_MASK_DISABLED 0x0000FF00 +#define JK_STATUS_MASK_STOPPED 0x00FF0000 +#define JK_STATUS_MASK_OK 0x00010101 +#define JK_STATUS_MASK_IDLE 0x00020202 +#define JK_STATUS_MASK_BUSY 0x00040404 +#define JK_STATUS_MASK_RECOVER 0x00080808 +#define JK_STATUS_MASK_ERROR 0x00101010 +#define JK_STATUS_MASK_GOOD_DEF 0x0000000F +#define JK_STATUS_MASK_BAD_DEF 0x00FF1010 + +#define JK_STATUS_NEEDS_PUSH 0x00000001 +#define JK_STATUS_NEEDS_RESET_LB_VALUES 0x00000002 +#define JK_STATUS_NEEDS_UPDATE_MULT 0x00000004 +#define JK_STATUS_NEEDS_ADDR_PUSH 0x00000008 + +#define JK_STATUS_WAIT_AFTER_UPDATE "3" +#define JK_STATUS_REFRESH_DEF "10" +#define JK_STATUS_ESC_CHARS ("<>?\"") +#define JK_STATUS_TIME_FMT_HTML "%a, %d %b %Y %X %Z" +#define JK_STATUS_TIME_FMT_TEXT "%Y%m%d%H%M%S" +#define JK_STATUS_TIME_FMT_TZ "%Z" +#define JK_STATUS_TIME_BUF_SZ (80) + +#define JK_STATUS_HEAD "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n" \ + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"" \ + " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" \ + "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">" \ + "<head><title>JK Status Manager</title>" + +#define JK_STATUS_COPYRIGHT "Copyright © 1999-2011, The Apache Software Foundation<br />" \ + "Licensed under the <a href=\"http://www.apache.org/licenses/LICENSE-2.0\">" \ + "Apache License, Version 2.0</a>." + +#define JK_STATUS_HEND "</head>\n<body>\n" +#define JK_STATUS_BEND "</body>\n</html>\n" + +#define JK_STATUS_XMLH "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + +#define JK_STATUS_NS_DEF "jk:" +#define JK_STATUS_XMLNS_DEF "xmlns:jk=\"http://tomcat.apache.org\"" +#define JK_STATUS_PREFIX_DEF "worker" + +#define JK_STATUS_FORM_START "<form method=\"%s\" action=\"%s\">\n" +#define JK_STATUS_FORM_HIDDEN_INT "<input type=\"hidden\" name=\"%s\" value=\"%d\"/>\n" +#define JK_STATUS_FORM_HIDDEN_STRING "<input type=\"hidden\" name=\"%s\" value=\"%s\"/>\n" +#define JK_STATUS_URI_MAP_TABLE_HEAD "<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>\n" +#define JK_STATUS_URI_MAP_TABLE_ROW "<tr><td>%s</td><td>%s</td><td>%s</td><td>%d</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%d</td></tr>\n" +#define JK_STATUS_URI_MAP_TABLE_HEAD2 "<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>\n" +#define JK_STATUS_URI_MAP_TABLE_ROW2 "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%d</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%d</td></tr>\n" +#define JK_STATUS_SHOW_AJP_CONF_HEAD "<tr>" \ + "<th>Type</th>" \ + "<th>" JK_STATUS_ARG_AJP_TEXT_HOST_STR "</th>" \ + "<th>" JK_STATUS_ARG_AJP_TEXT_ADDR_STR "</th>" \ + "<th>" JK_STATUS_ARG_AJP_TEXT_CACHE_TO "</th>" \ + "<th>" JK_STATUS_ARG_AJP_TEXT_CONNECT_TO "</th>" \ + "<th>" JK_STATUS_ARG_AJP_TEXT_PREPOST_TO "</th>" \ + "<th>" JK_STATUS_ARG_AJP_TEXT_REPLY_TO "</th>" \ + "<th>" JK_STATUS_ARG_AJP_TEXT_RETRIES "</th>" \ + "<th>" JK_STATUS_ARG_AJP_TEXT_REC_OPTS "</th>" \ + "<th>" JK_STATUS_ARG_AJP_TEXT_MAX_PK_SZ "</th>" \ + "<th>\n" +#define JK_STATUS_SHOW_AJP_CONF_ROW "<tr>" \ + "<td>%s</td>" \ + "<td>%s</td>" \ + "<td>%s</td>" \ + "<td>%d</td>" \ + "<td>%d</td>" \ + "<td>%d</td>" \ + "<td>%d</td>" \ + "<td>%u</td>" \ + "<td>%u</td>" \ + "<td></td>" \ + "</tr>\n" +#define JK_STATUS_SHOW_AJP_HEAD "<tr>" \ + "<th>State</th>" \ + "<th>Acc</th>" \ + "<th>Err</th><th>CE</th><th>RE</th>" \ + "<th>Wr</th><th>Rd</th><th>Busy</th><th>Max</th><th>Con</th><th>LR</th><th>LE</th>" \ + "</tr>\n" +#define JK_STATUS_SHOW_AJP_ROW "<tr>" \ + "<td>%s</td>" \ + "<td>%" JK_UINT64_T_FMT " (%d/sec)</td>" \ + "<td>%" JK_UINT32_T_FMT "</td>" \ + "<td>%" JK_UINT32_T_FMT "</td>" \ + "<td>%" JK_UINT32_T_FMT "</td>" \ + "<td>%s (%s/sec)</td>" \ + "<td>%s (%s/sec)</td>" \ + "<td>%d</td>" \ + "<td>%d</td>" \ + "<td>%d</td>" \ + "<td>%d</td>" \ + "<td>%s</td>" \ + "</tr>\n" +#define JK_STATUS_SHOW_LB_HEAD "<tr>" \ + "<th>Type</th>" \ + "<th>" JK_STATUS_ARG_LB_TEXT_STICKY "</th>" \ + "<th>" JK_STATUS_ARG_LB_TEXT_STICKY_FORCE "</th>" \ + "<th>" JK_STATUS_ARG_LB_TEXT_RETRIES "</th>" \ + "<th>" JK_STATUS_ARG_LB_TEXT_METHOD "</th>" \ + "<th>" JK_STATUS_ARG_LB_TEXT_LOCK "</th>" \ + "<th>" JK_STATUS_ARG_LB_TEXT_RECOVER_TIME "</th>" \ + "<th>" JK_STATUS_ARG_LB_TEXT_ERROR_ESCALATION_TIME "</th>" \ + "<th>" JK_STATUS_ARG_LB_TEXT_MAX_REPLY_TIMEOUTS "</th>" \ + "<th>\n" +#define JK_STATUS_SHOW_LB_ROW "<tr>" \ + "<td>%s</td>" \ + "<td>%s</td>" \ + "<td>%s</td>" \ + "<td>%d</td>" \ + "<td>%s</td>" \ + "<td>%s</td>" \ + "<td>%d</td>" \ + "<td>%d</td>" \ + "<td>%d</td>" \ + "<td></td>" \ + "</tr>\n" +#define JK_STATUS_SHOW_MEMBER_HEAD "<tr>" \ + "<th> </th><th>Name</th>" \ + "<th>Act</th><th>State</th>" \ + "<th>D</th><th>F</th><th>M</th>" \ + "<th>V</th><th>Acc</th>" \ + "<th>Err</th><th>CE</th><th>RE</th>" \ + "<th>Wr</th><th>Rd</th><th>Busy</th><th>Max</th><th>Con</th>" \ + "<th>" JK_STATUS_ARG_LBM_TEXT_ROUTE "</th>" \ + "<th>RR</th><th>Cd</th><th>Rs</th><th>LR</th><th>LE</th>" \ + "</tr>\n" +#define JK_STATUS_SHOW_MEMBER_ROW "<td>%s</td>" \ + "<td>%s</td>" \ + "<td>%s</td>" \ + "<td>%d</td>" \ + "<td>%d</td>" \ + "<td>%" JK_UINT64_T_FMT "</td>" \ + "<td>%" JK_UINT64_T_FMT "</td>" \ + "<td>%" JK_UINT64_T_FMT " (%d/sec)</td>" \ + "<td>%" JK_UINT32_T_FMT "</td>" \ + "<td>%" JK_UINT32_T_FMT "</td>" \ + "<td>%" JK_UINT32_T_FMT "</td>" \ + "<td>%s (%s/sec)</td>" \ + "<td>%s (%s/sec)</td>" \ + "<td>%d</td>" \ + "<td>%d</td>" \ + "<td>%d</td>" \ + "<td>%s</td>" \ + "<td>%s</td>" \ + "<td>%s</td>" \ + "<td>%d/%d</td>" \ + "<td>%d</td>" \ + "<td>%s</td>" \ + "</tr>\n" +#define JK_STATUS_SHOW_MEMBER_CONF_HEAD "<tr>" \ + "<th>Name</th><th>Type</th>" \ + "<th>" JK_STATUS_ARG_AJP_TEXT_HOST_STR "</th>" \ + "<th>" JK_STATUS_ARG_AJP_TEXT_ADDR_STR "</th>" \ + "<th>" JK_STATUS_ARG_AJP_TEXT_CACHE_TO "</th>" \ + "<th>" JK_STATUS_ARG_AJP_TEXT_CONNECT_TO "</th>" \ + "<th>" JK_STATUS_ARG_AJP_TEXT_PREPOST_TO "</th>" \ + "<th>" JK_STATUS_ARG_AJP_TEXT_REPLY_TO "</th>" \ + "<th>" JK_STATUS_ARG_AJP_TEXT_RETRIES "</th>" \ + "<th>" JK_STATUS_ARG_AJP_TEXT_REC_OPTS "</th>" \ + "<th>" JK_STATUS_ARG_AJP_TEXT_MAX_PK_SZ "</th>" \ + "<th>\n" +#define JK_STATUS_SHOW_MEMBER_CONF_ROW "<tr>" \ + "<td>%s</td>" \ + "<td>%s</td>" \ + "<td>%s</td>" \ + "<td>%s</td>" \ + "<td>%d</td>" \ + "<td>%d</td>" \ + "<td>%d</td>" \ + "<td>%d</td>" \ + "<td>%d</td>" \ + "<td>%u</td>" \ + "<td>%u</td>" \ + "<td></td>" \ + "</tr>\n" + +typedef struct status_worker status_worker_t; + +struct status_endpoint +{ + status_worker_t *worker; + + char *query_string; + jk_map_t *req_params; + char *msg; + + jk_endpoint_t endpoint; + +}; + +typedef struct status_endpoint status_endpoint_t; + +struct status_worker +{ + jk_pool_t p; + jk_pool_atom_t buf[TINY_POOL_SIZE]; + const char *name; + const char *css; + const char *ns; + const char *xmlns; + const char *doctype; + const char *prefix; + int read_only; + char **user_names; + unsigned int num_of_users; + int user_case_insensitive; + jk_uint32_t good_mask; + jk_uint32_t bad_mask; + jk_worker_t worker; + jk_worker_env_t *we; +}; + +static const char *worker_type[] = { + "unknown", + "ajp12", + "ajp13", + "ajp14", + "jni", + "lb", + "status", + NULL +}; + +static const char *headers_names[] = { + "Content-Type", + "Cache-Control", + "Pragma", + NULL +}; + +static const char *cmd_type[] = { + JK_STATUS_CMD_TEXT_UNKNOWN, + JK_STATUS_CMD_TEXT_LIST, + JK_STATUS_CMD_TEXT_SHOW, + JK_STATUS_CMD_TEXT_EDIT, + JK_STATUS_CMD_TEXT_UPDATE, + JK_STATUS_CMD_TEXT_RESET, + JK_STATUS_CMD_TEXT_VERSION, + JK_STATUS_CMD_TEXT_RECOVER, + JK_STATUS_CMD_TEXT_DUMP, + NULL +}; + +static const char *mime_type[] = { + JK_STATUS_MIME_TEXT_UNKNOWN, + JK_STATUS_MIME_TEXT_HTML, + JK_STATUS_MIME_TEXT_XML, + JK_STATUS_MIME_TEXT_TXT, + JK_STATUS_MIME_TEXT_PROP, + NULL +}; + +#define HEADERS_NO_CACHE "no-cache", "no-cache", NULL + +static const char *headers_vhtml[] = { + "text/html", + HEADERS_NO_CACHE +}; + +static const char *headers_vxml[] = { + "text/xml", + HEADERS_NO_CACHE +}; + +static const char *headers_vtxt[] = { + "text/plain", + HEADERS_NO_CACHE +}; + +static void jk_puts(jk_ws_service_t *s, const char *str) +{ + if (str) + s->write(s, str, (unsigned int)strlen(str)); + else + s->write(s, "(null)", 6); +} + +static void jk_putv(jk_ws_service_t *s, ...) +{ + va_list va; + const char *str; + + va_start(va, s); + while (1) { + str = va_arg(va, const char *); + if (str == NULL) + break; + s->write(s, str, (unsigned int)strlen(str)); + } + va_end(va); +} + +static int jk_printf(jk_ws_service_t *s, const char *fmt, ...) +{ + int rc = 0; + va_list args; +#ifdef NETWARE +/* On NetWare, this can get called on a thread that has a limited stack so */ +/* we will allocate and free the temporary buffer in this function */ + char *buf; +#else + char buf[HUGE_BUFFER_SIZE]; +#endif + + if (!s || !fmt) { + return -1; + } + va_start(args, fmt); + +#ifdef NETWARE + buf = (char *)malloc(HUGE_BUFFER_SIZE); + if (NULL == buf) + return -1; +#endif + rc = vsnprintf(buf, HUGE_BUFFER_SIZE, fmt, args); + va_end(args); + if (rc > 0) + s->write(s, buf, rc); +#ifdef NETWARE + free(buf); +#endif + return rc; +} + +static void jk_print_xml_start_elt(jk_ws_service_t *s, status_worker_t *w, + int indentation, int close_tag, + const char *name) +{ + if (close_tag) { + jk_printf(s, "%*s<%s%s>\n", indentation, "", w->ns, name); + } + else { + jk_printf(s, "%*s<%s%s\n", indentation, "", w->ns, name); + } +} + +static void jk_print_xml_close_elt(jk_ws_service_t *s, status_worker_t *w, + int indentation, + const char *name) +{ + jk_printf(s, "%*s</%s%s>\n", indentation, "", w->ns, name); +} + +static void jk_print_xml_stop_elt(jk_ws_service_t *s, + int indentation, int close_tag) +{ + if (close_tag) { + jk_printf(s, "%*s/>\n", indentation, ""); + } + else { + jk_printf(s, "%*s>\n", indentation, ""); + } +} + +static void jk_print_xml_att_string(jk_ws_service_t *s, + int indentation, + const char *key, const char *value) +{ + jk_printf(s, "%*s%s=\"%s\"\n", indentation, "", key, value ? value : ""); +} + +static void jk_print_xml_att_int(jk_ws_service_t *s, + int indentation, + const char *key, int value) +{ + jk_printf(s, "%*s%s=\"%d\"\n", indentation, "", key, value); +} + +static void jk_print_xml_att_uint(jk_ws_service_t *s, + int indentation, + const char *key, unsigned int value) +{ + jk_printf(s, "%*s%s=\"%u\"\n", indentation, "", key, value); +} + +static void jk_print_xml_att_long(jk_ws_service_t *s, + int indentation, + const char *key, long value) +{ + jk_printf(s, "%*s%s=\"%ld\"\n", indentation, "", key, value); +} + +static void jk_print_xml_att_uint32(jk_ws_service_t *s, + int indentation, + const char *key, jk_uint32_t value) +{ + jk_printf(s, "%*s%s=\"%" JK_UINT32_T_FMT "\"\n", indentation, "", key, value); +} + +static void jk_print_xml_att_uint64(jk_ws_service_t *s, + int indentation, + const char *key, jk_uint64_t value) +{ + jk_printf(s, "%*s%s=\"%" JK_UINT64_T_FMT "\"\n", indentation, "", key, value); +} + +static void jk_print_prop_att_string(jk_ws_service_t *s, status_worker_t *w, + const char *name, + const char *key, const char *value) +{ + if (name) { + jk_printf(s, "%s.%s.%s=%s\n", w->prefix, name, key, value ? value : ""); + } + else { + jk_printf(s, "%s.%s=%s\n", w->prefix, key, value ? value : ""); + } +} + +static void jk_print_prop_att_int(jk_ws_service_t *s, status_worker_t *w, + const char *name, + const char *key, int value) +{ + if (name) { + jk_printf(s, "%s.%s.%s=%d\n", w->prefix, name, key, value); + } + else { + jk_printf(s, "%s.%s=%d\n", w->prefix, key, value); + } +} + +static void jk_print_prop_att_uint(jk_ws_service_t *s, status_worker_t *w, + const char *name, + const char *key, unsigned int value) +{ + if (name) { + jk_printf(s, "%s.%s.%s=%u\n", w->prefix, name, key, value); + } + else { + jk_printf(s, "%s.%s=%u\n", w->prefix, key, value); + } +} + +static void jk_print_prop_att_long(jk_ws_service_t *s, status_worker_t *w, + const char *name, + const char *key, long value) +{ + if (name) { + jk_printf(s, "%s.%s.%s=%ld\n", w->prefix, name, key, value); + } + else { + jk_printf(s, "%s.%s=%ld\n", w->prefix, key, value); + } +} + +static void jk_print_prop_att_uint32(jk_ws_service_t *s, status_worker_t *w, + const char *name, + const char *key, jk_uint32_t value) +{ + if (name) { + jk_printf(s, "%s.%s.%s=%" JK_UINT32_T_FMT "\n", w->prefix, name, key, value); + } + else { + jk_printf(s, "%s.%s=%" JK_UINT32_T_FMT "\n", w->prefix, key, value); + } +} + +static void jk_print_prop_att_uint64(jk_ws_service_t *s, status_worker_t *w, + const char *name, + const char *key, jk_uint64_t value) +{ + if (name) { + jk_printf(s, "%s.%s.%s=%" JK_UINT64_T_FMT "\n", w->prefix, name, key, value); + } + else { + jk_printf(s, "%s.%s=%" JK_UINT64_T_FMT "\n", w->prefix, key, value); + } +} + +static void jk_print_prop_item_int(jk_ws_service_t *s, status_worker_t *w, + const char *name, const char *list, int num, + const char *key, int value) +{ + if (name) { + jk_printf(s, "%s.%s.%s.%d.%s=%d\n", w->prefix, name, list, num, key, value); + } + else { + jk_printf(s, "%s.%s.%d.%s=%d\n", w->prefix, list, num, key, value); + } +} + +static void jk_print_prop_item_string(jk_ws_service_t *s, status_worker_t *w, + const char *name, const char *list, int num, + const char *key, const char *value) +{ + if (name) { + jk_printf(s, "%s.%s.%s.%d.%s=%s\n", w->prefix, name, list, num, key, value ? value : ""); + } + else { + jk_printf(s, "%s.%s.%d.%s=%s\n", w->prefix, list, num, key, value ? value : ""); + } +} + +/* Actually APR's apr_strfsize */ +static char *status_strfsize(jk_uint64_t size, char *buf) +{ + const char ord[] = "KMGTPE"; + const char *o = ord; + unsigned int remain, siz; + + if (size < 973) { + if (sprintf(buf, "%d ", (int) size) < 0) + return strcpy(buf, "****"); + return buf; + } + do { + remain = (unsigned int)(size & 0x03FF); + size >>= 10; + if (size >= 973) { + ++o; + continue; + } + siz = (unsigned int)(size & 0xFFFF); + if (siz < 9 || (siz == 9 && remain < 973)) { + if ((remain = ((remain * 5) + 256) / 512) >= 10) + ++siz, remain = 0; + if (sprintf(buf, "%d.%d%c", siz, remain, *o) < 0) + return strcpy(buf, "****"); + return buf; + } + if (remain >= 512) + ++siz; + if (sprintf(buf, "%d%c", siz, *o) < 0) + return strcpy(buf, "****"); + return buf; + } while (1); +} + +static int status_strftime(time_t clock, int mime, char *buf_time, char *buf_tz, + jk_logger_t *l) +{ + size_t rc_time; +#ifdef _MT_CODE_PTHREAD + struct tm res; + struct tm *tms = localtime_r(&clock, &res); +#else + struct tm *tms = localtime(&clock); +#endif + + JK_TRACE_ENTER(l); + + if (mime == JK_STATUS_MIME_HTML) + rc_time = strftime(buf_time, JK_STATUS_TIME_BUF_SZ, JK_STATUS_TIME_FMT_HTML, tms); + else { + rc_time = strftime(buf_time, JK_STATUS_TIME_BUF_SZ, JK_STATUS_TIME_FMT_TEXT, tms); + } + strftime(buf_tz, JK_STATUS_TIME_BUF_SZ, JK_STATUS_TIME_FMT_TZ, tms); + + JK_TRACE_EXIT(l); + return (int)rc_time; + +} + +static int status_rate(lb_sub_worker_t *wr, status_worker_t *w, + jk_logger_t *l) +{ + jk_uint32_t mask = 0; + int activation = wr->activation; + int state = wr->s->state; + jk_uint32_t good = w->good_mask; + jk_uint32_t bad = w->bad_mask; + int rv = 0; + + switch (activation) + { + case JK_LB_ACTIVATION_ACTIVE: + mask = JK_STATUS_MASK_ACTIVE; + break; + case JK_LB_ACTIVATION_DISABLED: + mask = JK_STATUS_MASK_DISABLED; + break; + case JK_LB_ACTIVATION_STOPPED: + mask = JK_STATUS_MASK_STOPPED; + break; + default: + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' unknown activation type '%d'", + w->name, activation); + } + switch (state) + { + case JK_LB_STATE_IDLE: + mask &= JK_STATUS_MASK_IDLE; + break; + case JK_LB_STATE_OK: + mask &= JK_STATUS_MASK_OK; + break; + case JK_LB_STATE_RECOVER: + mask &= JK_STATUS_MASK_RECOVER; + break; + case JK_LB_STATE_FORCE: + mask &= JK_STATUS_MASK_RECOVER; + break; + case JK_LB_STATE_BUSY: + mask &= JK_STATUS_MASK_BUSY; + break; + case JK_LB_STATE_ERROR: + mask &= JK_STATUS_MASK_ERROR; + break; + case JK_LB_STATE_PROBE: + mask &= JK_STATUS_MASK_RECOVER; + break; + default: + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' unknown state type '%d'", + w->name, state); + } + if (mask&bad) + rv = -1; + else if (mask&good) + rv = 1; + else + rv = 0; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' rating of activation '%s' and state '%s' for good '%08" JK_UINT32_T_HEX_FMT + "' and bad '%08" JK_UINT32_T_HEX_FMT "' is %d", + w->name, jk_lb_get_activation(wr, l), jk_lb_get_state(wr, l), + good, bad, rv); + return rv; +} + +static jk_uint32_t status_get_single_rating(const char rating, jk_logger_t *l) +{ + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "rating retrieval for '%c'", + rating); + switch (rating) + { + case 'A': + case 'a': + return JK_STATUS_MASK_ACTIVE; + case 'D': + case 'd': + return JK_STATUS_MASK_DISABLED; + case 'S': + case 's': + return JK_STATUS_MASK_STOPPED; + case 'O': + case 'o': + return JK_STATUS_MASK_OK; + case 'I': + case 'i': + case 'N': + case 'n': + return JK_STATUS_MASK_IDLE; + case 'B': + case 'b': + return JK_STATUS_MASK_BUSY; + case 'R': + case 'r': + return JK_STATUS_MASK_RECOVER; + case 'E': + case 'e': + return JK_STATUS_MASK_ERROR; + default: + jk_log(l, JK_LOG_WARNING, + "Unknown rating type '%c'", + rating); + return 0; + } +} + +static jk_uint32_t status_get_rating(const char *rating, + jk_logger_t *l) +{ + int off = 0; + jk_uint32_t mask = 0; + + while (rating[off] == ' ' || rating[off] == '\t' || rating[off] == '.') { + off++; + } + mask = status_get_single_rating(rating[off], l); + while (rating[off] != '\0' && rating[off] != '.') { + off++; + } + if (rating[off] == '.') { + off++; + } + if (rating[off] != '\0') { + mask &= status_get_single_rating(rating[off], l); + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "rating for '%s' is '%08" JK_UINT32_T_HEX_FMT "'", + rating, mask); + return mask; +} + +static const char *status_worker_type(int t) +{ + if (t < 0 || t > 6) + t = 0; + return worker_type[t]; +} + + +static int status_get_string(status_endpoint_t *p, + const char *param, + const char *def, + const char **result, + jk_logger_t *l) +{ + int rv; + + *result = jk_map_get_string(p->req_params, + param, NULL); + if (*result) { + rv = JK_TRUE; + } + else { + *result = def; + rv = JK_FALSE; + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "retrieved string arg '%s' as '%s'%s", + param, *result ? *result : "(null)", + rv == JK_FALSE ? " (default)" : ""); + return rv; +} + +static int status_get_int(status_endpoint_t *p, + const char *param, + int def, + jk_logger_t *l) +{ + const char *arg; + int rv = def; + + if (status_get_string(p, param, NULL, &arg, l) == JK_TRUE) { + rv = atoi(arg); + } + return rv; +} + +static int status_get_bool(status_endpoint_t *p, + const char *param, + int def, + jk_logger_t *l) +{ + const char *arg; + + if (status_get_string(p, param, NULL, &arg, l) == JK_TRUE) { + return jk_get_bool_code(arg, def); + } + return def; +} + +static const char *status_cmd_text(int cmd) +{ + return cmd_type[cmd]; +} + +static int status_cmd_int(const char *cmd) +{ + if (!cmd) + return JK_STATUS_CMD_DEF; + if (!strcmp(cmd, JK_STATUS_CMD_TEXT_LIST)) + return JK_STATUS_CMD_LIST; + else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_SHOW)) + return JK_STATUS_CMD_SHOW; + else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_EDIT)) + return JK_STATUS_CMD_EDIT; + else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_UPDATE)) + return JK_STATUS_CMD_UPDATE; + else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_RESET)) + return JK_STATUS_CMD_RESET; + else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_VERSION)) + return JK_STATUS_CMD_VERSION; + else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_RECOVER)) + return JK_STATUS_CMD_RECOVER; + else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_DUMP)) + return JK_STATUS_CMD_DUMP; + return JK_STATUS_CMD_UNKNOWN; +} + +static const char *status_mime_text(int mime) +{ + return mime_type[mime]; +} + +static int status_mime_int(const char *mime) +{ + if (!mime) + return JK_STATUS_MIME_DEF; + if (!strcmp(mime, JK_STATUS_MIME_TEXT_HTML)) + return JK_STATUS_MIME_HTML; + else if (!strcmp(mime, JK_STATUS_MIME_TEXT_XML)) + return JK_STATUS_MIME_XML; + else if (!strcmp(mime, JK_STATUS_MIME_TEXT_TXT)) + return JK_STATUS_MIME_TXT; + else if (!strcmp(mime, JK_STATUS_MIME_TEXT_PROP)) + return JK_STATUS_MIME_PROP; + return JK_STATUS_MIME_UNKNOWN; +} + +static jk_uint32_t status_cmd_props(int cmd) +{ + jk_uint32_t props = 0; + + if (cmd == JK_STATUS_CMD_LIST || + cmd == JK_STATUS_CMD_SHOW) + props |= JK_STATUS_CMD_PROP_REFRESH | + JK_STATUS_CMD_PROP_SWITCH_RO | + JK_STATUS_CMD_PROP_LINK_HELP | + JK_STATUS_CMD_PROP_LEGEND; + if (cmd == JK_STATUS_CMD_LIST || + cmd == JK_STATUS_CMD_SHOW || + cmd == JK_STATUS_CMD_VERSION) + props |= JK_STATUS_CMD_PROP_DUMP_LINK; + if (cmd == JK_STATUS_CMD_LIST || + cmd == JK_STATUS_CMD_SHOW || + cmd == JK_STATUS_CMD_VERSION || + cmd == JK_STATUS_CMD_DUMP) + props |= JK_STATUS_CMD_PROP_HEAD | + JK_STATUS_CMD_PROP_FMT; + if (cmd == JK_STATUS_CMD_SHOW || + cmd == JK_STATUS_CMD_VERSION || + cmd == JK_STATUS_CMD_DUMP) + props |= JK_STATUS_CMD_PROP_BACK_LIST; + if (cmd == JK_STATUS_CMD_SHOW || + cmd == JK_STATUS_CMD_EDIT || + cmd == JK_STATUS_CMD_VERSION || + cmd == JK_STATUS_CMD_DUMP) + props |= JK_STATUS_CMD_PROP_BACK_LINK; + if (cmd == JK_STATUS_CMD_UPDATE) + props |= JK_STATUS_CMD_PROP_WILDCARD; + if (cmd != JK_STATUS_CMD_EDIT && + cmd != JK_STATUS_CMD_UPDATE && + cmd != JK_STATUS_CMD_RESET && + cmd != JK_STATUS_CMD_RECOVER) + props |= JK_STATUS_CMD_PROP_READONLY; + if (cmd != JK_STATUS_CMD_LIST && + cmd != JK_STATUS_CMD_VERSION && + cmd != JK_STATUS_CMD_DUMP) + props |= JK_STATUS_CMD_PROP_CHECK_WORKER; + + return props; +} + +static void status_start_form(jk_ws_service_t *s, + status_endpoint_t *p, + const char *method, + int cmd, + const char *overwrite, + jk_logger_t *l) +{ + + int i; + int sz; + jk_map_t *m = p->req_params; + + if (method) + jk_printf(s, JK_STATUS_FORM_START, method, s->req_uri); + else + return; + if (cmd != JK_STATUS_CMD_UNKNOWN) { + jk_printf(s, JK_STATUS_FORM_HIDDEN_STRING, + JK_STATUS_ARG_CMD, status_cmd_text(cmd)); + } + + sz = jk_map_size(m); + for (i = 0; i < sz; i++) { + const char *k = jk_map_name_at(m, i); + const char *v = jk_map_value_at(m, i); + if ((strcmp(k, JK_STATUS_ARG_CMD) || + cmd == JK_STATUS_CMD_UNKNOWN) && + (!overwrite || + strcmp(k, overwrite))) { + jk_printf(s, JK_STATUS_FORM_HIDDEN_STRING, k, v); + } + } +} + +static void status_write_uri(jk_ws_service_t *s, + status_endpoint_t *p, + const char *text, + int cmd, int mime, + const char *worker, const char *sub_worker, + unsigned int add_options, unsigned int rm_options, + const char *attribute, + jk_logger_t *l) +{ + int i; + int sz; + int started = 0; + int from; + int restore_sub_worker = JK_FALSE; + int save_sub_worker = JK_FALSE; + int prev; + unsigned int opt = 0; + const char *arg; + jk_map_t *m = p->req_params; + + if (text) + jk_puts(s, "<a href=\""); + jk_puts(s, s->req_uri); + status_get_string(p, JK_STATUS_ARG_FROM, NULL, &arg, l); + from = status_cmd_int(arg); + status_get_string(p, JK_STATUS_ARG_CMD, NULL, &arg, l); + prev = status_cmd_int(arg); + if (cmd == JK_STATUS_CMD_SHOW && prev == JK_STATUS_CMD_EDIT) { + restore_sub_worker = JK_TRUE; + } + if (cmd == JK_STATUS_CMD_UNKNOWN) { + if (prev == JK_STATUS_CMD_UPDATE || + prev == JK_STATUS_CMD_RESET || + prev == JK_STATUS_CMD_RECOVER) { + cmd = from; + restore_sub_worker = JK_TRUE; + } + } + if (cmd != JK_STATUS_CMD_UNKNOWN) { + jk_printf(s, "%s%s=%s", started ? "&" : "?", + JK_STATUS_ARG_CMD, status_cmd_text(cmd)); + if (cmd == JK_STATUS_CMD_EDIT || + cmd == JK_STATUS_CMD_RESET || + cmd == JK_STATUS_CMD_RECOVER) { + jk_printf(s, "%s%s=%s", "&", + JK_STATUS_ARG_FROM, status_cmd_text(prev)); + save_sub_worker = JK_TRUE; + } + started=1; + } + if (mime != JK_STATUS_MIME_UNKNOWN) { + jk_printf(s, "%s%s=%s", started ? "&" : "?", + JK_STATUS_ARG_MIME, status_mime_text(mime)); + started=1; + } + if (worker && worker[0]) { + jk_printf(s, "%s%s=%s", started ? "&" : "?", + JK_STATUS_ARG_WORKER, worker); + started=1; + } + if (sub_worker && sub_worker[0] && cmd != JK_STATUS_CMD_LIST) { + jk_printf(s, "%s%s=%s", started ? "&" : "?", + JK_STATUS_ARG_SUB_WORKER, sub_worker); + started=1; + } + if (attribute && attribute[0]) { + jk_printf(s, "%s%s=%s", started ? "&" : "?", + JK_STATUS_ARG_ATTRIBUTE, attribute); + started=1; + } + + sz = jk_map_size(m); + for (i = 0; i < sz; i++) { + const char *k = jk_map_name_at(m, i); + const char *v = jk_map_value_at(m, i); + if (!strcmp(k, JK_STATUS_ARG_CMD) && cmd != JK_STATUS_CMD_UNKNOWN) { + continue; + } + if (!strcmp(k, JK_STATUS_ARG_MIME) && mime != JK_STATUS_MIME_UNKNOWN) { + continue; + } + if (!strcmp(k, JK_STATUS_ARG_FROM)) { + continue; + } + if (!strcmp(k, JK_STATUS_ARG_WORKER) && worker) { + continue; + } + if (!strcmp(k, JK_STATUS_ARG_SUB_WORKER)) { + if (save_sub_worker == JK_TRUE) { + jk_printf(s, "%s%s=%s", started ? "&" : "?", + JK_STATUS_ARG_PREV_SUB_WORKER, v); + started=1; + continue; + } + else if (sub_worker || cmd == JK_STATUS_CMD_LIST) { + continue; + } + else if (restore_sub_worker == JK_TRUE) { + continue; + } + } + if (!strcmp(k, JK_STATUS_ARG_PREV_SUB_WORKER) && restore_sub_worker == JK_TRUE && cmd != JK_STATUS_CMD_LIST) { + jk_printf(s, "%s%s=%s", started ? "&" : "?", + JK_STATUS_ARG_SUB_WORKER, v); + started=1; + continue; + } + if (!strcmp(k, JK_STATUS_ARG_ATTRIBUTE) && attribute) { + continue; + } + if (!strcmp(k, JK_STATUS_ARG_ATTRIBUTE) && cmd != JK_STATUS_CMD_UPDATE && cmd != JK_STATUS_CMD_EDIT) { + continue; + } + if (!strncmp(k, JK_STATUS_ARG_MULT_VALUE_BASE, 3) && cmd != JK_STATUS_CMD_UPDATE) { + continue; + } + if (k[0] == 'v' && cmd != JK_STATUS_CMD_UPDATE) { + continue; + } + if (!strcmp(k, JK_STATUS_ARG_OPTIONS)) { + opt = atoi(v); + continue; + } + jk_printf(s, "%s%s=%s", started ? "&" : "?", k, v); + started=1; + } + if (opt | add_options | rm_options) + jk_printf(s, "%s%s=%u", started ? "&" : "?", + JK_STATUS_ARG_OPTIONS, (opt | add_options) & ~rm_options); + if (text) + jk_putv(s, "\">", text, "</a>", NULL); +} + +static int status_parse_uri(jk_ws_service_t *s, + status_endpoint_t *p, + jk_logger_t *l) +{ + jk_map_t *m; + status_worker_t *w = p->worker; +#ifdef _MT_CODE_PTHREAD + char *lasts; +#endif + char *param; + char *query; + + JK_TRACE_ENTER(l); + + if (!s->query_string) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' query string is empty", + w->name); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + + p->query_string = jk_pool_strdup(s->pool, s->query_string); + if (!p->query_string) { + jk_log(l, JK_LOG_ERROR, + "Status worker '%s' could not copy query string", + w->name); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + /* XXX We simply mask special chars n the query string with '@' to prevent cross site scripting */ + query = p->query_string; + while ((query = strpbrk(query, JK_STATUS_ESC_CHARS))) + query[0] = '@'; + + if (!jk_map_alloc(&(p->req_params))) { + jk_log(l, JK_LOG_ERROR, + "Status worker '%s' could not alloc map for request parameters", + w->name); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + m = p->req_params; + + query = jk_pool_strdup(s->pool, p->query_string); + if (!query) { + jk_log(l, JK_LOG_ERROR, + "Status worker '%s' could not copy query string", + w->name); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + +#ifdef _MT_CODE_PTHREAD + for (param = strtok_r(query, "&", &lasts); + param; param = strtok_r(NULL, "&", &lasts)) { +#else + for (param = strtok(query, "&"); param; param = strtok(NULL, "&")) { +#endif + char *key = jk_pool_strdup(s->pool, param); + char *value; + if (!key) { + jk_log(l, JK_LOG_ERROR, + "Status worker '%s' could not copy string", + w->name); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + value = strchr(key, '='); + if (value) { + *value = '\0'; + value++; + /* XXX Depending on the params values, we might need to trim and decode */ + if (strlen(key)) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' adding request param '%s' with value '%s'", + w->name, key, value); + jk_map_put(m, key, value, NULL); + } + } + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +static void write_html_refresh_response(jk_ws_service_t *s, + status_endpoint_t *p, + const char *err, + jk_logger_t *l) +{ + if (!err) { + jk_puts(s, "\n<meta http-equiv=\"Refresh\" content=\"" + JK_STATUS_WAIT_AFTER_UPDATE ";url="); + status_write_uri(s, p, NULL, JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, 0, 0, NULL, l); + jk_puts(s, "\">"); + jk_putv(s, "<p><b>Result: OK - You will be redirected in " + JK_STATUS_WAIT_AFTER_UPDATE " seconds.</b><p/>", NULL); + } +} + +static int fetch_worker_and_sub_worker(status_endpoint_t *p, + const char *operation, + const char **worker, + const char **sub_worker, + jk_logger_t *l) +{ + status_worker_t *w = p->worker; + + JK_TRACE_ENTER(l); + status_get_string(p, JK_STATUS_ARG_WORKER, NULL, worker, l); + status_get_string(p, JK_STATUS_ARG_SUB_WORKER, NULL, sub_worker, l); + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' %s worker '%s' sub worker '%s'", + w->name, operation, + *worker ? *worker : "(null)", *sub_worker ? *sub_worker : "(null)"); + if (!*worker || !(*worker)[0]) { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' NULL or EMPTY worker param", + w->name); + p->msg = "NULL or EMPTY worker param"; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + if (*sub_worker && !(*sub_worker)[0]) { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' EMPTY sub worker param", + w->name); + p->msg = "EMPTY sub worker param"; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +static int check_valid_lb(jk_ws_service_t *s, + status_endpoint_t *p, + jk_worker_t *jw, + const char *worker, + lb_worker_t **lbp, + int implemented, + jk_logger_t *l) +{ + status_worker_t *w = p->worker; + + JK_TRACE_ENTER(l); + if (jw->type != JK_LB_WORKER_TYPE) { + if (implemented) { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' worker type of worker '%s' has no sub workers", + w->name, worker); + p->msg = "worker type has no sub workers"; + } + else { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' worker type of worker '%s' not implemented", + w->name, worker); + p->msg = "worker type not implemented"; + } + JK_TRACE_EXIT(l); + return JK_FALSE; + } + *lbp = (lb_worker_t *)jw->worker_private; + if (!*lbp) { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' lb structure of worker '%s' is (null)", + w->name, worker); + p->msg = "lb structure is (null)"; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + p->msg = "OK"; + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +static int search_worker(jk_ws_service_t *s, + status_endpoint_t *p, + jk_worker_t **jwp, + const char *worker, + jk_logger_t *l) +{ + status_worker_t *w = p->worker; + + JK_TRACE_ENTER(l); + *jwp = NULL; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' searching worker '%s'", + w->name, worker ? worker : "(null)"); + if (!worker || !worker[0]) { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' NULL or EMPTY worker param", + w->name); + p->msg = "NULL or EMPTY worker param"; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + *jwp = wc_get_worker_for_name(worker, l); + if (!*jwp) { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' could not find worker '%s'", + w->name, worker); + p->msg = "Could not find given worker"; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + p->msg = "OK"; + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +static int search_sub_worker(jk_ws_service_t *s, + status_endpoint_t *p, + jk_worker_t *jw, + const char *worker, + lb_sub_worker_t **wrp, + const char *sub_worker, + unsigned int *idx, + jk_logger_t *l) +{ + lb_worker_t *lb = NULL; + lb_sub_worker_t *wr = NULL; + status_worker_t *w = p->worker; + unsigned int i = 0; + + JK_TRACE_ENTER(l); + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' searching sub worker '%s' of worker '%s'", + w->name, sub_worker ? sub_worker : "(null)", + worker ? worker : "(null)"); + if (!sub_worker || !sub_worker[0]) { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' NULL or EMPTY sub_worker param", + w->name); + p->msg = "NULL or EMPTY sub_worker param"; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + if (check_valid_lb(s, p, jw, worker, &lb, 1, l) == JK_FALSE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + if (idx) + i = *idx; + for (; i < lb->num_of_workers; i++) { + wr = &(lb->lb_workers[i]); + if (idx) { + if (jk_wildchar_match(wr->name, sub_worker, 0) == 0) { + *idx = i + 1; + break; + } + } + else if (strcmp(sub_worker, wr->name) == 0) + break; + } + *wrp = wr; + if (!wr || i == lb->num_of_workers) { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' could not find sub worker '%s' of worker '%s'", + w->name, sub_worker, worker ? worker : "(null)"); + p->msg = "could not find sub worker"; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + p->msg = "OK"; + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +static int count_map(jk_uri_worker_map_t *uw_map, + const char *worker, + jk_logger_t *l) +{ + unsigned int i; + int count=0; + + JK_TRACE_ENTER(l); + if (uw_map) { + for (i = 0; i < uw_map->size[uw_map->index]; i++) { + uri_worker_record_t *uwr = uw_map->maps[uw_map->index][i]; + if (strcmp(uwr->worker_name, worker) && + strcmp(uwr->worker_name, "*")) { + continue; + } + count++; + } + } + JK_TRACE_EXIT(l); + return count; +} + +static int count_maps(jk_ws_service_t *s, + const char *worker, + jk_logger_t *l) +{ + int count=0; + + JK_TRACE_ENTER(l); + if (s->next_vhost) { + void *srv; + for (srv = s->next_vhost(NULL); srv; srv = s->next_vhost(srv)) { + count += count_map(s->vhost_to_uw_map(srv), worker, l); + } + } + else if (s->uw_map) + count = count_map(s->uw_map, worker, l); + JK_TRACE_EXIT(l); + return count; +} + +static void display_map(jk_ws_service_t *s, + status_endpoint_t *p, + jk_uri_worker_map_t *uw_map, + const char *worker, + const char *server_name, + int *count_ptr, + int mime, + jk_logger_t *l) +{ + char buf[64]; + unsigned int i; + int count; + status_worker_t *w = p->worker; + + JK_TRACE_ENTER(l); + + if (uw_map->fname) { + uri_worker_map_update(uw_map, 1, l); + } + for (i = 0; i < uw_map->size[uw_map->index]; i++) { + uri_worker_record_t *uwr = uw_map->maps[uw_map->index][i]; + + if (strcmp(uwr->worker_name, worker) && + strcmp(uwr->worker_name, "*")) { + continue; + } + (*count_ptr)++; + count = *count_ptr; + + if (mime == JK_STATUS_MIME_HTML) { + if (server_name) + jk_printf(s, JK_STATUS_URI_MAP_TABLE_ROW2, + server_name, + uwr->uri, + uri_worker_map_get_match(uwr, buf, l), + uri_worker_map_get_source(uwr, l), + uwr->extensions.reply_timeout, + uwr->extensions.fail_on_status_str ? uwr->extensions.fail_on_status_str : "-", + uwr->extensions.active ? uwr->extensions.active : "-", + uwr->extensions.disabled ? uwr->extensions.disabled : "-", + uwr->extensions.stopped ? uwr->extensions.stopped : "-", + uwr->extensions.use_server_error_pages); + else + jk_printf(s, JK_STATUS_URI_MAP_TABLE_ROW, + uwr->uri, + uri_worker_map_get_match(uwr, buf, l), + uri_worker_map_get_source(uwr, l), + uwr->extensions.reply_timeout, + uwr->extensions.fail_on_status_str ? uwr->extensions.fail_on_status_str : "-", + uwr->extensions.active ? uwr->extensions.active : "-", + uwr->extensions.disabled ? uwr->extensions.disabled : "-", + uwr->extensions.stopped ? uwr->extensions.stopped : "-", + uwr->extensions.use_server_error_pages); + } + else if (mime == JK_STATUS_MIME_XML) { + jk_print_xml_start_elt(s, w, 6, 0, "map"); + jk_print_xml_att_int(s, 8, "id", count); + if (server_name) + jk_print_xml_att_string(s, 8, "server", server_name); + jk_print_xml_att_string(s, 8, "uri", uwr->uri); + jk_print_xml_att_string(s, 8, "type", uri_worker_map_get_match(uwr, buf, l)); + jk_print_xml_att_string(s, 8, "source", uri_worker_map_get_source(uwr, l)); + jk_print_xml_att_int(s, 8, "reply_timeout", uwr->extensions.reply_timeout); + jk_print_xml_att_string(s, 8, "fail_on_status", uwr->extensions.fail_on_status_str); + jk_print_xml_att_string(s, 8, "active", uwr->extensions.active); + jk_print_xml_att_string(s, 8, "disabled", uwr->extensions.disabled); + jk_print_xml_att_string(s, 8, "stopped", uwr->extensions.stopped); + jk_print_xml_att_int(s, 8, "use_server_errors", uwr->extensions.use_server_error_pages); + jk_print_xml_stop_elt(s, 6, 1); + } + else if (mime == JK_STATUS_MIME_TXT) { + jk_puts(s, "Map:"); + jk_printf(s, " id=%d", count); + if (server_name) + jk_printf(s, " server=\"%s\"", server_name); + jk_printf(s, " uri=\"%s\"", uwr->uri); + jk_printf(s, " type=\"%s\"", uri_worker_map_get_match(uwr, buf, l)); + jk_printf(s, " source=\"%s\"", uri_worker_map_get_source(uwr, l)); + jk_printf(s, " reply_timeout=\"%d\"", uwr->extensions.reply_timeout); + jk_printf(s, " fail_on_status=\"%s\"", uwr->extensions.fail_on_status_str ? uwr->extensions.fail_on_status_str : ""); + jk_printf(s, " active=\"%s\"", uwr->extensions.active ? uwr->extensions.active : ""); + jk_printf(s, " disabled=\"%s\"", uwr->extensions.disabled ? uwr->extensions.disabled : ""); + jk_printf(s, " stopped=\"%s\"", uwr->extensions.stopped ? uwr->extensions.stopped : ""); + jk_printf(s, " use_server_errors=\"%d\"", uwr->extensions.use_server_error_pages); + jk_puts(s, "\n"); + } + else if (mime == JK_STATUS_MIME_PROP) { + if (server_name) + jk_print_prop_item_string(s, w, worker, "map", count, "server", server_name); + jk_print_prop_item_string(s, w, worker, "map", count, "uri", uwr->uri); + jk_print_prop_item_string(s, w, worker, "map", count, "type", uri_worker_map_get_match(uwr, buf, l)); + jk_print_prop_item_string(s, w, worker, "map", count, "source", uri_worker_map_get_source(uwr, l)); + jk_print_prop_item_int(s, w, worker, "map", count, "reply_timeout", uwr->extensions.reply_timeout); + jk_print_prop_item_string(s, w, worker, "map", count, "fail_on_status", uwr->extensions.fail_on_status_str); + jk_print_prop_item_string(s, w, worker, "map", count, "active", uwr->extensions.active); + jk_print_prop_item_string(s, w, worker, "map", count, "disabled", uwr->extensions.disabled); + jk_print_prop_item_string(s, w, worker, "map", count, "stopped", uwr->extensions.stopped); + jk_print_prop_item_int(s, w, worker, "map", count, "use_server_errors", uwr->extensions.use_server_error_pages); + } + } + JK_TRACE_EXIT(l); +} + +static void display_maps(jk_ws_service_t *s, + status_endpoint_t *p, + const char *worker, + jk_logger_t *l) +{ + int mime; + unsigned int hide; + int has_server_iterator = 0; + int count=0; + const char *arg; + status_worker_t *w = p->worker; + jk_uri_worker_map_t *uw_map; + char server_name[80]; + void *srv; + + JK_TRACE_ENTER(l); + status_get_string(p, JK_STATUS_ARG_MIME, NULL, &arg, l); + mime = status_mime_int(arg); + hide = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & + JK_STATUS_ARG_OPTION_NO_MAPS; + if (s->next_vhost) + has_server_iterator = 1; + + count = count_maps(s, worker, l); + + if (hide) { + if (count && mime == JK_STATUS_MIME_HTML) { + jk_puts(s, "<p>\n"); + status_write_uri(s, p, "Show URI Mappings", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_MAPS, NULL, l); + jk_puts(s, "</p>\n"); + } + JK_TRACE_EXIT(l); + return; + } + + if (count) { + if (mime == JK_STATUS_MIME_HTML) { + jk_printf(s, "<hr/><h3>URI Mappings for %s (%d maps) [", worker, count); + status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, JK_STATUS_ARG_OPTION_NO_MAPS, 0, NULL, l); + jk_puts(s, "]</h3><table>\n"); + if (has_server_iterator) + jk_printf(s, JK_STATUS_URI_MAP_TABLE_HEAD2, + "Server", "URI", "Match Type", "Source", "Reply Timeout", "Fail on Status", "Active", "Disabled", "Stopped", "Use Server Errors"); + else + jk_printf(s, JK_STATUS_URI_MAP_TABLE_HEAD, + "URI", "Match Type", "Source", "Reply Timeout", "Fail on Status", "Active", "Disabled", "Stopped", "Use Server Errors"); + } + count = 0; + if (has_server_iterator) { + for (srv = s->next_vhost(NULL); srv; srv = s->next_vhost(srv)) { + uw_map = s->vhost_to_uw_map(srv); + if (uw_map) { + s->vhost_to_text(srv, server_name, 80); + display_map(s, p, uw_map, worker, server_name, &count, mime, l); + } + } + } + else { + uw_map = s->uw_map; + if (uw_map) { + display_map(s, p, uw_map, worker, NULL, &count, mime, l); + } + } + if (mime == JK_STATUS_MIME_HTML) { + jk_puts(s, "</table>\n"); + } + } + else { + if (mime == JK_STATUS_MIME_HTML) { + jk_putv(s, "<hr/><h3>Warning: No URI Mappings defined for ", + worker, " !</h3>\n", NULL); + } + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' displayed %d maps for worker '%s'", + w->name, count, worker); + JK_TRACE_EXIT(l); +} + +static const char *dump_ajp_addr(ajp_worker_t *aw, char *buf) +{ + if (aw->port > 0) + return jk_dump_hinfo(&aw->worker_inet_addr, buf); + else { + if (aw->addr_sequence != aw->s->addr_sequence) + return "unresolved"; + else + return "invalid"; + } +} + +static void display_worker_ajp_conf_details(jk_ws_service_t *s, + status_endpoint_t *p, + ajp_worker_t *aw, + int is_member, + int type, + jk_logger_t *l) +{ + char buf[32]; + + JK_TRACE_ENTER(l); + + if (is_member) + jk_printf(s, JK_STATUS_SHOW_MEMBER_CONF_ROW, + aw->name, + status_worker_type(type), + aw->host, + dump_ajp_addr(aw, buf), + aw->cache_timeout, + aw->connect_timeout, + aw->prepost_timeout, + aw->reply_timeout, + aw->retries, + aw->recovery_opts, + aw->max_packet_size); + else + jk_printf(s, JK_STATUS_SHOW_AJP_CONF_ROW, + status_worker_type(type), + aw->host, + dump_ajp_addr(aw, buf), + aw->cache_timeout, + aw->connect_timeout, + aw->prepost_timeout, + aw->reply_timeout, + aw->retries, + aw->recovery_opts, + aw->max_packet_size); + JK_TRACE_EXIT(l); + +} + +static void display_worker_ajp_details(jk_ws_service_t *s, + status_endpoint_t *p, + ajp_worker_t *aw, + lb_sub_worker_t *wr, + lb_worker_t *lb, + int ms_min, + int ms_max, + int map_count, + jk_logger_t *l) +{ + char buf[32]; + char buf_rd[32]; + char buf_rd_sec[32]; + char buf_wr[32]; + char buf_wr_sec[32]; + int mime; + const char *arg; + time_t now = time(NULL); + const char *name = NULL; + const char *sub_name = NULL; + const char *ajp_name = NULL; + status_worker_t *w = p->worker; + int rs_min = 0; + int rs_max = 0; + int delta_reset = (int)difftime(now, aw->s->last_reset); + int delta_error = -1; + char buf_time[JK_STATUS_TIME_BUF_SZ]; + char buf_tz[JK_STATUS_TIME_BUF_SZ]; + time_t error_time = 0; + int rc_time = -1; + + JK_TRACE_ENTER(l); + + status_get_string(p, JK_STATUS_ARG_MIME, NULL, &arg, l); + mime = status_mime_int(arg); + + if (lb) { + name = lb->name; + sub_name = wr->name; + ajp_name = wr->name; + error_time = wr->s->error_time; + if (wr->s->state == JK_LB_STATE_ERROR) { + rs_min = lb->recover_wait_time - (int)difftime(now, wr->s->error_time); + if (rs_min < 0) { + rs_min = 0; + } + rs_max = rs_min + lb->maintain_time; + if (rs_min < ms_min) { + rs_min = ms_min; + } + } + } + else { + name = aw->name; + sub_name = NULL; + ajp_name = aw->name; + error_time = aw->s->error_time; + } + + if (error_time > 0) { + delta_error = (int)difftime(now, error_time); + rc_time = status_strftime(error_time, mime, buf_time, buf_tz, l); + } + + if (mime == JK_STATUS_MIME_HTML) { + + if (lb) + jk_printf(s, JK_STATUS_SHOW_MEMBER_ROW, + sub_name, + jk_lb_get_activation(wr, l), + jk_lb_get_state(wr, l), + wr->distance, + wr->lb_factor, + wr->lb_mult, + wr->s->lb_value, + aw->s->used, + delta_reset > 0 ? (int)(aw->s->used / delta_reset) : -1, + wr->s->errors, + aw->s->client_errors, + aw->s->reply_timeouts, + status_strfsize(aw->s->transferred, buf_wr), + delta_reset > 0 ? status_strfsize(aw->s->transferred / delta_reset, buf_wr_sec) : "-", + status_strfsize(aw->s->readed, buf_rd), + delta_reset > 0 ? status_strfsize(aw->s->readed / delta_reset , buf_rd_sec) : "-", + aw->s->busy, + aw->s->max_busy, + aw->s->connected, + wr->route, + wr->redirect ? (*wr->redirect ? wr->redirect : " ") : " ", + wr->domain ? (*wr->domain ? wr->domain : " ") : " ", + rs_min, + rs_max, + delta_reset, + rc_time > 0 ? buf_time : " "); + else { + jk_printf(s, JK_STATUS_SHOW_AJP_ROW, + jk_ajp_get_state(aw, l), + aw->s->used, + delta_reset > 0 ? (int)(aw->s->used / delta_reset) : -1, + aw->s->errors, + aw->s->client_errors, + aw->s->reply_timeouts, + status_strfsize(aw->s->transferred, buf_wr), + delta_reset > 0 ? status_strfsize(aw->s->transferred / delta_reset, buf_wr_sec) : "-", + status_strfsize(aw->s->readed, buf_rd), + delta_reset > 0 ? status_strfsize(aw->s->readed / delta_reset , buf_rd_sec) : "-", + aw->s->busy, + aw->s->max_busy, + aw->s->connected, + delta_reset, + rc_time > 0 ? buf_time : " "); + } + + } + else if (mime == JK_STATUS_MIME_XML) { + + int off = 2; + if (lb) + off = 6; + if (lb) { + jk_print_xml_start_elt(s, w, off, 0, "member"); + jk_print_xml_att_string(s, off+2, "name", sub_name); + jk_print_xml_att_string(s, off+2, "type", status_worker_type(wr->worker->type)); + } + else { + jk_print_xml_start_elt(s, w, off, 0, "ajp"); + jk_print_xml_att_string(s, off+2, "name", ajp_name); + jk_print_xml_att_string(s, off+2, "type", status_worker_type(aw->worker.type)); + } + jk_print_xml_att_string(s, off+2, "host", aw->host); + jk_print_xml_att_int(s, off+2, "port", aw->port); + jk_print_xml_att_string(s, off+2, "address", dump_ajp_addr(aw, buf)); + jk_print_xml_att_int(s, off+2, "connection_pool_timeout", aw->cache_timeout); + jk_print_xml_att_int(s, off+2, "ping_timeout", aw->ping_timeout); + jk_print_xml_att_int(s, off+2, "connect_timeout", aw->connect_timeout); + jk_print_xml_att_int(s, off+2, "prepost_timeout", aw->prepost_timeout); + jk_print_xml_att_int(s, off+2, "reply_timeout", aw->reply_timeout); + jk_print_xml_att_int(s, off+2, "connection_ping_interval", aw->conn_ping_interval); + jk_print_xml_att_int(s, off+2, "retries", aw->retries); + jk_print_xml_att_uint(s, off+2, "recovery_options", aw->recovery_opts); + jk_print_xml_att_uint(s, off+2, "max_packet_size", aw->max_packet_size); + if (lb) { + jk_print_xml_att_string(s, off+2, "activation", jk_lb_get_activation(wr, l)); + jk_print_xml_att_int(s, off+2, "lbfactor", wr->lb_factor); + jk_print_xml_att_string(s, off+2, "route", wr->route); + jk_print_xml_att_string(s, off+2, "redirect", wr->redirect); + jk_print_xml_att_string(s, off+2, "domain", wr->domain); + jk_print_xml_att_int(s, off+2, "distance", wr->distance); + jk_print_xml_att_string(s, off+2, "state", jk_lb_get_state(wr, l)); + jk_print_xml_att_uint64(s, off+2, "lbmult", wr->lb_mult); + jk_print_xml_att_uint64(s, off+2, "lbvalue", wr->s->lb_value); + jk_print_xml_att_uint64(s, off+2, "elected", aw->s->used); + jk_print_xml_att_uint32(s, off+2, "errors", wr->s->errors); + } + else { + jk_print_xml_att_uint64(s, off+2, "used", aw->s->used); + jk_print_xml_att_uint32(s, off+2, "errors", aw->s->errors); + } + jk_print_xml_att_uint32(s, off+2, "client_errors", aw->s->client_errors); + jk_print_xml_att_uint32(s, off+2, "reply_timeouts", aw->s->reply_timeouts); + jk_print_xml_att_uint64(s, off+2, "transferred", aw->s->transferred); + jk_print_xml_att_uint64(s, off+2, "read", aw->s->readed); + jk_print_xml_att_int(s, off+2, "busy", aw->s->busy); + jk_print_xml_att_int(s, off+2, "max_busy", aw->s->max_busy); + jk_print_xml_att_int(s, off+2, "connected", aw->s->connected); + if (lb) { + jk_print_xml_att_int(s, off+2, "time_to_recover_min", rs_min); + jk_print_xml_att_int(s, off+2, "time_to_recover_max", rs_max); + } + else + jk_print_xml_att_int(s, off+2, "map_count", map_count); + jk_print_xml_att_long(s, off+2, "last_reset_at", (long)aw->s->last_reset); + jk_print_xml_att_int(s, off+2, "last_reset_ago", delta_reset); + if (rc_time > 0 ) { + jk_print_xml_att_string(s, off+2, "error_time_datetime", buf_time); + jk_print_xml_att_string(s, off+2, "error_time_tz", buf_tz); + jk_print_xml_att_int(s, off+2, "error_time_unix_seconds", (int)error_time); + jk_print_xml_att_int(s, off+2, "error_time_ago", delta_error); + } + /* Terminate the tag */ + jk_print_xml_stop_elt(s, off, 1); + + } + else if (mime == JK_STATUS_MIME_TXT) { + + if (lb) { + jk_puts(s, "Member:"); + jk_printf(s, " name=%s", sub_name); + jk_printf(s, " type=%s", status_worker_type(wr->worker->type)); + } + else { + jk_puts(s, "AJP Worker:"); + jk_printf(s, " name=%s", ajp_name); + jk_printf(s, " type=%s", status_worker_type(aw->worker.type)); + } + jk_printf(s, " host=%s", aw->host); + jk_printf(s, " port=%d", aw->port); + jk_printf(s, " address=%s", dump_ajp_addr(aw, buf)); + jk_printf(s, " connection_pool_timeout=%d", aw->cache_timeout); + jk_printf(s, " ping_timeout=%d", aw->ping_timeout); + jk_printf(s, " connect_timeout=%d", aw->connect_timeout); + jk_printf(s, " prepost_timeout=%d", aw->prepost_timeout); + jk_printf(s, " reply_timeout=%d", aw->reply_timeout); + jk_printf(s, " retries=%d", aw->retries); + jk_printf(s, " connection_ping_interval=%d", aw->conn_ping_interval); + jk_printf(s, " recovery_options=%u", aw->recovery_opts); + jk_printf(s, " max_packet_size=%u", aw->max_packet_size); + if (lb) { + jk_printf(s, " activation=%s", jk_lb_get_activation(wr, l)); + jk_printf(s, " lbfactor=%d", wr->lb_factor); + jk_printf(s, " route=\"%s\"", wr->route ? wr->route : ""); + jk_printf(s, " redirect=\"%s\"", wr->redirect ? wr->redirect : ""); + jk_printf(s, " domain=\"%s\"", wr->domain ? wr->domain : ""); + jk_printf(s, " distance=%d", wr->distance); + jk_printf(s, " state=%s", jk_lb_get_state(wr, l)); + jk_printf(s, " lbmult=%" JK_UINT64_T_FMT, wr->lb_mult); + jk_printf(s, " lbvalue=%" JK_UINT64_T_FMT, wr->s->lb_value); + jk_printf(s, " elected=%" JK_UINT64_T_FMT, aw->s->used); + jk_printf(s, " errors=%" JK_UINT32_T_FMT, wr->s->errors); + } + else { + jk_printf(s, " used=%" JK_UINT64_T_FMT, aw->s->used); + jk_printf(s, " errors=%" JK_UINT32_T_FMT, aw->s->errors); + } + jk_printf(s, " client_errors=%" JK_UINT32_T_FMT, aw->s->client_errors); + jk_printf(s, " reply_timeouts=%" JK_UINT32_T_FMT, aw->s->reply_timeouts); + jk_printf(s, " transferred=%" JK_UINT64_T_FMT, aw->s->transferred); + jk_printf(s, " read=%" JK_UINT64_T_FMT, aw->s->readed); + jk_printf(s, " busy=%d", aw->s->busy); + jk_printf(s, " max_busy=%d", aw->s->max_busy); + jk_printf(s, " connected=%d", aw->s->connected); + if (lb) { + jk_printf(s, " time_to_recover_min=%d", rs_min); + jk_printf(s, " time_to_recover_max=%d", rs_max); + } + else + jk_printf(s, " map_count=%d", map_count); + jk_printf(s, " last_reset_at=%ld", (long)aw->s->last_reset); + jk_printf(s, " last_reset_ago=%d", delta_reset); + if (rc_time > 0) { + jk_printf(s, " error_time_datetime=%s", buf_time); + jk_printf(s, " error_time_tz=%s", buf_tz); + jk_printf(s, " error_time_unix_seconds=%d", error_time); + jk_printf(s, " error_time_ago=%d", delta_error); + } + jk_puts(s, "\n"); + + } + else if (mime == JK_STATUS_MIME_PROP) { + + if (lb) { + jk_print_prop_att_string(s, w, name, "balance_workers", sub_name); + jk_print_prop_att_string(s, w, ajp_name, "type", status_worker_type(wr->worker->type)); + } + else { + jk_print_prop_att_string(s, w, name, "list", ajp_name); + jk_print_prop_att_string(s, w, ajp_name, "type", status_worker_type(aw->worker.type)); + } + jk_print_prop_att_string(s, w, ajp_name, "host", aw->host); + jk_print_prop_att_int(s, w, ajp_name, "port", aw->port); + jk_print_prop_att_string(s, w, ajp_name, "address", dump_ajp_addr(aw, buf)); + jk_print_prop_att_int(s, w, ajp_name, "connection_pool_timeout", aw->cache_timeout); + jk_print_prop_att_int(s, w, ajp_name, "ping_timeout", aw->ping_timeout); + jk_print_prop_att_int(s, w, ajp_name, "connect_timeout", aw->connect_timeout); + jk_print_prop_att_int(s, w, ajp_name, "prepost_timeout", aw->prepost_timeout); + jk_print_prop_att_int(s, w, ajp_name, "reply_timeout", aw->reply_timeout); + jk_print_prop_att_int(s, w, ajp_name, "retries", aw->retries); + jk_print_prop_att_int(s, w, ajp_name, "connection_ping_interval", aw->conn_ping_interval); + jk_print_prop_att_uint(s, w, ajp_name, "recovery_options", aw->recovery_opts); + jk_print_prop_att_uint(s, w, ajp_name, "max_packet_size", aw->max_packet_size); + if (lb) { + jk_print_prop_att_string(s, w, ajp_name, "activation", jk_lb_get_activation(wr, l)); + jk_print_prop_att_int(s, w, ajp_name, "lbfactor", wr->lb_factor); + jk_print_prop_att_string(s, w, ajp_name, "route", wr->route); + jk_print_prop_att_string(s, w, ajp_name, "redirect", wr->redirect); + jk_print_prop_att_string(s, w, ajp_name, "domain", wr->domain); + jk_print_prop_att_int(s, w, ajp_name, "distance", wr->distance); + jk_print_prop_att_string(s, w, ajp_name, "state", jk_lb_get_state(wr, l)); + jk_print_prop_att_uint64(s, w, ajp_name, "lbmult", wr->lb_mult); + jk_print_prop_att_uint64(s, w, ajp_name, "lbvalue", wr->s->lb_value); + jk_print_prop_att_uint64(s, w, ajp_name, "elected", aw->s->used); + jk_print_prop_att_uint32(s, w, ajp_name, "errors", wr->s->errors); + } + else { + jk_print_prop_att_uint64(s, w, ajp_name, "used", aw->s->used); + jk_print_prop_att_uint32(s, w, ajp_name, "errors", aw->s->errors); + } + jk_print_prop_att_uint32(s, w, ajp_name, "client_errors", aw->s->client_errors); + jk_print_prop_att_uint32(s, w, ajp_name, "reply_timeouts", aw->s->reply_timeouts); + jk_print_prop_att_uint64(s, w, ajp_name, "transferred", aw->s->transferred); + jk_print_prop_att_uint64(s, w, ajp_name, "read", aw->s->readed); + jk_print_prop_att_int(s, w, ajp_name, "busy", aw->s->busy); + jk_print_prop_att_int(s, w, ajp_name, "max_busy", aw->s->max_busy); + jk_print_prop_att_int(s, w, ajp_name, "connected", aw->s->connected); + if (lb) { + jk_print_prop_att_int(s, w, ajp_name, "time_to_recover_min", rs_min); + jk_print_prop_att_int(s, w, ajp_name, "time_to_recover_max", rs_max); + } + else + jk_print_prop_att_int(s, w, name, "map_count", map_count); + jk_print_prop_att_long(s, w, name, "last_reset_at", (long)aw->s->last_reset); + jk_print_prop_att_int(s, w, name, "last_reset_ago", delta_reset); + if (rc_time > 0) { + jk_print_prop_att_string(s, w, name, "error_time_datetime", buf_time); + jk_print_prop_att_string(s, w, name, "error_time_tz", buf_tz); + jk_print_prop_att_int(s, w, name, "error_time_unix seconds", (int)error_time); + jk_print_prop_att_int(s, w, name, "error_time_ago seconds", delta_error); + } + + } + JK_TRACE_EXIT(l); + +} + +static void display_worker_lb(jk_ws_service_t *s, + status_endpoint_t *p, + lb_worker_t *lb, + lb_sub_worker_t *swr, + jk_logger_t *l) +{ + int cmd; + int mime; + int read_only = 0; + int single = 0; + unsigned int hide_members; + unsigned int hide_lb_conf; + unsigned int hide_lb_summary; + unsigned int hide_ajp_conf; + const char *arg; + time_t now = time(NULL); + unsigned int good = 0; + unsigned int degraded = 0; + unsigned int bad = 0; + int map_count; + int ms_min; + int ms_max; + unsigned int j; + int pstart = JK_FALSE; + const char *name = lb->name; + status_worker_t *w = p->worker; + + JK_TRACE_ENTER(l); + status_get_string(p, JK_STATUS_ARG_CMD, NULL, &arg, l); + cmd = status_cmd_int(arg); + status_get_string(p, JK_STATUS_ARG_MIME, NULL, &arg, l); + mime = status_mime_int(arg); + hide_members = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & + JK_STATUS_ARG_OPTION_NO_MEMBERS; + hide_lb_conf = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & + JK_STATUS_ARG_OPTION_NO_LB_CONF; + hide_lb_summary = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & + JK_STATUS_ARG_OPTION_NO_LB_SUMMARY; + hide_ajp_conf = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & + JK_STATUS_ARG_OPTION_NO_AJP_CONF; + if (w->read_only) { + read_only = 1; + } + else { + read_only = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & + JK_STATUS_ARG_OPTION_READ_ONLY; + } + if (cmd == JK_STATUS_CMD_SHOW) { + single = 1; + } + + if (lb->sequence != lb->s->h.sequence) + jk_lb_pull(lb, JK_FALSE, l); + + for (j = 0; j < lb->num_of_workers; j++) { + lb_sub_worker_t *wr = &(lb->lb_workers[j]); + int rate; + rate = status_rate(wr, w, l); + if (rate > 0 ) + good++; + else if (rate < 0 ) + bad++; + else + degraded++; + } + + map_count = count_maps(s, name, l); + ms_min = lb->maintain_time - (int)difftime(now, lb->s->last_maintain_time); + ms_max = ms_min + lb->maintain_time; + ms_min -= JK_LB_MAINTAIN_TOLERANCE; + if (ms_min < 0) { + ms_min = 0; + } + if (ms_max < 0) { + ms_max = 0; + } + + if (mime == JK_STATUS_MIME_HTML) { + + jk_puts(s, "<hr/><h3>["); + if (single) { + jk_puts(s, "S"); + } + else { + status_write_uri(s, p, "S", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, + name, "", 0, 0, "", l); + } + if (!read_only) { + jk_puts(s, "|"); + status_write_uri(s, p, "E", JK_STATUS_CMD_EDIT, JK_STATUS_MIME_UNKNOWN, + name, "", 0, 0, "", l); + jk_puts(s, "|"); + status_write_uri(s, p, "R", JK_STATUS_CMD_RESET, JK_STATUS_MIME_UNKNOWN, + name, "", 0, 0, "", l); + } + jk_puts(s, "] "); + jk_putv(s, "Worker Status for ", name, "</h3>\n", NULL); + if (hide_lb_conf) { + pstart = JK_TRUE; + jk_puts(s, "<p>\n"); + if (single) { + status_write_uri(s, p, "Show LB Configuration", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_LB_CONF, "", l); + } + else { + status_write_uri(s, p, "Show LB Configuration", JK_STATUS_CMD_LIST, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_LB_CONF, "", l); + } + } + if (hide_lb_summary) { + if (pstart == JK_FALSE) + jk_puts(s, "<p>\n"); + else + jk_puts(s, " | "); + pstart = JK_TRUE; + if (single) { + status_write_uri(s, p, "Show LB Summary", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_LB_SUMMARY, "", l); + } + else { + status_write_uri(s, p, "Show LB Summary", JK_STATUS_CMD_LIST, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_LB_SUMMARY, "", l); + } + } + if (!hide_members && hide_ajp_conf) { + if (pstart == JK_FALSE) + jk_puts(s, "<p>\n"); + else + jk_puts(s, " | "); + pstart = JK_TRUE; + if (single) { + status_write_uri(s, p, "Show AJP Configuration", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_AJP_CONF, "", l); + } + else { + status_write_uri(s, p, "Show AJP Configuration", JK_STATUS_CMD_LIST, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_AJP_CONF, "", l); + } + } + if (hide_members) { + if (pstart == JK_FALSE) + jk_puts(s, "<p>\n"); + else + jk_puts(s, " | "); + pstart = JK_TRUE; + if (single) { + status_write_uri(s, p, "Show Balancer Members", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_MEMBERS, "", l); + } + else { + status_write_uri(s, p, "Show Balancer Members", JK_STATUS_CMD_LIST, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_MEMBERS, "", l); + } + } + if (pstart == JK_TRUE) + jk_puts(s, "</p>\n"); + + if (!hide_lb_conf) { + jk_puts(s, "<table>" JK_STATUS_SHOW_LB_HEAD); + jk_puts(s, "["); + status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, JK_STATUS_ARG_OPTION_NO_LB_CONF, 0, NULL, l); + jk_puts(s, "]</th></tr>"); + jk_printf(s, JK_STATUS_SHOW_LB_ROW, + status_worker_type(JK_LB_WORKER_TYPE), + jk_get_bool(lb->sticky_session), + jk_get_bool(lb->sticky_session_force), + lb->retries, + jk_lb_get_method(lb, l), + jk_lb_get_lock(lb, l), + lb->recover_wait_time, + lb->error_escalation_time, + lb->max_reply_timeouts); + jk_puts(s, "</table>\n<br/>\n"); + } + + if (!hide_lb_summary) { + jk_puts(s, "<table><tr>" + "<th>Good</th><th>Degraded</th><th>Bad/Stopped</th><th>Busy</th><th>Max Busy</th><th>Next Maintenance</th><th>Last Reset</th><th>["); + status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, JK_STATUS_ARG_OPTION_NO_LB_SUMMARY, 0, NULL, l); + jk_puts(s, "]</th></tr>\n<tr>"); + jk_printf(s, "<td>%d</td>", good); + jk_printf(s, "<td>%d</td>", degraded); + jk_printf(s, "<td>%d</td>", bad); + jk_printf(s, "<td>%d</td>", lb->s->busy); + jk_printf(s, "<td>%d</td>", lb->s->max_busy); + jk_printf(s, "<td>%d/%d</td>", ms_min, ms_max); + jk_printf(s, "<td>%d</td>", (int)difftime(now, lb->s->last_reset)); + jk_puts(s, "<td></td></tr>\n</table>\n\n"); + } + } + else if (mime == JK_STATUS_MIME_XML) { + + jk_print_xml_start_elt(s, w, 2, 0, "balancer"); + jk_print_xml_att_string(s, 4, "name", name); + jk_print_xml_att_string(s, 4, "type", status_worker_type(JK_LB_WORKER_TYPE)); + jk_print_xml_att_string(s, 4, "sticky_session", jk_get_bool(lb->sticky_session)); + jk_print_xml_att_string(s, 4, "sticky_session_force", jk_get_bool(lb->sticky_session_force)); + jk_print_xml_att_int(s, 4, "retries", lb->retries); + jk_print_xml_att_int(s, 4, "recover_time", lb->recover_wait_time); + jk_print_xml_att_int(s, 4, "error_escalation_time", lb->error_escalation_time); + jk_print_xml_att_int(s, 4, "max_reply_timeouts", lb->max_reply_timeouts); + jk_print_xml_att_string(s, 4, "method", jk_lb_get_method(lb, l)); + jk_print_xml_att_string(s, 4, "lock", jk_lb_get_lock(lb, l)); + jk_print_xml_att_int(s, 4, "member_count", lb->num_of_workers); + jk_print_xml_att_int(s, 4, "good", good); + jk_print_xml_att_int(s, 4, "degraded", degraded); + jk_print_xml_att_int(s, 4, "bad", bad); + jk_print_xml_att_int(s, 4, "busy", lb->s->busy); + jk_print_xml_att_int(s, 4, "max_busy", lb->s->max_busy); + jk_print_xml_att_int(s, 4, "map_count", map_count); + jk_print_xml_att_int(s, 4, "time_to_maintenance_min", ms_min); + jk_print_xml_att_int(s, 4, "time_to_maintenance_max", ms_max); + jk_print_xml_att_long(s, 4, "last_reset_at", (long)lb->s->last_reset); + jk_print_xml_att_int(s, 4, "last_reset_ago", (int)difftime(now, lb->s->last_reset)); + jk_print_xml_stop_elt(s, 2, 0); + + } + else if (mime == JK_STATUS_MIME_TXT) { + + jk_puts(s, "Balancer Worker:"); + jk_printf(s, " name=%s", name); + jk_printf(s, " type=%s", status_worker_type(JK_LB_WORKER_TYPE)); + jk_printf(s, " sticky_session=%s", jk_get_bool(lb->sticky_session)); + jk_printf(s, " sticky_session_force=%s", jk_get_bool(lb->sticky_session_force)); + jk_printf(s, " retries=%d", lb->retries); + jk_printf(s, " recover_time=%d", lb->recover_wait_time); + jk_printf(s, " error_escalation_time=%d", lb->error_escalation_time); + jk_printf(s, " max_reply_timeouts=%d", lb->max_reply_timeouts); + jk_printf(s, " method=%s", jk_lb_get_method(lb, l)); + jk_printf(s, " lock=%s", jk_lb_get_lock(lb, l)); + jk_printf(s, " member_count=%d", lb->num_of_workers); + jk_printf(s, " good=%d", good); + jk_printf(s, " degraded=%d", degraded); + jk_printf(s, " bad=%d", bad); + jk_printf(s, " busy=%d", lb->s->busy); + jk_printf(s, " max_busy=%d", lb->s->max_busy); + jk_printf(s, " map_count=%d", map_count); + jk_printf(s, " time_to_maintenance_min=%d", ms_min); + jk_printf(s, " time_to_maintenance_max=%d", ms_max); + jk_printf(s, " last_reset_at=%ld", (long)lb->s->last_reset); + jk_printf(s, " last_reset_ago=%d", (int)difftime(now, lb->s->last_reset)); + jk_puts(s, "\n"); + + } + else if (mime == JK_STATUS_MIME_PROP) { + + jk_print_prop_att_string(s, w, NULL, "list", name); + jk_print_prop_att_string(s, w, name, "type", status_worker_type(JK_LB_WORKER_TYPE)); + jk_print_prop_att_string(s, w, name, "sticky_session", jk_get_bool(lb->sticky_session)); + jk_print_prop_att_string(s, w, name, "sticky_session_force", jk_get_bool(lb->sticky_session_force)); + jk_print_prop_att_int(s, w, name, "retries", lb->retries); + jk_print_prop_att_int(s, w, name, "recover_time", lb->recover_wait_time); + jk_print_prop_att_int(s, w, name, "error_escalation_time", lb->error_escalation_time); + jk_print_prop_att_int(s, w, name, "max_reply_timeouts", lb->max_reply_timeouts); + jk_print_prop_att_string(s, w, name, "method", jk_lb_get_method(lb, l)); + jk_print_prop_att_string(s, w, name, "lock", jk_lb_get_lock(lb, l)); + jk_print_prop_att_int(s, w, name, "member_count", lb->num_of_workers); + jk_print_prop_att_int(s, w, name, "good", good); + jk_print_prop_att_int(s, w, name, "degraded", degraded); + jk_print_prop_att_int(s, w, name, "bad", bad); + jk_print_prop_att_int(s, w, name, "busy", lb->s->busy); + jk_print_prop_att_int(s, w, name, "max_busy", lb->s->max_busy); + jk_print_prop_att_int(s, w, name, "map_count", map_count); + jk_print_prop_att_int(s, w, name, "time_to_maintenance_min", ms_min); + jk_print_prop_att_int(s, w, name, "time_to_maintenance_max", ms_max); + jk_print_prop_att_long(s, w, name, "last_reset_at", (long)lb->s->last_reset); + jk_print_prop_att_int(s, w, name, "last_reset_ago", (int)difftime(now, lb->s->last_reset)); + + } + + if (!hide_members) { + + if (mime == JK_STATUS_MIME_HTML) { + + jk_puts(s, "<h4>Balancer Members ["); + if (swr) { + status_write_uri(s, p, "Show All Members", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, + name, "", 0, 0, "", l); + jk_puts(s, "] ["); + } + if (single) { + status_write_uri(s, p, "Hide", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, JK_STATUS_ARG_OPTION_NO_MEMBERS, 0, "", l); + } + else { + status_write_uri(s, p, "Hide", JK_STATUS_CMD_LIST, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, JK_STATUS_ARG_OPTION_NO_MEMBERS, 0, "", l); + } + jk_puts(s, "]</h4>\n"); + if (!hide_ajp_conf) { + jk_puts(s, "<table>" JK_STATUS_SHOW_MEMBER_CONF_HEAD); + jk_puts(s, "["); + status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, JK_STATUS_ARG_OPTION_NO_AJP_CONF, 0, NULL, l); + jk_puts(s, "]</td></tr>"); + if (swr) { + jk_worker_t *jw = (jk_worker_t *)swr->worker; + ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private; + display_worker_ajp_conf_details(s, p, aw, 1, jw->type, l); + } + else + for (j = 0; j < lb->num_of_workers; j++) { + lb_sub_worker_t *wr = &(lb->lb_workers[j]); + jk_worker_t *jw = (jk_worker_t *)wr->worker; + ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private; + display_worker_ajp_conf_details(s, p, aw, 1, jw->type, l); + } + jk_puts(s, "</table>\n<br/>\n"); + } + jk_puts(s, "<table>" JK_STATUS_SHOW_MEMBER_HEAD); + + } + + if (swr) { + const char *sub_name = swr->name; + ajp_worker_t *aw = (ajp_worker_t *)swr->worker->worker_private; + + if (mime == JK_STATUS_MIME_HTML) { + jk_puts(s, "<tr>\n<td>["); + jk_puts(s, "S"); + if (!read_only) { + jk_puts(s, "|"); + status_write_uri(s, p, "E", JK_STATUS_CMD_EDIT, JK_STATUS_MIME_UNKNOWN, + name, sub_name, 0, 0, "", l); + jk_puts(s, "|"); + status_write_uri(s, p, "R", JK_STATUS_CMD_RESET, JK_STATUS_MIME_UNKNOWN, + name, sub_name, 0, 0, "", l); + if (swr->s->state == JK_LB_STATE_ERROR) { + jk_puts(s, "|"); + status_write_uri(s, p, "T", JK_STATUS_CMD_RECOVER, JK_STATUS_MIME_UNKNOWN, + name, sub_name, 0, 0, "", l); + } + } + jk_puts(s, "]"); + jk_puts(s, " </td>"); + } + display_worker_ajp_details(s, p, aw, swr, lb, ms_min, ms_max, 0, l); + } else + for (j = 0; j < lb->num_of_workers; j++) { + lb_sub_worker_t *wr = &(lb->lb_workers[j]); + const char *sub_name = wr->name; + ajp_worker_t *aw = (ajp_worker_t *)wr->worker->worker_private; + + if (mime == JK_STATUS_MIME_HTML) { + jk_puts(s, "<tr>\n<td>["); + status_write_uri(s, p, "S", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, + name, sub_name, 0, 0, "", l); + if (!read_only) { + jk_puts(s, "|"); + status_write_uri(s, p, "E", JK_STATUS_CMD_EDIT, JK_STATUS_MIME_UNKNOWN, + name, sub_name, 0, 0, "", l); + jk_puts(s, "|"); + status_write_uri(s, p, "R", JK_STATUS_CMD_RESET, JK_STATUS_MIME_UNKNOWN, + name, sub_name, 0, 0, "", l); + if (wr->s->state == JK_LB_STATE_ERROR) { + jk_puts(s, "|"); + status_write_uri(s, p, "T", JK_STATUS_CMD_RECOVER, JK_STATUS_MIME_UNKNOWN, + name, sub_name, 0, 0, "", l); + } + } + jk_puts(s, "]"); + jk_puts(s, " </td>"); + } + display_worker_ajp_details(s, p, aw, wr, lb, ms_min, ms_max, 0, l); + } + + if (mime == JK_STATUS_MIME_HTML) { + + jk_puts(s, "</table><br/>\n"); + if (!read_only) { + const char *arg; + status_get_string(p, JK_STATUS_ARG_CMD, NULL, &arg, l); + status_start_form(s, p, "get", JK_STATUS_CMD_EDIT, NULL, l); + jk_printf(s, JK_STATUS_FORM_HIDDEN_STRING, JK_STATUS_ARG_WORKER, name); + if (arg) + jk_printf(s, JK_STATUS_FORM_HIDDEN_STRING, JK_STATUS_ARG_FROM, arg); + jk_puts(s, "<table><tr><td><b>E</b>dit this attribute for all members:</td><td>"); + jk_putv(s, "<select name=\"", JK_STATUS_ARG_ATTRIBUTE, + "\" size=\"1\">\n", NULL); + jk_putv(s, "<option value=\"", JK_STATUS_ARG_LBM_ACTIVATION, "\">", JK_STATUS_ARG_LBM_TEXT_ACTIVATION, "</option>\n", NULL); + jk_putv(s, "<option value=\"", JK_STATUS_ARG_LBM_FACTOR, "\">", JK_STATUS_ARG_LBM_TEXT_FACTOR, "</option>\n", NULL); + jk_putv(s, "<option value=\"", JK_STATUS_ARG_LBM_ROUTE, "\">", JK_STATUS_ARG_LBM_TEXT_ROUTE, "</option>\n", NULL); + jk_putv(s, "<option value=\"", JK_STATUS_ARG_LBM_REDIRECT, "\">", JK_STATUS_ARG_LBM_TEXT_REDIRECT, "</option>\n", NULL); + jk_putv(s, "<option value=\"", JK_STATUS_ARG_LBM_DOMAIN, "\">", JK_STATUS_ARG_LBM_TEXT_DOMAIN, "</option>\n", NULL); + jk_putv(s, "<option value=\"", JK_STATUS_ARG_LBM_DISTANCE, "\">", JK_STATUS_ARG_LBM_TEXT_DISTANCE, "</option>\n", NULL); + jk_putv(s, "<option value=\"", JK_STATUS_ARG_AJP_CACHE_TO, "\">", JK_STATUS_ARG_AJP_TEXT_CACHE_TO, "</option>\n", NULL); + jk_putv(s, "<option value=\"", JK_STATUS_ARG_AJP_PING_TO, "\">", JK_STATUS_ARG_AJP_TEXT_PING_TO, "</option>\n", NULL); + jk_putv(s, "<option value=\"", JK_STATUS_ARG_AJP_CONNECT_TO, "\">", JK_STATUS_ARG_AJP_TEXT_CONNECT_TO, "</option>\n", NULL); + jk_putv(s, "<option value=\"", JK_STATUS_ARG_AJP_PREPOST_TO, "\">", JK_STATUS_ARG_AJP_TEXT_PREPOST_TO, "</option>\n", NULL); + jk_putv(s, "<option value=\"", JK_STATUS_ARG_AJP_REPLY_TO, "\">", JK_STATUS_ARG_AJP_TEXT_REPLY_TO, "</option>\n", NULL); + jk_putv(s, "<option value=\"", JK_STATUS_ARG_AJP_RETRIES, "\">", JK_STATUS_ARG_AJP_TEXT_RETRIES, "</option>\n", NULL); + jk_putv(s, "<option value=\"", JK_STATUS_ARG_AJP_RETRY_INT, "\">", JK_STATUS_ARG_AJP_TEXT_RETRY_INT, "</option>\n", NULL); + jk_putv(s, "<option value=\"", JK_STATUS_ARG_AJP_CPING_INT, "\">", JK_STATUS_ARG_AJP_TEXT_CPING_INT, "</option>\n", NULL); + jk_putv(s, "<option value=\"", JK_STATUS_ARG_AJP_REC_OPTS, "\">", JK_STATUS_ARG_AJP_TEXT_REC_OPTS, "</option>\n", NULL); + jk_putv(s, "<option value=\"", JK_STATUS_ARG_AJP_MAX_PK_SZ, "\">", JK_STATUS_ARG_AJP_TEXT_MAX_PK_SZ, "</option>\n", NULL); + jk_puts(s, "</select></td><td><input type=\"submit\" value=\"Go\"/></tr></table></form>\n"); + } + + } + + } + + if (name) + display_maps(s, p, name, l); + + if (mime == JK_STATUS_MIME_XML) { + jk_print_xml_close_elt(s, w, 2, "balancer"); + } + + JK_TRACE_EXIT(l); +} + +static void display_worker_ajp(jk_ws_service_t *s, + status_endpoint_t *p, + ajp_worker_t *aw, + int type, + jk_logger_t *l) +{ + int cmd; + int mime; + int read_only = 0; + int single = 0; + unsigned int hide_ajp_conf; + const char *arg; + int map_count; + const char *name = aw->name; + status_worker_t *w = p->worker; + + JK_TRACE_ENTER(l); + status_get_string(p, JK_STATUS_ARG_CMD, NULL, &arg, l); + cmd = status_cmd_int(arg); + status_get_string(p, JK_STATUS_ARG_MIME, NULL, &arg, l); + mime = status_mime_int(arg); + hide_ajp_conf = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & + JK_STATUS_ARG_OPTION_NO_AJP_CONF; + if (w->read_only) { + read_only = 1; + } + else { + read_only = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & + JK_STATUS_ARG_OPTION_READ_ONLY; + } + if (cmd == JK_STATUS_CMD_SHOW) { + single = 1; + } + + if (aw->sequence != aw->s->h.sequence) + jk_ajp_pull(aw, JK_FALSE, l); + + map_count = count_maps(s, name, l); + + if (mime == JK_STATUS_MIME_HTML) { + + jk_puts(s, "<hr/><h3>["); + if (single) + jk_puts(s, "S"); + else + status_write_uri(s, p, "S", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, + name, "", 0, 0, "", l); + if (!read_only) { + jk_puts(s, "|"); + status_write_uri(s, p, "E", JK_STATUS_CMD_EDIT, JK_STATUS_MIME_UNKNOWN, + name, "", 0, 0, "", l); + jk_puts(s, "|"); + status_write_uri(s, p, "R", JK_STATUS_CMD_RESET, JK_STATUS_MIME_UNKNOWN, + name, "", 0, 0, "", l); + } + jk_puts(s, "] "); + jk_putv(s, "Worker Status for ", name, "</h3>\n", NULL); + if (!hide_ajp_conf) { + jk_puts(s, "<table>" JK_STATUS_SHOW_AJP_CONF_HEAD); + jk_puts(s, "["); + status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, JK_STATUS_ARG_OPTION_NO_AJP_CONF, 0, NULL, l); + jk_puts(s, "]</td></tr>"); + display_worker_ajp_conf_details(s, p, aw, 0, type, l); + jk_puts(s, "</table>\n<br/>\n"); + } + else { + jk_puts(s, "<p>\n"); + if (single) { + status_write_uri(s, p, "Show AJP Configuration", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_AJP_CONF, "", l); + } + else { + status_write_uri(s, p, "Show AJP Configuration", JK_STATUS_CMD_LIST, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_AJP_CONF, "", l); + } + jk_puts(s, "</p>\n"); + } + jk_puts(s, "<table>" JK_STATUS_SHOW_AJP_HEAD); + } + display_worker_ajp_details(s, p, aw, NULL, NULL, 0, 0, map_count, l); + + if (mime == JK_STATUS_MIME_HTML) { + jk_puts(s, "</table>\n"); + } + if (name) + display_maps(s, p, name, l); + + JK_TRACE_EXIT(l); +} + +static void display_worker(jk_ws_service_t *s, + status_endpoint_t *p, + jk_worker_t *jw, + lb_sub_worker_t *swr, + jk_logger_t *l) +{ + status_worker_t *w = p->worker; + + JK_TRACE_ENTER(l); + if (jw->type == JK_LB_WORKER_TYPE) { + lb_worker_t *lb = (lb_worker_t *)jw->worker_private; + if (lb) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' %s lb worker '%s'", + w->name, "displaying", lb->name); + display_worker_lb(s, p, lb, swr, l); + } + else { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' lb worker is (null)", + w->name); + } + } + else if (jw->type == JK_AJP13_WORKER_TYPE || + jw->type == JK_AJP14_WORKER_TYPE) { + ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private; + if (aw) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' %s ajp worker '%s'", + w->name, "displaying", aw->name); + display_worker_ajp(s, p, aw, jw->type, l); + } + else { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' aw worker is (null)", + w->name); + } + } + else { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' worker type not implemented", + w->name); + JK_TRACE_EXIT(l); + return; + } +} + +static void form_worker(jk_ws_service_t *s, + status_endpoint_t *p, + jk_worker_t *jw, + jk_logger_t *l) +{ + const char *name = NULL; + lb_worker_t *lb = NULL; + status_worker_t *w = p->worker; + + JK_TRACE_ENTER(l); + if (jw->type == JK_LB_WORKER_TYPE) { + lb = (lb_worker_t *)jw->worker_private; + name = lb->name; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' producing edit form for lb worker '%s'", + w->name, name); + } + else { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' worker type not implemented", + w->name); + JK_TRACE_EXIT(l); + return; + } + + if (!lb) { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' lb structure is (null)", + w->name); + JK_TRACE_EXIT(l); + return; + } + + jk_putv(s, "<hr/><h3>Edit load balancer settings for ", + name, "</h3>\n", NULL); + + status_start_form(s, p, "get", JK_STATUS_CMD_UPDATE, NULL, l); + + jk_putv(s, "<table>\n<tr><td>", JK_STATUS_ARG_LB_TEXT_RETRIES, + ":</td><td><input name=\"", + JK_STATUS_ARG_LB_RETRIES, "\" type=\"text\" ", NULL); + jk_printf(s, "value=\"%d\"/></td></tr>\n", lb->retries); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_LB_TEXT_RETRY_INT, + ":</td><td><input name=\"", + JK_STATUS_ARG_LB_RETRY_INT, "\" type=\"text\" ", NULL); + jk_printf(s, "value=\"%d\"/></td></tr>\n", lb->retry_interval); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_LB_TEXT_RECOVER_TIME, + ":</td><td><input name=\"", + JK_STATUS_ARG_LB_RECOVER_TIME, "\" type=\"text\" ", NULL); + jk_printf(s, "value=\"%d\"/></td></tr>\n", lb->recover_wait_time); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_LB_TEXT_ERROR_ESCALATION_TIME, + ":</td><td><input name=\"", + JK_STATUS_ARG_LB_ERROR_ESCALATION_TIME, "\" type=\"text\" ", NULL); + jk_printf(s, "value=\"%d\"/></td></tr>\n", lb->error_escalation_time); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_LB_TEXT_MAX_REPLY_TIMEOUTS, + ":</td><td><input name=\"", + JK_STATUS_ARG_LB_MAX_REPLY_TIMEOUTS, "\" type=\"text\" ", NULL); + jk_printf(s, "value=\"%d\"/></td></tr>\n", lb->max_reply_timeouts); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_LB_TEXT_STICKY, + ":</td><td><input name=\"", + JK_STATUS_ARG_LB_STICKY, "\" type=\"checkbox\"", NULL); + if (lb->sticky_session) + jk_puts(s, " checked=\"checked\""); + jk_puts(s, "/></td></tr>\n"); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_LB_TEXT_STICKY_FORCE, + ":</td><td><input name=\"", + JK_STATUS_ARG_LB_STICKY_FORCE, "\" type=\"checkbox\"", NULL); + if (lb->sticky_session_force) + jk_puts(s, " checked=\"checked\""); + jk_puts(s, "/></td></tr>\n"); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_LB_TEXT_METHOD, + ":</td><td></td></tr>\n", NULL); + jk_putv(s, "<tr><td> Requests</td><td><input name=\"", + JK_STATUS_ARG_LB_METHOD, "\" type=\"radio\"", NULL); + jk_printf(s, " value=\"%d\"", JK_LB_METHOD_REQUESTS); + if (lb->lbmethod == JK_LB_METHOD_REQUESTS) + jk_puts(s, " checked=\"checked\""); + jk_puts(s, "/></td></tr>\n"); + jk_putv(s, "<tr><td> Traffic</td><td><input name=\"", + JK_STATUS_ARG_LB_METHOD, "\" type=\"radio\"", NULL); + jk_printf(s, " value=\"%d\"", JK_LB_METHOD_TRAFFIC); + if (lb->lbmethod == JK_LB_METHOD_TRAFFIC) + jk_puts(s, " checked=\"checked\""); + jk_puts(s, "/></td></tr>\n"); + jk_putv(s, "<tr><td> Busyness</td><td><input name=\"", + JK_STATUS_ARG_LB_METHOD, "\" type=\"radio\"", NULL); + jk_printf(s, " value=\"%d\"", JK_LB_METHOD_BUSYNESS); + if (lb->lbmethod == JK_LB_METHOD_BUSYNESS) + jk_puts(s, " checked=\"checked\""); + jk_puts(s, "/></td></tr>\n"); + jk_putv(s, "<tr><td> Sessions</td><td><input name=\"", + JK_STATUS_ARG_LB_METHOD, "\" type=\"radio\"", NULL); + jk_printf(s, " value=\"%d\"", JK_LB_METHOD_SESSIONS); + if (lb->lbmethod == JK_LB_METHOD_SESSIONS) + jk_puts(s, " checked=\"checked\""); + jk_puts(s, "/></td></tr>\n"); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_LB_TEXT_LOCK, + ":</td><td></td></tr>\n", NULL); + jk_putv(s, "<tr><td> Optimistic</td><td><input name=\"", + JK_STATUS_ARG_LB_LOCK, "\" type=\"radio\"", NULL); + jk_printf(s, " value=\"%d\"", JK_LB_LOCK_OPTIMISTIC); + if (lb->lblock == JK_LB_LOCK_OPTIMISTIC) + jk_puts(s, " checked=\"checked\""); + jk_puts(s, "/></td></tr>\n"); + jk_putv(s, "<tr><td> Pessimistic</td><td><input name=\"", + JK_STATUS_ARG_LB_LOCK, "\" type=\"radio\"", NULL); + jk_printf(s, " value=\"%d\"", JK_LB_LOCK_PESSIMISTIC); + if (lb->lblock == JK_LB_LOCK_PESSIMISTIC) + jk_puts(s, " checked=\"checked\""); + jk_puts(s, "/></td></tr>\n"); + jk_puts(s, "</table>\n"); + jk_puts(s, "<br/><input type=\"submit\" value=\"Update Balancer\"/></form>\n"); + + JK_TRACE_EXIT(l); +} + +static void form_member(jk_ws_service_t *s, + status_endpoint_t *p, + lb_sub_worker_t *wr, + ajp_worker_t *aw, + const char *lb_name, + jk_logger_t *l) +{ + status_worker_t *w = p->worker; + + JK_TRACE_ENTER(l); + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' producing edit form for sub worker '%s' of lb worker '%s'", + w->name, wr? wr->name : aw->name, lb_name); + + jk_putv(s, "<hr/><h3>Edit worker settings for ", + wr? wr->name : aw->name, "</h3>\n", NULL); + status_start_form(s, p, "get", JK_STATUS_CMD_UPDATE, NULL, l); + + if (wr) { + jk_puts(s, "<table><tbody valign=\"baseline\"><tr><th>Balancing related settings</th>\n"); + jk_puts(s, "<th> </th><th>AJP settings</th>\n"); + jk_puts(s, "</tr>\n"); + jk_puts(s, "<tr><td><table>\n"); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_LBM_TEXT_ACTIVATION, + ":</td><td></td></tr>\n", NULL); + jk_putv(s, "<tr><td> Active</td><td><input name=\"", + JK_STATUS_ARG_LBM_ACTIVATION, "\" type=\"radio\"", NULL); + jk_printf(s, " value=\"%d\"", JK_LB_ACTIVATION_ACTIVE); + if (wr->activation == JK_LB_ACTIVATION_ACTIVE) + jk_puts(s, " checked=\"checked\""); + jk_puts(s, "/></td></tr>\n"); + jk_putv(s, "<tr><td> Disabled</td><td><input name=\"", + JK_STATUS_ARG_LBM_ACTIVATION, "\" type=\"radio\"", NULL); + jk_printf(s, " value=\"%d\"", JK_LB_ACTIVATION_DISABLED); + if (wr->activation == JK_LB_ACTIVATION_DISABLED) + jk_puts(s, " checked=\"checked\""); + jk_puts(s, "/></td></tr>\n"); + jk_putv(s, "<tr><td> Stopped</td><td><input name=\"", + JK_STATUS_ARG_LBM_ACTIVATION, "\" type=\"radio\"", NULL); + jk_printf(s, " value=\"%d\"", JK_LB_ACTIVATION_STOPPED); + if (wr->activation == JK_LB_ACTIVATION_STOPPED) + jk_puts(s, " checked=\"checked\""); + jk_puts(s, "/></td></tr>\n"); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_LBM_TEXT_FACTOR, + ":</td><td><input name=\"", + JK_STATUS_ARG_LBM_FACTOR, "\" type=\"text\" ", NULL); + jk_printf(s, "value=\"%d\"/></td></tr>\n", wr->lb_factor); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_LBM_TEXT_ROUTE, + ":</td><td><input name=\"", + JK_STATUS_ARG_LBM_ROUTE, "\" type=\"text\" ", NULL); + jk_printf(s, "value=\"%s\"/></td></tr>\n", wr->route); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_LBM_TEXT_REDIRECT, + ":</td><td><input name=\"", + JK_STATUS_ARG_LBM_REDIRECT, "\" type=\"text\" ", NULL); + jk_putv(s, "value=\"", wr->redirect, NULL); + jk_puts(s, "\"/></td></tr>\n"); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_LBM_TEXT_DOMAIN, + ":</td><td><input name=\"", + JK_STATUS_ARG_LBM_DOMAIN, "\" type=\"text\" ", NULL); + jk_putv(s, "value=\"", wr->domain, NULL); + jk_puts(s, "\"/></td></tr>\n"); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_LBM_TEXT_DISTANCE, + ":</td><td><input name=\"", + JK_STATUS_ARG_LBM_DISTANCE, "\" type=\"text\" ", NULL); + jk_printf(s, "value=\"%d\"/></td></tr>\n", wr->distance); + jk_puts(s, "</table>\n"); + jk_puts(s, "</td><td></td><td>\n"); + } + + jk_puts(s, "<table>\n"); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_HOST_STR, + ":</td><td><input name=\"", + JK_STATUS_ARG_AJP_HOST_STR, "\" type=\"text\" ", NULL); + jk_printf(s, "value=\"%s\"/></td></tr>\n", aw->host); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_PORT, + ":</td><td><input name=\"", + JK_STATUS_ARG_AJP_PORT, "\" type=\"text\" ", NULL); + jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->port); + + jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_CACHE_TO, + ":</td><td><input name=\"", + JK_STATUS_ARG_AJP_CACHE_TO, "\" type=\"text\" ", NULL); + jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->cache_timeout); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_PING_TO, + ":</td><td><input name=\"", + JK_STATUS_ARG_AJP_PING_TO, "\" type=\"text\" ", NULL); + jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->ping_timeout); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_CONNECT_TO, + ":</td><td><input name=\"", + JK_STATUS_ARG_AJP_CONNECT_TO, "\" type=\"text\" ", NULL); + jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->connect_timeout); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_PREPOST_TO, + ":</td><td><input name=\"", + JK_STATUS_ARG_AJP_PREPOST_TO, "\" type=\"text\" ", NULL); + jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->prepost_timeout); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_REPLY_TO, + ":</td><td><input name=\"", + JK_STATUS_ARG_AJP_REPLY_TO, "\" type=\"text\" ", NULL); + jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->reply_timeout); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_RETRIES, + ":</td><td><input name=\"", + JK_STATUS_ARG_AJP_RETRIES, "\" type=\"text\" ", NULL); + jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->retries); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_RETRY_INT, + ":</td><td><input name=\"", + JK_STATUS_ARG_AJP_RETRY_INT, "\" type=\"text\" ", NULL); + jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->retry_interval); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_CPING_INT, + ":</td><td><input name=\"", + JK_STATUS_ARG_AJP_CPING_INT, "\" type=\"text\" ", NULL); + jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->conn_ping_interval); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_REC_OPTS, + ":</td><td><input name=\"", + JK_STATUS_ARG_AJP_REC_OPTS, "\" type=\"text\" ", NULL); + jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->recovery_opts); + jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_MAX_PK_SZ, + ":</td><td><input name=\"", + JK_STATUS_ARG_AJP_MAX_PK_SZ, "\" type=\"text\" ", NULL); + jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->max_packet_size); + jk_puts(s, "</table>\n"); + if (wr) + jk_puts(s, "</td></tr></table>\n"); + jk_puts(s, "<br/><input type=\"submit\" value=\"Update Worker\"/>\n</form>\n"); + JK_TRACE_EXIT(l); +} + +static void form_all_members(jk_ws_service_t *s, + status_endpoint_t *p, + jk_worker_t *jw, + const char *attribute, + jk_logger_t *l) +{ + const char *name = NULL; + lb_worker_t *lb = NULL; + status_worker_t *w = p->worker; + const char *aname; + unsigned int i; + + JK_TRACE_ENTER(l); + if (!attribute) { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' missing request parameter '%s'", + w->name, JK_STATUS_ARG_ATTRIBUTE); + JK_TRACE_EXIT(l); + return; + } + else { + if (!strcmp(attribute, JK_STATUS_ARG_LBM_ACTIVATION)) + aname=JK_STATUS_ARG_LBM_TEXT_ACTIVATION; + else if (!strcmp(attribute, JK_STATUS_ARG_LBM_FACTOR)) + aname=JK_STATUS_ARG_LBM_TEXT_FACTOR; + else if (!strcmp(attribute, JK_STATUS_ARG_LBM_ROUTE)) + aname=JK_STATUS_ARG_LBM_TEXT_ROUTE; + else if (!strcmp(attribute, JK_STATUS_ARG_LBM_REDIRECT)) + aname=JK_STATUS_ARG_LBM_TEXT_REDIRECT; + else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DOMAIN)) + aname=JK_STATUS_ARG_LBM_TEXT_DOMAIN; + else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DISTANCE)) + aname=JK_STATUS_ARG_LBM_TEXT_DISTANCE; + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CACHE_TO)) + aname=JK_STATUS_ARG_AJP_TEXT_CACHE_TO; + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PING_TO)) + aname=JK_STATUS_ARG_AJP_TEXT_PING_TO; + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CONNECT_TO)) + aname=JK_STATUS_ARG_AJP_TEXT_CONNECT_TO; + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PREPOST_TO)) + aname=JK_STATUS_ARG_AJP_TEXT_PREPOST_TO; + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REPLY_TO)) + aname=JK_STATUS_ARG_AJP_TEXT_REPLY_TO; + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRIES)) + aname=JK_STATUS_ARG_AJP_TEXT_RETRIES; + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRY_INT)) + aname=JK_STATUS_ARG_AJP_TEXT_RETRY_INT; + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CPING_INT)) + aname=JK_STATUS_ARG_AJP_TEXT_CPING_INT; + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REC_OPTS)) + aname=JK_STATUS_ARG_AJP_TEXT_REC_OPTS; + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_MAX_PK_SZ)) + aname=JK_STATUS_ARG_AJP_TEXT_MAX_PK_SZ; + else { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' unknown attribute '%s'", + w->name, attribute); + JK_TRACE_EXIT(l); + return; + } + } + if (jw->type == JK_LB_WORKER_TYPE) { + lb = (lb_worker_t *)jw->worker_private; + name = lb->name; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' producing edit form for attribute '%s' [%s] of all members of lb worker '%s'", + w->name, attribute, aname, name); + } + else { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' worker type not implemented", + w->name); + JK_TRACE_EXIT(l); + return; + } + + if (lb) { + jk_putv(s, "<hr/><h3>Edit attribute '", aname, + "' for all members of load balancer ", + name, "</h3>\n", NULL); + + status_start_form(s, p, "get", JK_STATUS_CMD_UPDATE, NULL, l); + + jk_putv(s, "<table><tr>" + "<th>Balanced Worker</th><th>", aname, "</th>" + "</tr>", NULL); + + for (i = 0; i < lb->num_of_workers; i++) { + lb_sub_worker_t *wr = &(lb->lb_workers[i]); + jk_worker_t *jw = wr->worker; + ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private;; + + jk_putv(s, "<tr><td>", wr->name, "</td><td>\n", NULL); + + if (!strcmp(attribute, JK_STATUS_ARG_LBM_ACTIVATION)) { + + jk_printf(s, "Active: <input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"radio\"", i); + jk_printf(s, " value=\"%d\"", JK_LB_ACTIVATION_ACTIVE); + if (wr->activation == JK_LB_ACTIVATION_ACTIVE) + jk_puts(s, " checked=\"checked\""); + jk_puts(s, "/> | \n"); + jk_printf(s, "Disabled: <input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"radio\"", i); + jk_printf(s, " value=\"%d\"", JK_LB_ACTIVATION_DISABLED); + if (wr->activation == JK_LB_ACTIVATION_DISABLED) + jk_puts(s, " checked=\"checked\""); + jk_puts(s, "/> | \n"); + jk_printf(s, "Stopped: <input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"radio\"", i); + jk_printf(s, " value=\"%d\"", JK_LB_ACTIVATION_STOPPED); + if (wr->activation == JK_LB_ACTIVATION_STOPPED) + jk_puts(s, " checked=\"checked\""); + jk_puts(s, "/>\n"); + + } + else if (!strcmp(attribute, JK_STATUS_ARG_LBM_FACTOR)) { + jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i); + jk_printf(s, "value=\"%d\"/>\n", wr->lb_factor); + } + else if (!strcmp(attribute, JK_STATUS_ARG_LBM_ROUTE)) { + jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i); + jk_putv(s, "value=\"", wr->route, "\"/>\n", NULL); + } + else if (!strcmp(attribute, JK_STATUS_ARG_LBM_REDIRECT)) { + jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i); + jk_putv(s, "value=\"", wr->redirect, "\"/>\n", NULL); + } + else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DOMAIN)) { + jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i); + jk_putv(s, "value=\"", wr->domain, "\"/>\n", NULL); + } + else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DISTANCE)) { + jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i); + jk_printf(s, "value=\"%d\"/>\n", wr->distance); + } + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CACHE_TO)) { + jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i); + jk_printf(s, "value=\"%d\"/>\n", aw->cache_timeout); + } + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PING_TO)) { + jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i); + jk_printf(s, "value=\"%d\"/>\n", aw->ping_timeout); + } + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CONNECT_TO)) { + jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i); + jk_printf(s, "value=\"%d\"/>\n", aw->connect_timeout); + } + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PREPOST_TO)) { + jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i); + jk_printf(s, "value=\"%d\"/>\n", aw->prepost_timeout); + } + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REPLY_TO)) { + jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i); + jk_printf(s, "value=\"%d\"/>\n", aw->reply_timeout); + } + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRIES)) { + jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i); + jk_printf(s, "value=\"%d\"/>\n", aw->retries); + } + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRY_INT)) { + jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i); + jk_printf(s, "value=\"%d\"/>\n", aw->retry_interval); + } + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CPING_INT)) { + jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i); + jk_printf(s, "value=\"%d\"/>\n", aw->conn_ping_interval); + } + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REC_OPTS)) { + jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i); + jk_printf(s, "value=\"%d\"/>\n", aw->recovery_opts); + } + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_MAX_PK_SZ)) { + jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i); + jk_printf(s, "value=\"%d\"/>\n", aw->max_packet_size); + } + + jk_puts(s, "</td></tr>"); + } + + jk_puts(s, "</table>\n"); + jk_puts(s, "<br/><input type=\"submit\" value=\"Update Balancer\"/></form>\n"); + } + JK_TRACE_EXIT(l); +} + +static void commit_worker(jk_ws_service_t *s, + status_endpoint_t *p, + jk_worker_t *jw, + jk_logger_t *l) +{ + const char *name = NULL; + lb_worker_t *lb = NULL; + status_worker_t *w = p->worker; + const char *arg; + int sync_needed = JK_FALSE; + int i; + + JK_TRACE_ENTER(l); + if (jw->type == JK_LB_WORKER_TYPE) { + lb = (lb_worker_t *)jw->worker_private; + name = lb->name; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' committing changes for lb worker '%s'", + w->name, name); + } + else { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' worker type not implemented", + w->name); + JK_TRACE_EXIT(l); + return; + } + + if (!lb) { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' lb structure is (null)", + w->name); + JK_TRACE_EXIT(l); + return; + } + + i = status_get_int(p, JK_STATUS_ARG_LB_RETRIES, + lb->retries, l); + if (i != lb->retries && i > 0) { + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting 'retries' for lb worker '%s' to '%i'", + w->name, name, i); + lb->retries = i; + sync_needed = JK_TRUE; + } + i = status_get_int(p, JK_STATUS_ARG_LB_RETRY_INT, + lb->retry_interval, l); + if (i != lb->retry_interval && i > 0) { + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting 'retry_interval' for lb worker '%s' to '%i'", + w->name, name, i); + lb->retry_interval = i; + sync_needed = JK_TRUE; + } + i = status_get_int(p, JK_STATUS_ARG_LB_RECOVER_TIME, + lb->recover_wait_time, l); + if (i != lb->recover_wait_time && i > 0) { + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting 'recover_time' for lb worker '%s' to '%i'", + w->name, name, i); + lb->recover_wait_time = i; + sync_needed = JK_TRUE; + } + i = status_get_int(p, JK_STATUS_ARG_LB_ERROR_ESCALATION_TIME, + lb->error_escalation_time, l); + if (i != lb->error_escalation_time && i > 0) { + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting 'error_escalation_time' for lb worker '%s' to '%i'", + w->name, name, i); + lb->error_escalation_time = i; + sync_needed = JK_TRUE; + } + i = status_get_int(p, JK_STATUS_ARG_LB_MAX_REPLY_TIMEOUTS, + lb->max_reply_timeouts, l); + if (i != lb->max_reply_timeouts && i >= 0) { + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting 'max_reply_timeouts' for lb worker '%s' to '%i'", + w->name, name, i); + lb->max_reply_timeouts = i; + sync_needed = JK_TRUE; + } + i = status_get_bool(p, JK_STATUS_ARG_LB_STICKY, lb->sticky_session, l); + if (i != lb->sticky_session) { + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting 'sticky_session' for lb worker '%s' to '%i'", + w->name, name, i); + lb->sticky_session = i; + sync_needed = JK_TRUE; + } + i = status_get_bool(p, JK_STATUS_ARG_LB_STICKY_FORCE, lb->sticky_session_force, l); + if (i != lb->sticky_session_force) { + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting 'sticky_session_force' for lb worker '%s' to '%i'", + w->name, name, i); + lb->sticky_session_force = i; + sync_needed = JK_TRUE; + } + if (status_get_string(p, JK_STATUS_ARG_LB_METHOD, NULL, &arg, l) == JK_TRUE) { + i = jk_lb_get_method_code(arg); + if (i != lb->lbmethod && i >= 0 && i <= JK_LB_METHOD_MAX) { + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting 'method' for lb worker '%s' to '%s'", + w->name, name, jk_lb_get_method(lb, l)); + lb->lbmethod = i; + sync_needed = JK_TRUE; + } + } + if (status_get_string(p, JK_STATUS_ARG_LB_LOCK, NULL, &arg, l) == JK_TRUE) { + i = jk_lb_get_lock_code(arg); + if (i != lb->lblock && i >= 0 && i <= JK_LB_LOCK_MAX) { + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting 'lock' for lb worker '%s' to '%s'", + w->name, name, jk_lb_get_lock(lb, l)); + lb->lblock = i; + sync_needed = JK_TRUE; + } + } + if (sync_needed == JK_TRUE) { + lb->sequence++; + jk_lb_push(lb, JK_TRUE, l); + } +} + +static int set_int_if_changed(status_endpoint_t *p, + const char *name, + const char *att, + const char *arg, + int min, + int max, + int *param, + const char *lb_name, + jk_logger_t *l) +{ + int i; + status_worker_t *w = p->worker; + i = status_get_int(p, arg, *param, l); + if (i != *param && i >= min && i <= max) { + if (lb_name) + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting '%s' for sub worker '%s' of lb worker '%s' to '%i'", + w->name, att, name, lb_name, i); + else + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting '%s' for ajp worker '%s' to '%i'", + w->name, att, name, i); + *param = i; + return JK_TRUE; + } + return JK_FALSE; +} + +static int set_uint_if_changed(status_endpoint_t *p, + const char *name, + const char *att, + const char *arg, + unsigned int min, + unsigned int max, + unsigned int *param, + const char *lb_name, + jk_logger_t *l) +{ + unsigned i; + status_worker_t *w = p->worker; + i = (unsigned)status_get_int(p, arg, *param, l); + if (i != *param && i >= min && i <= max) { + if (lb_name) + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting '%s' for sub worker '%s' of lb worker '%s' to '%u'", + w->name, att, name, lb_name, i); + else + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting '%s' for ajp worker '%s' to '%u'", + w->name, att, name, i); + *param = i; + return JK_TRUE; + } + return JK_FALSE; +} + +static int commit_member(jk_ws_service_t *s, + status_endpoint_t *p, + lb_worker_t *lb, + lb_sub_worker_t *wr, + ajp_worker_t *aw, + int *side_effect, + jk_logger_t *l) +{ + const char *arg; + const char *lb_name = NULL; + status_worker_t *w = p->worker; + int rc = JK_TRUE; + int rv; + int i; + int old; + int resolve = JK_FALSE; + char host[JK_SHM_STR_SIZ+1]; + int port = 0; + + JK_TRACE_ENTER(l); + if (lb) { + lb_name = lb->name; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' committing changes for sub worker '%s' of lb worker '%s'", + w->name, wr->name, lb_name); + } + else { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' committing changes for ajp worker '%s'", + w->name, aw->name); + } + + if (lb) { + if (status_get_string(p, JK_STATUS_ARG_LBM_ACTIVATION, NULL, &arg, l) == JK_TRUE) { + i = jk_lb_get_activation_code(arg); + if (i != wr->activation && i >= 0 && i <= JK_LB_ACTIVATION_MAX) { + wr->activation = i; + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting 'activation' for sub worker '%s' of lb worker '%s' to '%s'", + w->name, wr->name, lb_name, jk_lb_get_activation(wr, l)); + *side_effect |= JK_STATUS_NEEDS_RESET_LB_VALUES | JK_STATUS_NEEDS_PUSH; + } + } + if (set_int_if_changed(p, wr->name, "lbfactor", JK_STATUS_ARG_LBM_FACTOR, + 1, INT_MAX, &wr->lb_factor, lb_name, l)) + /* Recalculate the load multiplicators wrt. lb_factor */ + *side_effect |= JK_STATUS_NEEDS_UPDATE_MULT | JK_STATUS_NEEDS_PUSH; + if ((rv = status_get_string(p, JK_STATUS_ARG_LBM_ROUTE, + NULL, &arg, l)) == JK_TRUE) { + if (strncmp(wr->route, arg, JK_SHM_STR_SIZ)) { + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting 'route' for sub worker '%s' of lb worker '%s' to '%s'", + w->name, wr->name, lb_name, arg); + strncpy(wr->route, arg, JK_SHM_STR_SIZ); + *side_effect |= JK_STATUS_NEEDS_PUSH; + if (!wr->domain[0]) { + char * id_domain = strchr(wr->route, '.'); + if (id_domain) { + *id_domain = '\0'; + strcpy(wr->domain, wr->route); + *id_domain = '.'; + } + } + } + } + if ((rv = status_get_string(p, JK_STATUS_ARG_LBM_REDIRECT, + NULL, &arg, l)) == JK_TRUE) { + if (strncmp(wr->redirect, arg, JK_SHM_STR_SIZ)) { + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting 'redirect' for sub worker '%s' of lb worker '%s' to '%s'", + w->name, wr->name, lb_name, arg); + strncpy(wr->redirect, arg, JK_SHM_STR_SIZ); + *side_effect |= JK_STATUS_NEEDS_PUSH; + } + } + if ((rv = status_get_string(p, JK_STATUS_ARG_LBM_DOMAIN, + NULL, &arg, l)) == JK_TRUE) { + if (strncmp(wr->domain, arg, JK_SHM_STR_SIZ)) { + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting 'domain' for sub worker '%s' of lb worker '%s' to '%s'", + w->name, wr->name, lb_name, arg); + strncpy(wr->domain, arg, JK_SHM_STR_SIZ); + *side_effect |= JK_STATUS_NEEDS_PUSH; + } + } + if (set_int_if_changed(p, wr->name, "distance", JK_STATUS_ARG_LBM_DISTANCE, + 0, INT_MAX, &wr->distance, lb_name, l)) + *side_effect |= JK_STATUS_NEEDS_PUSH; + } + old = aw->cache_timeout; + if (set_int_if_changed(p, aw->name, "connection_pool_timeout", JK_STATUS_ARG_AJP_CACHE_TO, + 0, INT_MAX, &aw->cache_timeout, lb_name, l)) { + *side_effect |= JK_STATUS_NEEDS_PUSH; + if (old == 0) { + unsigned int i; + for (i = 0; i < aw->ep_cache_sz; i++) { + ajp_endpoint_t *ae = (ajp_endpoint_t *) aw->ep_cache[i]; + if (ae) + ae->last_access = time(NULL); + } + } + } + port = aw->port; + if (set_int_if_changed(p, aw->name, "port", JK_STATUS_ARG_AJP_PORT, + 0, INT_MAX, &port, lb_name, l)) { + strncpy(host, aw->host, JK_SHM_STR_SIZ); + resolve = JK_TRUE; + } + if ((rv = status_get_string(p, JK_STATUS_ARG_AJP_HOST_STR, + NULL, &arg, l)) == JK_TRUE) { + if (strncmp(aw->host, arg, JK_SHM_STR_SIZ)) { + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting 'host' for sub worker '%s' to '%s'", + w->name, aw->name, arg); + strncpy(host, arg, JK_SHM_STR_SIZ); + resolve = JK_TRUE; + } + } + if (resolve == JK_TRUE) { + struct sockaddr_in inet_addr; + if (!jk_resolve(host, port, &inet_addr, + aw->worker.we->pool, l)) { + const char *msg = "Update failed (at least partially): could not resolve address '%s:%d' for sub worker '%s'."; + size_t size = strlen(msg) + strlen(host) + strlen(aw->name) + 10 + 1; + p->msg = jk_pool_alloc(s->pool, size); + snprintf(p->msg, size, msg, host, port, aw->name); + jk_log(l, JK_LOG_ERROR, + "Status worker '%s' failed resolving address '%s:%d' for sub worker '%s'.", + w->name, host, port, aw->name); + rc = JK_FALSE; + } + else { + /* This is not atomic and not thread safe */ + aw->port = port; + strncpy(aw->host, host, JK_SHM_STR_SIZ); + memcpy(&(aw->worker_inet_addr), &inet_addr, sizeof(inet_addr)); + *side_effect |= JK_STATUS_NEEDS_PUSH | JK_STATUS_NEEDS_ADDR_PUSH; + } + } + if (set_int_if_changed(p, aw->name, "ping_timeout", JK_STATUS_ARG_AJP_PING_TO, + 0, INT_MAX, &aw->ping_timeout, lb_name, l)) + *side_effect |= JK_STATUS_NEEDS_PUSH; + if (set_int_if_changed(p, aw->name, "connect_timeout", JK_STATUS_ARG_AJP_CONNECT_TO, + 0, INT_MAX, &aw->connect_timeout, lb_name, l)) + *side_effect |= JK_STATUS_NEEDS_PUSH; + if (set_int_if_changed(p, aw->name, "prepost_timeout", JK_STATUS_ARG_AJP_PREPOST_TO, + 0, INT_MAX, &aw->prepost_timeout, lb_name, l)) + *side_effect |= JK_STATUS_NEEDS_PUSH; + if (set_int_if_changed(p, aw->name, "reply_timeout", JK_STATUS_ARG_AJP_REPLY_TO, + 0, INT_MAX, &aw->reply_timeout, lb_name, l)) + *side_effect |= JK_STATUS_NEEDS_PUSH; + if (set_int_if_changed(p, aw->name, "retries", JK_STATUS_ARG_AJP_RETRIES, + 1, INT_MAX, &aw->retries, lb_name, l)) + *side_effect |= JK_STATUS_NEEDS_PUSH; + if (set_int_if_changed(p, aw->name, "retry_interval", JK_STATUS_ARG_AJP_RETRY_INT, + 1, INT_MAX, &aw->retry_interval, lb_name, l)) + *side_effect |= JK_STATUS_NEEDS_PUSH; + if (set_int_if_changed(p, aw->name, "connection_ping_interval", JK_STATUS_ARG_AJP_CPING_INT, + 1, INT_MAX, &aw->conn_ping_interval, lb_name, l)) + *side_effect |= JK_STATUS_NEEDS_PUSH; + if (set_uint_if_changed(p, aw->name, "recovery_options", JK_STATUS_ARG_AJP_REC_OPTS, + 0, INT_MAX, &aw->recovery_opts, lb_name, l)) + *side_effect |= JK_STATUS_NEEDS_PUSH; + if (set_uint_if_changed(p, aw->name, "max_packet_size", JK_STATUS_ARG_AJP_MAX_PK_SZ, + 8*1024, 64*1024, &aw->max_packet_size, lb_name, l)) { + *side_effect |= JK_STATUS_NEEDS_PUSH; + if (aw->max_packet_size > lb->max_packet_size) { + lb->max_packet_size = aw->max_packet_size; + } + } + return rc; +} + +static void commit_all_members(jk_ws_service_t *s, + status_endpoint_t *p, + jk_worker_t *jw, + const char *attribute, + jk_logger_t *l) +{ + const char *arg; + char vname[32]; + const char *name = NULL; + lb_worker_t *lb = NULL; + status_worker_t *w = p->worker; + const char *aname; + int i; + int rc = 0; + unsigned int j; + + JK_TRACE_ENTER(l); + if (!attribute) { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' missing request parameter '%s'", + w->name, JK_STATUS_ARG_ATTRIBUTE); + JK_TRACE_EXIT(l); + return; + } + else { + if (!strcmp(attribute, JK_STATUS_ARG_LBM_ACTIVATION)) + aname=JK_STATUS_ARG_LBM_TEXT_ACTIVATION; + else if (!strcmp(attribute, JK_STATUS_ARG_LBM_FACTOR)) + aname=JK_STATUS_ARG_LBM_TEXT_FACTOR; + else if (!strcmp(attribute, JK_STATUS_ARG_LBM_ROUTE)) + aname=JK_STATUS_ARG_LBM_TEXT_ROUTE; + else if (!strcmp(attribute, JK_STATUS_ARG_LBM_REDIRECT)) + aname=JK_STATUS_ARG_LBM_TEXT_REDIRECT; + else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DOMAIN)) + aname=JK_STATUS_ARG_LBM_TEXT_DOMAIN; + else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DISTANCE)) + aname=JK_STATUS_ARG_LBM_TEXT_DISTANCE; + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CACHE_TO)) + aname=JK_STATUS_ARG_AJP_TEXT_CACHE_TO; + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PING_TO)) + aname=JK_STATUS_ARG_AJP_TEXT_PING_TO; + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CONNECT_TO)) + aname=JK_STATUS_ARG_AJP_TEXT_CONNECT_TO; + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PREPOST_TO)) + aname=JK_STATUS_ARG_AJP_TEXT_PREPOST_TO; + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REPLY_TO)) + aname=JK_STATUS_ARG_AJP_TEXT_REPLY_TO; + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRIES)) + aname=JK_STATUS_ARG_AJP_TEXT_RETRIES; + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRY_INT)) + aname=JK_STATUS_ARG_AJP_TEXT_RETRY_INT; + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CPING_INT)) + aname=JK_STATUS_ARG_AJP_TEXT_CPING_INT; + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REC_OPTS)) + aname=JK_STATUS_ARG_AJP_TEXT_REC_OPTS; + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_MAX_PK_SZ)) + aname=JK_STATUS_ARG_AJP_TEXT_MAX_PK_SZ; + else { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' unknown attribute '%s'", + w->name, attribute); + JK_TRACE_EXIT(l); + return; + } + } + if (jw->type == JK_LB_WORKER_TYPE) { + lb = (lb_worker_t *)jw->worker_private; + name = lb->name; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' committing changes for attribute '%s' [%s] of all members of lb worker '%s'", + w->name, attribute, aname, name); + } + else { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' worker type not implemented", + w->name); + JK_TRACE_EXIT(l); + return; + } + + if (lb) { + for (j = 0; j < lb->num_of_workers; j++) { + int sync_needed = JK_FALSE; + lb_sub_worker_t *wr = &(lb->lb_workers[j]); + jk_worker_t *jw = wr->worker; + ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private;; + snprintf(vname, 32-1, "" JK_STATUS_ARG_MULT_VALUE_BASE "%d", j); + + if (!strcmp(attribute, JK_STATUS_ARG_LBM_FACTOR)) { + if (set_int_if_changed(p, wr->name, "lbfactor", vname, + 1, INT_MAX, &wr->lb_factor, name, l)) { + rc = 2; + sync_needed = JK_TRUE; + } + } + else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DISTANCE)) { + if (set_int_if_changed(p, wr->name, "distance", vname, + 0, INT_MAX, &wr->distance, name, l)) + sync_needed = JK_TRUE; + } + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CACHE_TO)) { + int old = aw->cache_timeout; + if (set_int_if_changed(p, aw->name, "connection_pool_timeout", vname, + 0, INT_MAX, &aw->cache_timeout, name, l)) { + sync_needed = JK_TRUE; + if (old == 0) { + unsigned int i; + for (i = 0; i < aw->ep_cache_sz; i++) { + ajp_endpoint_t *ae = (ajp_endpoint_t *) aw->ep_cache[i]; + if (ae) + ae->last_access = time(NULL); + } + } + } + } + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PING_TO)) { + if (set_int_if_changed(p, aw->name, "ping_timeout", vname, + 0, INT_MAX, &aw->ping_timeout, name, l)) + sync_needed = JK_TRUE; + } + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CONNECT_TO)) { + if (set_int_if_changed(p, aw->name, "connect_timeout", vname, + 0, INT_MAX, &aw->connect_timeout, name, l)) + sync_needed = JK_TRUE; + } + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PREPOST_TO)) { + if (set_int_if_changed(p, aw->name, "prepost_timeout", vname, + 0, INT_MAX, &aw->prepost_timeout, name, l)) + sync_needed = JK_TRUE; + } + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REPLY_TO)) { + if (set_int_if_changed(p, aw->name, "reply_timeout", vname, + 0, INT_MAX, &aw->reply_timeout, name, l)) + sync_needed = JK_TRUE; + } + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRIES)) { + if (set_int_if_changed(p, aw->name, "retries", vname, + 1, INT_MAX, &aw->retries, name, l)) + sync_needed = JK_TRUE; + } + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRY_INT)) { + if (set_int_if_changed(p, aw->name, "retry_interval", vname, + 1, INT_MAX, &aw->retry_interval, name, l)) + sync_needed = JK_TRUE; + } + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CPING_INT)) { + if (set_int_if_changed(p, aw->name, "connection_ping_interval", vname, + 1, INT_MAX, &aw->conn_ping_interval, name, l)) + sync_needed = JK_TRUE; + } + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REC_OPTS)) { + if (set_uint_if_changed(p, aw->name, "recovery_options", vname, + 0, INT_MAX, &aw->recovery_opts, name, l)) + sync_needed = JK_TRUE; + } + else if (!strcmp(attribute, JK_STATUS_ARG_AJP_MAX_PK_SZ)) { + if (set_uint_if_changed(p, aw->name, "max_packet_size", vname, + 8*1024, 64*1024, &aw->max_packet_size, name, l)) { + sync_needed = JK_TRUE; + if (aw->max_packet_size > lb->max_packet_size) { + lb->max_packet_size = aw->max_packet_size; + } + } + } + else { + int rv = status_get_string(p, vname, NULL, &arg, l); + if (!strcmp(attribute, JK_STATUS_ARG_LBM_ACTIVATION)) { + if (rv == JK_TRUE) { + i = jk_lb_get_activation_code(arg); + if (i != wr->activation && i >= 0 && i <= JK_LB_ACTIVATION_MAX) { + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting 'activation' for sub worker '%s' of lb worker '%s' to '%s'", + w->name, wr->name, name, jk_lb_get_activation(wr, l)); + wr->activation = i; + rc = 1; + sync_needed = JK_TRUE; + } + } + } + else if (!strcmp(attribute, JK_STATUS_ARG_LBM_ROUTE)) { + if (rv == JK_TRUE) { + if (strncmp(wr->route, arg, JK_SHM_STR_SIZ)) { + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting 'route' for sub worker '%s' of lb worker '%s' to '%s'", + w->name, wr->name, name, arg); + strncpy(wr->route, arg, JK_SHM_STR_SIZ); + sync_needed = JK_TRUE; + if (!wr->domain[0]) { + char * id_domain = strchr(wr->route, '.'); + if (id_domain) { + *id_domain = '\0'; + strcpy(wr->domain, wr->route); + *id_domain = '.'; + } + } + } + } + } + else if (!strcmp(attribute, JK_STATUS_ARG_LBM_REDIRECT)) { + if (rv == JK_TRUE) { + if (strncmp(wr->redirect, arg, JK_SHM_STR_SIZ)) { + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting 'redirect' for sub worker '%s' of lb worker '%s' to '%s'", + w->name, wr->name, name, arg); + strncpy(wr->redirect, arg, JK_SHM_STR_SIZ); + sync_needed = JK_TRUE; + } + } + } + else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DOMAIN)) { + if (rv == JK_TRUE) { + if (strncmp(wr->domain, arg, JK_SHM_STR_SIZ)) { + jk_log(l, JK_LOG_INFO, + "Status worker '%s' setting 'domain' for sub worker '%s' of lb worker '%s' to '%s'", + w->name, wr->name, name, arg); + strncpy(wr->domain, arg, JK_SHM_STR_SIZ); + sync_needed = JK_TRUE; + } + } + } + } + if (sync_needed == JK_TRUE) { + wr->sequence++; + if (!rc) + rc = 3; + } + } + if (rc == 1) + reset_lb_values(lb, l); + else if (rc == 2) + /* Recalculate the load multiplicators wrt. lb_factor */ + update_mult(lb, l); + if (rc) { + lb->sequence++; + jk_lb_push(lb, JK_TRUE, l); + } + } + JK_TRACE_EXIT(l); +} + +static void display_legend(jk_ws_service_t *s, + status_endpoint_t *p, + jk_logger_t *l) +{ + + int mime; + const char *arg; + unsigned int hide_legend; + + JK_TRACE_ENTER(l); + status_get_string(p, JK_STATUS_ARG_MIME, NULL, &arg, l); + mime = status_mime_int(arg); + if (mime != JK_STATUS_MIME_HTML) { + JK_TRACE_EXIT(l); + return; + } + hide_legend = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & + JK_STATUS_ARG_OPTION_NO_LEGEND; + if (hide_legend) { + jk_puts(s, "<p>\n"); + status_write_uri(s, p, "Show Legend", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_LEGEND, NULL, l); + jk_puts(s, "</p>\n"); + } + else { + jk_puts(s, "<h2>Legend ["); + status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, JK_STATUS_ARG_OPTION_NO_LEGEND, 0, NULL, l); + jk_puts(s, "]</h2>\n"); + + jk_puts(s, "<table>\n" + "<tbody valign=\"baseline\">\n" + "<tr><th>Name</th><td>Worker name</td></tr>\n" + "<tr><th>Type</th><td>Worker type</td></tr>\n" + "<tr><th>Route</th><td>Worker route</td></tr>\n" + "<tr><th>Act</th><td>Worker activation configuration<br/>\n" + "ACT=Active, DIS=Disabled, STP=Stopped</td></tr>\n" + "<tr><th>State</th><td>Worker error status<br/>\n" + "OK=OK, ERR=Error with substates<br/>\n" + "IDLE=No requests handled, BUSY=All connections busy,<br/>\n" + "REC=Recovering, PRB=Probing, FRC=Forced Recovery</td></tr>\n" + "<tr><th>D</th><td>Worker distance</td></tr>\n" + "<tr><th>F</th><td>Load Balancer factor</td></tr>\n" + "<tr><th>M</th><td>Load Balancer multiplicity</td></tr>\n" + "<tr><th>V</th><td>Load Balancer value</td></tr>\n" + "<tr><th>Acc</th><td>Number of requests</td></tr>\n" + "<tr><th>Err</th><td>Number of failed requests</td></tr>\n" + "<tr><th>CE</th><td>Number of client errors</td></tr>\n" + "<tr><th>RE</th><td>Number of reply timeouts (decayed)</td></tr>\n" + "<tr><th>Wr</th><td>Number of bytes transferred</td></tr>\n" + "<tr><th>Rd</th><td>Number of bytes read</td></tr>\n" + "<tr><th>Busy</th><td>Current number of busy connections</td></tr>\n" + "<tr><th>Max</th><td>Maximum number of busy connections</td></tr>\n" + "<tr><th>Con</th><td>Current number of backend connections</td></tr>\n" + "<tr><th>RR</th><td>Route redirect</td></tr>\n" + "<tr><th>Cd</th><td>Cluster domain</td></tr>\n" + "<tr><th>Rs</th><td>Recovery scheduled in app. min/max seconds</td></tr>\n" + "<tr><th>LR</th><td>Seconds since last reset of statistics counters</td></tr>\n" + "<tr><th>LE</th><td>Timestamp of the last error</td></tr>\n" + "</tbody>\n" + "</table>\n"); + } + + JK_TRACE_EXIT(l); +} + +static int check_worker(jk_ws_service_t *s, + status_endpoint_t *p, + jk_uint32_t allow_wildchars, + jk_logger_t *l) +{ + const char *worker; + const char *sub_worker; + status_worker_t *w = p->worker; + jk_worker_t *jw = NULL; + lb_sub_worker_t *wr = NULL; + + JK_TRACE_ENTER(l); + if (fetch_worker_and_sub_worker(p, "checking", &worker, &sub_worker, l) == JK_FALSE || + search_worker(s, p, &jw, worker, l) == JK_FALSE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (sub_worker && sub_worker[0]) { + unsigned int idx = 0; + unsigned int *wi = NULL; + if (strchr(sub_worker, '*') || strchr(sub_worker, '?')) { + /* We have a wildchar matching rule */ + if (!allow_wildchars) { + jk_log(l, JK_LOG_ERROR, + "Status worker '%s' wildcards in sub worker '%s' of worker '%s' not allowed for this command", + w->name, sub_worker, worker ? worker : "(null)"); + p->msg = "wildcard not allowed in sub worker for this command"; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + else { + wi = &idx; + } + } + if (search_sub_worker(s, p, jw, worker, &wr, sub_worker, + wi, l) == JK_FALSE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +static void count_workers(jk_ws_service_t *s, + status_endpoint_t *p, + int *lb_cnt, int *ajp_cnt, + jk_logger_t *l) +{ + unsigned int i; + jk_worker_t *jw = NULL; + status_worker_t *w = p->worker; + + JK_TRACE_ENTER(l); + *lb_cnt = 0; + *ajp_cnt = 0; + for (i = 0; i < w->we->num_of_workers; i++) { + jw = wc_get_worker_for_name(w->we->worker_list[i], l); + if (!jw) { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' could not find worker '%s'", + w->name, w->we->worker_list[i]); + continue; + } + if (jw->type == JK_LB_WORKER_TYPE) { + (*lb_cnt)++; + } + else if (jw->type == JK_AJP13_WORKER_TYPE || + jw->type == JK_AJP14_WORKER_TYPE) { + (*ajp_cnt)++; + } + } + JK_TRACE_EXIT(l); +} + +static void list_workers_type(jk_ws_service_t *s, + status_endpoint_t *p, + int list_lb, int count, + jk_logger_t *l) +{ + + const char *arg; + unsigned int i; + int mime; + unsigned int hide; + jk_worker_t *jw = NULL; + status_worker_t *w = p->worker; + + JK_TRACE_ENTER(l); + + status_get_string(p, JK_STATUS_ARG_MIME, NULL, &arg, l); + mime = status_mime_int(arg); + if (list_lb) { + hide = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & + JK_STATUS_ARG_OPTION_NO_LB; + if (hide) { + if (mime == JK_STATUS_MIME_HTML) { + jk_puts(s, "<p>\n"); + status_write_uri(s, p, "Show Load Balancing Workers", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_LB, NULL, l); + jk_puts(s, "</p>\n"); + } + } + else { + if (mime == JK_STATUS_MIME_XML) { + jk_print_xml_start_elt(s, w, 0, 0, "balancers"); + jk_print_xml_att_int(s, 2, "count", count); + jk_print_xml_stop_elt(s, 0, 0); + } + else if (mime == JK_STATUS_MIME_TXT) { + jk_printf(s, "Balancer Workers: count=%d\n", count); + } + else if (mime == JK_STATUS_MIME_PROP) { + jk_print_prop_att_int(s, w, NULL, "lb_count", count); + } + else { + jk_printf(s, "<hr/><h2>Listing Load Balancing Worker%s (%d Worker%s) [", + count>1 ? "s" : "", count, count>1 ? "s" : ""); + status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, JK_STATUS_ARG_OPTION_NO_LB, 0, NULL, l); + jk_puts(s, "]</h2>\n"); + } + } + } + else { + hide = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & + JK_STATUS_ARG_OPTION_NO_AJP; + if (hide) { + if (mime == JK_STATUS_MIME_HTML) { + jk_puts(s, "<p>\n"); + status_write_uri(s, p, "Show AJP Workers", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_AJP, NULL, l); + jk_puts(s, "</p>\n"); + } + } + else { + if (mime == JK_STATUS_MIME_XML) { + jk_print_xml_start_elt(s, w, 0, 0, "ajp_workers"); + jk_print_xml_att_int(s, 2, "count", count); + jk_print_xml_stop_elt(s, 0, 0); + } + else if (mime == JK_STATUS_MIME_TXT) { + jk_printf(s, "AJP Workers: count=%d\n", count); + } + else if (mime == JK_STATUS_MIME_PROP) { + jk_print_prop_att_int(s, w, NULL, "ajp_count", count); + } + else { + jk_printf(s, "<hr/><h2>Listing AJP Worker%s (%d Worker%s) [", + count>1 ? "s" : "", count, count>1 ? "s" : ""); + status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, JK_STATUS_ARG_OPTION_NO_AJP, 0, NULL, l); + jk_puts(s, "]</h2>\n"); + } + } + } + + if (hide) { + JK_TRACE_EXIT(l); + return; + } + + for (i = 0; i < w->we->num_of_workers; i++) { + jw = wc_get_worker_for_name(w->we->worker_list[i], l); + if (!jw) { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' could not find worker '%s'", + w->name, w->we->worker_list[i]); + continue; + } + if ((list_lb && jw->type == JK_LB_WORKER_TYPE) || + (!list_lb && jw->type != JK_LB_WORKER_TYPE)) { + display_worker(s, p, jw, NULL, l); + } + } + + if (list_lb) { + if (mime == JK_STATUS_MIME_XML) { + jk_print_xml_close_elt(s, w, 0, "balancers"); + } + else if (mime == JK_STATUS_MIME_TXT) { + } + else if (mime == JK_STATUS_MIME_PROP) { + } + else if (mime == JK_STATUS_MIME_HTML) { + } + } + else { + if (mime == JK_STATUS_MIME_XML) { + jk_print_xml_close_elt(s, w, 0, "ajp_workers"); + } + else if (mime == JK_STATUS_MIME_TXT) { + } + else if (mime == JK_STATUS_MIME_PROP) { + } + else if (mime == JK_STATUS_MIME_HTML) { + } + } + + JK_TRACE_EXIT(l); +} + +static int list_workers(jk_ws_service_t *s, + status_endpoint_t *p, + jk_logger_t *l) +{ + int lb_cnt = 0; + int ajp_cnt = 0; + + JK_TRACE_ENTER(l); + count_workers(s, p, &lb_cnt, &ajp_cnt, l); + + if (lb_cnt) { + list_workers_type(s, p, 1, lb_cnt, l); + } + + if (ajp_cnt) { + list_workers_type(s, p, 0, ajp_cnt, l); + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +static int show_worker(jk_ws_service_t *s, + status_endpoint_t *p, + jk_logger_t *l) +{ + const char *worker; + const char *sub_worker; + jk_worker_t *jw = NULL; + lb_sub_worker_t *wr = NULL; + + JK_TRACE_ENTER(l); + if (fetch_worker_and_sub_worker(p, "showing", &worker, &sub_worker, l) == JK_FALSE || + search_worker(s, p, &jw, worker, l) == JK_FALSE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + if (sub_worker && sub_worker[0]) { + if (search_sub_worker(s, p, jw, worker, &wr, sub_worker, + NULL, l) == JK_FALSE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + display_worker(s, p, jw, wr, l); + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +static int edit_worker(jk_ws_service_t *s, + status_endpoint_t *p, + jk_logger_t *l) +{ + const char *worker; + const char *sub_worker; + status_worker_t *w = p->worker; + jk_worker_t *jw = NULL; + lb_worker_t *lb = NULL; + lb_sub_worker_t *wr = NULL; + ajp_worker_t *aw = NULL; + + JK_TRACE_ENTER(l); + if (fetch_worker_and_sub_worker(p, "editing", &worker, &sub_worker, l) == JK_FALSE || + search_worker(s, p, &jw, worker, l) == JK_FALSE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (jw->type == JK_LB_WORKER_TYPE) { + if (check_valid_lb(s, p, jw, worker, &lb, 0, l) == JK_FALSE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (lb->sequence != lb->s->h.sequence) + jk_lb_pull(lb, JK_FALSE, l); + if (!sub_worker || !sub_worker[0]) { + const char *arg; + if (status_get_string(p, JK_STATUS_ARG_ATTRIBUTE, + NULL, &arg, l) == JK_TRUE) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' %s lb worker '%s' with all sub workers", + w->name, "editing", lb->name); + form_all_members(s, p, jw, arg, l); + } + else { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' %s lb worker '%s'", + w->name, "editing", lb->name); + form_worker(s, p, jw, l); + } + JK_TRACE_EXIT(l); + return JK_TRUE; + } + else { + if (search_sub_worker(s, p, jw, worker, &wr, sub_worker, + NULL, l) == JK_FALSE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' %s lb worker '%s' sub worker '%s'", + w->name, "editing", lb->name, wr->name); + aw = (ajp_worker_t *)wr->worker->worker_private; + form_member(s, p, wr, aw, worker, l); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + } + else if (jw->type == JK_AJP13_WORKER_TYPE || + jw->type == JK_AJP14_WORKER_TYPE) { + ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private; + if (aw) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' %s ajp worker '%s'", + w->name, "editing", aw->name); + if (aw->sequence != aw->s->h.sequence) + jk_ajp_pull(aw, JK_FALSE, l); + form_member(s, p, NULL, aw, worker, l); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + else { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' aw worker is (null)", + w->name); + } + } + else { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' worker type not implemented", + w->name); + } + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +static int update_worker(jk_ws_service_t *s, + status_endpoint_t *p, + jk_logger_t *l) +{ + const char *worker; + const char *sub_worker; + status_worker_t *w = p->worker; + jk_worker_t *jw = NULL; + lb_worker_t *lb = NULL; + lb_sub_worker_t *wr = NULL; + ajp_worker_t *aw = NULL; + int rc = JK_TRUE; + int rv; + + JK_TRACE_ENTER(l); + if (fetch_worker_and_sub_worker(p, "updating", &worker, &sub_worker, l) == JK_FALSE || + search_worker(s, p, &jw, worker, l) == JK_FALSE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (jw->type == JK_LB_WORKER_TYPE) { + if (check_valid_lb(s, p, jw, worker, &lb, 0, l) == JK_FALSE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (lb->sequence != lb->s->h.sequence) + jk_lb_pull(lb, JK_TRUE, l); + if (!sub_worker || !sub_worker[0]) { + const char *arg; + if (status_get_string(p, JK_STATUS_ARG_ATTRIBUTE, + NULL, &arg, l) == JK_TRUE) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' %s lb worker '%s' with all sub workers", + w->name, "updating", lb->name); + commit_all_members(s, p, jw, arg, l); + } + else { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' %s lb worker '%s'", + w->name, "updating", lb->name); + commit_worker(s, p, jw, l); + } + JK_TRACE_EXIT(l); + return JK_TRUE; + } + else { + unsigned int idx = 0; + unsigned int *wi = NULL; + int is_wildchar = JK_FALSE; + + if (strchr(sub_worker, '*') || strchr(sub_worker, '?')) { + /* We have a wildchar matching rule */ + wi = &idx; + is_wildchar = JK_TRUE; + } + for (;;) { + if (search_sub_worker(s, p, jw, worker, &wr, sub_worker, + wi, l) == JK_FALSE) { + if (!idx) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + else { + /* We have found at least one match previously */ + p->msg = "OK"; + break; + } + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' %s lb worker '%s' sub worker '%s'", + w->name, "updating", lb->name, wr->name); + aw = (ajp_worker_t *)wr->worker->worker_private; + rv = 0; + rc = commit_member(s, p, lb, wr, aw, &rv, l); + if (rv & JK_STATUS_NEEDS_ADDR_PUSH) { + aw->addr_sequence++; + } + if (rv & (JK_STATUS_NEEDS_PUSH | JK_STATUS_NEEDS_ADDR_PUSH)) { + wr->sequence++; + lb->sequence++; + jk_lb_push(lb, JK_TRUE, l); + } + if (rv & JK_STATUS_NEEDS_RESET_LB_VALUES) + reset_lb_values(lb, l); + if (rv & JK_STATUS_NEEDS_UPDATE_MULT) + /* Recalculate the load multiplicators wrt. lb_factor */ + update_mult(lb, l); + if (rc == JK_FALSE) { + jk_log(l, JK_LOG_ERROR, + "Status worker '%s' failed updating sub worker '%s' (at least partially).%s", + w->name, aw->name, (is_wildchar == JK_TRUE) ? " Aborting further wildcard updates." : ""); + if (!strncmp("OK", p->msg, 3)) { + const char *msg = "Update failed (at least partially) for sub worker '%s'"; + size_t size = strlen(msg) + strlen(aw->name) + 1; + p->msg = jk_pool_alloc(s->pool, size); + snprintf(p->msg, size, msg, aw->name); + } + if (is_wildchar == JK_TRUE) { + const char *msg = " Aborting further wildcard updates."; + size_t size = strlen(msg) + strlen(p->msg) + 1; + p->msg = jk_pool_realloc(s->pool, size, p->msg, strlen(p->msg) + 1); + strcat(p->msg, msg); + } + break; + } + if (!wi) + break; + } + JK_TRACE_EXIT(l); + return rc; + } + } + else if (jw->type == JK_AJP13_WORKER_TYPE || + jw->type == JK_AJP14_WORKER_TYPE) { + ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private; + if (aw) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' %s ajp worker '%s'", + w->name, "updating", aw->name); + if (aw->sequence != aw->s->h.sequence) + jk_ajp_pull(aw, JK_TRUE, l); + rv = 0; + rc = commit_member(s, p, NULL, NULL, aw, &rv, l); + if (rv & JK_STATUS_NEEDS_ADDR_PUSH) { + aw->addr_sequence++; + } + if (rv & (JK_STATUS_NEEDS_PUSH | JK_STATUS_NEEDS_ADDR_PUSH)) { + aw->sequence++; + jk_ajp_push(aw, JK_TRUE, l); + } + if (rc == JK_FALSE) { + jk_log(l, JK_LOG_ERROR, + "Status worker '%s' failed updating worker '%s' (at least partially).", + w->name, aw->name); + if (!strncmp("OK", p->msg, 3)) { + const char *msg = "Update failed (at least partially) for worker '%s'"; + size_t size = strlen(msg) + strlen(aw->name) + 1; + p->msg = jk_pool_alloc(s->pool, size); + snprintf(p->msg, size, msg, aw->name); + } + } + JK_TRACE_EXIT(l); + return rc; + } + else { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' aw worker is (null)", + w->name); + } + } + else { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' worker type not implemented", + w->name); + } + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +static int reset_worker(jk_ws_service_t *s, + status_endpoint_t *p, + jk_logger_t *l) +{ + unsigned int i; + const char *worker; + const char *sub_worker; + status_worker_t *w = p->worker; + jk_worker_t *jw = NULL; + lb_worker_t *lb = NULL; + lb_sub_worker_t *wr = NULL; + ajp_worker_t *aw = NULL; + time_t now = 0; + + JK_TRACE_ENTER(l); + if (fetch_worker_and_sub_worker(p, "resetting", &worker, &sub_worker, l) == JK_FALSE || + search_worker(s, p, &jw, worker, l) == JK_FALSE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + now = time(NULL); + if (jw->type == JK_LB_WORKER_TYPE) { + if (check_valid_lb(s, p, jw, worker, &lb, 0, l) == JK_FALSE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (!sub_worker || !sub_worker[0]) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' %s lb worker '%s' with all sub workers", + w->name, "resetting", lb->name); + lb->s->max_busy = 0; + lb->s->last_reset = now; + for (i = 0; i < lb->num_of_workers; i++) { + wr = &(lb->lb_workers[i]); + aw = (ajp_worker_t *)wr->worker->worker_private; + wr->s->state = JK_LB_STATE_IDLE; + wr->s->elected_snapshot = 0; + wr->s->error_time = 0; + wr->s->errors = 0; + wr->s->lb_value = 0; + aw->s->used = 0; + aw->s->client_errors = 0; + aw->s->reply_timeouts = 0; + aw->s->transferred = 0; + aw->s->readed = 0; + aw->s->max_busy = 0; + aw->s->last_reset = now; + } + JK_TRACE_EXIT(l); + return JK_TRUE; + } + else { + if (search_sub_worker(s, p, jw, worker, &wr, sub_worker, + NULL, l) == JK_FALSE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' %s lb worker '%s' sub worker '%s'", + w->name, "resetting", lb->name, wr->name); + aw = (ajp_worker_t *)wr->worker->worker_private; + wr->s->state = JK_LB_STATE_IDLE; + wr->s->elected_snapshot = 0; + wr->s->error_time = 0; + wr->s->errors = 0; + wr->s->lb_value = 0; + aw->s->used = 0; + aw->s->client_errors = 0; + aw->s->reply_timeouts = 0; + aw->s->transferred = 0; + aw->s->readed = 0; + aw->s->max_busy = 0; + aw->s->last_reset = now; + JK_TRACE_EXIT(l); + return JK_TRUE; + } + } + else if (jw->type == JK_AJP13_WORKER_TYPE || + jw->type == JK_AJP14_WORKER_TYPE) { + ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private; + if (aw) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' %s ajp worker '%s'", + w->name, "resetting", aw->name); + aw->s->errors = 0; + aw->s->used = 0; + aw->s->client_errors = 0; + aw->s->reply_timeouts = 0; + aw->s->transferred = 0; + aw->s->readed = 0; + aw->s->max_busy = 0; + aw->s->last_reset = now; + JK_TRACE_EXIT(l); + return JK_TRUE; + } + else { + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' aw worker is (null)", + w->name); + } + } + else { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' worker type not implemented", + w->name); + } + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +static int recover_worker(jk_ws_service_t *s, + status_endpoint_t *p, + jk_logger_t *l) +{ + const char *worker; + const char *sub_worker; + jk_worker_t *jw = NULL; + lb_sub_worker_t *wr = NULL; + ajp_worker_t *aw = NULL; + status_worker_t *w = p->worker; + + JK_TRACE_ENTER(l); + if (fetch_worker_and_sub_worker(p, "recovering", &worker, &sub_worker, l) == JK_FALSE || + search_worker(s, p, &jw, worker, l) == JK_FALSE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (search_sub_worker(s, p, jw, worker, &wr, sub_worker, + NULL, l) == JK_FALSE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + aw = (ajp_worker_t *)wr->worker->worker_private; + if (wr->s->state == JK_LB_STATE_ERROR) { + lb_worker_t *lb = NULL; + + /* We need an lb to correct the lb_value */ + if (check_valid_lb(s, p, jw, worker, &lb, 0, l) == JK_FALSE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (lb->lbmethod != JK_LB_METHOD_BUSYNESS) { + unsigned int i; + jk_uint64_t curmax = 0; + + for (i = 0; i < lb->num_of_workers; i++) { + if (lb->lb_workers[i].s->lb_value > curmax) { + curmax = lb->lb_workers[i].s->lb_value; + } + } + wr->s->lb_value = curmax; + } + + aw->s->reply_timeouts = 0; + wr->s->state = JK_LB_STATE_RECOVER; + jk_log(l, JK_LOG_INFO, + "Status worker '%s' marked worker '%s' sub worker '%s' for recovery", + w->name, worker ? worker : "(null)", sub_worker ? sub_worker : "(null)"); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' could not mark worker '%s' sub worker '%s' for recovery - state %s is not an error state", + w->name, worker ? worker : "(null)", sub_worker ? sub_worker : "(null)", + jk_lb_get_state(wr, l)); + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +static int dump_config(jk_ws_service_t *s, + status_endpoint_t *p, + int mime, jk_logger_t *l) +{ + status_worker_t *w = p->worker; + jk_worker_env_t *we = w->we; + jk_map_t *init_data = we->init_data; + + JK_TRACE_ENTER(l); + + if (init_data) { + int l = jk_map_size(init_data); + int i; + if (mime == JK_STATUS_MIME_HTML) { + jk_puts(s, "<hr/><h2>Configuration Data</h2><hr/>\n"); + jk_puts(s, "This dump does not include any changes applied by the status worker\n"); + jk_puts(s, "to the configuration after the initial startup\n"); + jk_puts(s, "<PRE>\n"); + } + else if (mime == JK_STATUS_MIME_XML) { + jk_print_xml_start_elt(s, w, 2, 0, "configuration"); + } + else if (mime == JK_STATUS_MIME_TXT) { + jk_puts(s, "Configuration:\n"); + } + for (i=0;i<l;i++) { + const char *name = jk_map_name_at(init_data, i); + if (name) { + const char *value; + size_t nl = strlen(name); + if (nl > sizeof(".secret") && + strcmp(name + nl - 7, ".secret") == 0) { + continue; + } + value = jk_map_value_at(init_data, i); + if (!value) + value = "(null)"; + if (mime == JK_STATUS_MIME_HTML || + mime == JK_STATUS_MIME_PROP || + mime == JK_STATUS_MIME_TXT) { + jk_putv(s, name, "=", value, "\n", NULL); + } + else if (mime == JK_STATUS_MIME_XML) { + jk_print_xml_att_string(s, 4, name, value); + } + } + } + if (mime == JK_STATUS_MIME_HTML) { + jk_puts(s, "</PRE>\n"); + } + else if (mime == JK_STATUS_MIME_XML) { + jk_print_xml_stop_elt(s, 2, 1); + } + } + else { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +/* + * Return values of service() method for status worker: + * return value is_error reason + * JK_FALSE JK_HTTP_SERVER_ERROR Invalid parameters (null values) + * JK_TRUE JK_HTTP_OK All other cases + */ +static int JK_METHOD service(jk_endpoint_t *e, + jk_ws_service_t *s, + jk_logger_t *l, int *is_error) +{ + int cmd; + jk_uint32_t cmd_props; + int mime; + int refresh; + int read_only = 0; + const char *arg; + char *err = NULL; + status_endpoint_t *p; + status_worker_t *w; + int denied = 0; + + JK_TRACE_ENTER(l); + + if (!e || !e->endpoint_private || !s || !is_error) { + JK_LOG_NULL_PARAMS(l); + if (is_error) + *is_error = JK_HTTP_SERVER_ERROR; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + p = e->endpoint_private; + w = p->worker; + + /* Set returned error to OK */ + *is_error = JK_HTTP_OK; + + if (w->num_of_users) { + if (s->remote_user) { + unsigned int i; + denied = 1; + for (i = 0; i < w->num_of_users; i++) { + if (w->user_case_insensitive) { + if (!strcasecmp(s->remote_user, w->user_names[i])) { + denied = 0; + break; + } + } + else { + if (!strcmp(s->remote_user, w->user_names[i])) { + denied = 0; + break; + } + } + } + } + else { + denied = 2; + } + } + + /* Step 1: Process GET params and update configuration */ + if (status_parse_uri(s, p, l) != JK_TRUE) { + err = "Error during parsing of URI"; + } + status_get_string(p, JK_STATUS_ARG_CMD, NULL, &arg, l); + cmd = status_cmd_int(arg); + cmd_props = status_cmd_props(cmd); + status_get_string(p, JK_STATUS_ARG_MIME, NULL, &arg, l); + mime = status_mime_int(arg); + refresh = status_get_int(p, JK_STATUS_ARG_REFRESH, 0, l); + if (w->read_only) { + read_only = 1; + } + else { + read_only = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & + JK_STATUS_ARG_OPTION_READ_ONLY; + } + + if (mime == JK_STATUS_MIME_HTML) { + s->start_response(s, 200, "OK", headers_names, headers_vhtml, 3); + jk_puts(s, JK_STATUS_HEAD); + } + else if (mime == JK_STATUS_MIME_XML) { + s->start_response(s, 200, "OK", headers_names, headers_vxml, 3); + jk_puts(s, JK_STATUS_XMLH); + if (w->doctype) { + jk_putv(s, w->doctype, "\n", NULL); + } + jk_print_xml_start_elt(s, w, 0, 0, "status"); + if (w->xmlns && strlen(w->xmlns)) + jk_putv(s, " ", w->xmlns, NULL); + jk_print_xml_stop_elt(s, 0, 0); + } + else { + s->start_response(s, 200, "OK", headers_names, headers_vtxt, 3); + } + + if (denied == 0) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' service allowed for user '%s' [%s] from %s [%s]", + w->name, + s->remote_user ? s->remote_user : "(null)", + s->auth_type ? s->auth_type : "(null)", + s->remote_addr ? s->remote_addr : "(null)", + s->remote_host ? s->remote_host : "(null)"); + } + else if (denied == 1) { + err = "Access denied."; + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' service denied for user '%s' [%s] from %s [%s]", + w->name, + s->remote_user ? s->remote_user : "(null)", + s->auth_type ? s->auth_type : "(null)", + s->remote_addr ? s->remote_addr : "(null)", + s->remote_host ? s->remote_host : "(null)"); + } + else if (denied == 2) { + err = "Access denied."; + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' service denied (no user) [%s] from %s [%s]", + w->name, + s->remote_user ? s->remote_user : "(null)", + s->auth_type ? s->auth_type : "(null)", + s->remote_addr ? s->remote_addr : "(null)", + s->remote_host ? s->remote_host : "(null)"); + } + else { + err = "Access denied."; + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' service denied (unknown reason) for user '%s' [%s] from %s [%s]", + w->name, + s->remote_user ? s->remote_user : "(null)", + s->auth_type ? s->auth_type : "(null)", + s->remote_addr ? s->remote_addr : "(null)", + s->remote_host ? s->remote_host : "(null)"); + } + + if (!err) { + if (read_only && !(cmd_props & JK_STATUS_CMD_PROP_READONLY)) { + err = "This command is not allowed in read only mode."; + } + } + + if (!err) { + if (cmd == JK_STATUS_CMD_UNKNOWN) { + err = "Invalid command."; + } + else if (mime == JK_STATUS_MIME_UNKNOWN) { + err = "Invalid mime type."; + } + else if (cmd_props & JK_STATUS_CMD_PROP_CHECK_WORKER && + (check_worker(s, p, cmd_props & JK_STATUS_CMD_PROP_WILDCARD, l) != JK_TRUE)) { + err = p->msg; + } + } + + if (!err) { + char buf_time[JK_STATUS_TIME_BUF_SZ]; + char buf_tz[JK_STATUS_TIME_BUF_SZ]; + time_t clock = time(NULL); + long unix_seconds = (long)clock; + int rc_time = status_strftime(clock, mime, buf_time, buf_tz, l); + if (cmd == JK_STATUS_CMD_UPDATE) { + /* lock shared memory */ + jk_shm_lock(); + if (update_worker(s, p, l) == JK_FALSE) { + if (strncmp("OK", p->msg, 3)) + err = p->msg; + else + err = "Update failed"; + } + /* unlock the shared memory */ + jk_shm_unlock(); + if (mime == JK_STATUS_MIME_HTML) { + write_html_refresh_response(s, p, err, l); + } + } + else if (cmd == JK_STATUS_CMD_RESET) { + /* lock shared memory */ + jk_shm_lock(); + if (reset_worker(s, p, l) == JK_FALSE) { + err = "Reset failed"; + } + /* unlock the shared memory */ + jk_shm_unlock(); + if (mime == JK_STATUS_MIME_HTML) { + write_html_refresh_response(s, p, err, l); + } + } + else if (cmd == JK_STATUS_CMD_RECOVER) { + /* lock shared memory */ + jk_shm_lock(); + if (recover_worker(s, p, l) == JK_FALSE) { + err = "Marking worker for recovery failed"; + } + /* unlock the shared memory */ + jk_shm_unlock(); + if (mime == JK_STATUS_MIME_HTML) { + write_html_refresh_response(s, p, err, l); + } + } + else { + if (mime == JK_STATUS_MIME_XML) { + jk_print_xml_start_elt(s, w, 0, 0, "server"); + jk_print_xml_att_string(s, 2, "name", s->server_name); + jk_print_xml_att_int(s, 2, "port", s->server_port); + jk_print_xml_stop_elt(s, 0, 1); + if (cmd_props & JK_STATUS_CMD_PROP_HEAD) { + if (rc_time > 0 ) { + jk_print_xml_start_elt(s, w, 0, 0, "time"); + jk_print_xml_att_string(s, 2, "datetime", buf_time); + jk_print_xml_att_string(s, 2, "tz", buf_tz); + jk_print_xml_att_long(s, 2, "unix", unix_seconds); + jk_print_xml_stop_elt(s, 0, 1); + } + jk_print_xml_start_elt(s, w, 0, 0, "software"); + jk_print_xml_att_string(s, 2, "web_server", s->server_software); + jk_print_xml_att_string(s, 2, "jk_version", JK_FULL_EXPOSED_VERSION); + jk_print_xml_stop_elt(s, 0, 1); + } + if (cmd == JK_STATUS_CMD_LIST) { + /* Step 2: Display configuration */ + if (list_workers(s, p, l) != JK_TRUE) { + err = "Error in listing the workers."; + } + } + else if (cmd == JK_STATUS_CMD_SHOW) { + /* Step 2: Display detailed configuration */ + if (show_worker(s, p, l) != JK_TRUE) { + err = "Error in showing this worker."; + } + } + } + else if (mime == JK_STATUS_MIME_TXT) { + jk_puts(s, "Server:"); + jk_printf(s, " name=%s", s->server_name); + jk_printf(s, " port=%d", s->server_port); + jk_puts(s, "\n"); + if (cmd_props & JK_STATUS_CMD_PROP_HEAD) { + if (rc_time > 0) { + jk_puts(s, "Time:"); + jk_printf(s, " datetime=%s", buf_time); + jk_printf(s, " tz=%s", buf_tz); + jk_printf(s, " unix=%ld", unix_seconds); + jk_puts(s, "\n"); + } + jk_puts(s, "Software:"); + jk_printf(s, " web_server=\"%s\"", s->server_software); + jk_printf(s, " jk_version=%s", JK_FULL_EXPOSED_VERSION); + jk_puts(s, "\n"); + } + if (cmd == JK_STATUS_CMD_LIST) { + /* Step 2: Display configuration */ + if (list_workers(s, p, l) != JK_TRUE) { + err = "Error in listing the workers."; + } + } + else if (cmd == JK_STATUS_CMD_SHOW) { + /* Step 2: Display detailed configuration */ + if (show_worker(s, p, l) != JK_TRUE) { + err = "Error in showing this worker."; + } + } + } + else if (mime == JK_STATUS_MIME_PROP) { + jk_print_prop_att_string(s, w, NULL, "server_name", s->server_name); + jk_print_prop_att_int(s, w, NULL, "server_port", s->server_port); + if (cmd_props & JK_STATUS_CMD_PROP_HEAD) { + if (rc_time > 0) { + jk_print_prop_att_string(s, w, NULL, "time_datetime", buf_time); + jk_print_prop_att_string(s, w, NULL, "time_tz", buf_tz); + jk_print_prop_att_long(s, w, NULL, "time_unix", unix_seconds); + } + jk_print_prop_att_string(s, w, NULL, "web_server", s->server_software); + jk_print_prop_att_string(s, w, NULL, "jk_version", JK_FULL_EXPOSED_VERSION); + } + if (cmd == JK_STATUS_CMD_LIST) { + /* Step 2: Display configuration */ + if (list_workers(s, p, l) != JK_TRUE) { + err = "Error in listing the workers."; + } + } + else if (cmd == JK_STATUS_CMD_SHOW) { + /* Step 2: Display detailed configuration */ + if (show_worker(s, p, l) != JK_TRUE) { + err = "Error in showing this worker."; + } + } + } + else if (mime == JK_STATUS_MIME_HTML) { + if (cmd_props & JK_STATUS_CMD_PROP_REFRESH && + refresh > 0) { + jk_printf(s, "\n<meta http-equiv=\"Refresh\" content=\"%d;url=%s?%s\">", + refresh, s->req_uri, p->query_string); + } + if (w->css) { + jk_putv(s, "\n<link rel=\"stylesheet\" type=\"text/css\" href=\"", + w->css, "\" />\n", NULL); + } + jk_puts(s, JK_STATUS_HEND); + jk_puts(s, "<h1>JK Status Manager for "); + jk_puts(s, s->server_name); + jk_printf(s, ":%d", s->server_port); + if (read_only) { + jk_puts(s, " (read only)"); + } + jk_puts(s, "</h1>\n\n"); + if (cmd_props & JK_STATUS_CMD_PROP_HEAD) { + jk_putv(s, "<table><tr><td>Server Version:</td><td>", + s->server_software, "</td><td> </td><td>", NULL); + if (rc_time > 0) { + jk_putv(s, "Server Time:</td><td>", buf_time, NULL); + } + jk_puts(s, "</td></tr>\n"); + jk_putv(s, "<tr><td>JK Version:</td><td>", + JK_FULL_EXPOSED_VERSION, "</td><td></td><td>", NULL); + jk_printf(s, "Unix Seconds:</td><td>%d", unix_seconds); + jk_puts(s, "</td></tr></table>\n<hr/>\n"); + } + jk_puts(s, "<table><tbody valign=\"baseline\"><tr>\n"); + if (cmd_props & JK_STATUS_CMD_PROP_REFRESH) { + jk_puts(s, "<td>"); + if (refresh > 0) { + const char *str = p->query_string; + char *buf = jk_pool_alloc(s->pool, sizeof(char *) * (strlen(str)+1)); + int result = 0; + size_t scan = 0; + size_t len = strlen(JK_STATUS_ARG_REFRESH); + + while (str[scan] != '\0') { + if (strncmp(&str[scan], JK_STATUS_ARG_REFRESH, len) == 0 && + str[scan+len] == '=') { + scan += len + 1; + while (str[scan] != '\0' && str[scan] != '&') + scan++; + if (str[scan] == '&') + scan++; + } + else { + if (result > 0 && str[scan] != '\0' && str[scan] != '&') { + buf[result] = '&'; + result++; + } + while (str[scan] != '\0' && str[scan] != '&') { + buf[result] = str[scan]; + result++; + scan++; + } + if (str[scan] == '&') + scan++; + } + } + buf[result] = '\0'; + + jk_putv(s, "[<a href=\"", s->req_uri, NULL); + if (buf && buf[0]) + jk_putv(s, "?", buf, NULL); + jk_puts(s, "\">Stop auto refresh</a>]"); + } + else { + status_start_form(s, p, "get", JK_STATUS_CMD_UNKNOWN, JK_STATUS_ARG_REFRESH, l); + jk_puts(s, "<input type=\"submit\" value=\"Start auto refresh\"/>\n"); + jk_putv(s, "(every ", + "<input name=\"", JK_STATUS_ARG_REFRESH, + "\" type=\"text\" size=\"3\" value=\"", + JK_STATUS_REFRESH_DEF "\"/> ", + "seconds)", NULL); + jk_puts(s, "</form>\n"); + } + jk_puts(s, "</td><td> | </td>\n"); + } + if (cmd_props & JK_STATUS_CMD_PROP_FMT) { + jk_puts(s, "<td>\n"); + status_start_form(s, p, "get", JK_STATUS_CMD_UNKNOWN, JK_STATUS_ARG_MIME, l); + jk_puts(s, "<input type=\"submit\" value=\"Change format\"/>\n"); + jk_putv(s, "<select name=\"", JK_STATUS_ARG_MIME, "\" size=\"1\">", NULL); + jk_putv(s, "<option value=\"", JK_STATUS_MIME_TEXT_XML, "\">XML</option>", NULL); + jk_putv(s, "<option value=\"", JK_STATUS_MIME_TEXT_PROP, "\">Properties</option>", NULL); + jk_putv(s, "<option value=\"", JK_STATUS_MIME_TEXT_TXT, "\">Text</option>", NULL); + jk_puts(s, "</select></form>\n"); + jk_puts(s, "</td>\n"); + } + jk_puts(s, "</tr></table>\n"); + jk_puts(s, "<table><tbody valign=\"baseline\"><tr>\n"); + if (cmd_props & JK_STATUS_CMD_PROP_BACK_LINK) { + int from; + jk_puts(s, "<td>\n"); + status_get_string(p, JK_STATUS_ARG_FROM, NULL, &arg, l); + from = status_cmd_int(arg); + jk_puts(s, "["); + if (cmd_props & JK_STATUS_CMD_PROP_BACK_LIST || + from == JK_STATUS_CMD_LIST) { + status_write_uri(s, p, "Back to worker list", JK_STATUS_CMD_LIST, JK_STATUS_MIME_UNKNOWN, + "", "", 0, 0, "", l); + } + else { + status_write_uri(s, p, "Back to worker view", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, 0, 0, "", l); + } + jk_puts(s, "] "); + jk_puts(s, "</td>\n"); + } + if (cmd_props & JK_STATUS_CMD_PROP_SWITCH_RO) { + jk_puts(s, "<td>\n"); + if (!w->read_only) { + jk_puts(s, "["); + if (read_only) { + status_write_uri(s, p, "Read/Write", 0, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, 0, JK_STATUS_ARG_OPTION_READ_ONLY, NULL, l); + } + else { + status_write_uri(s, p, "Read Only", 0, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, JK_STATUS_ARG_OPTION_READ_ONLY, 0, NULL, l); + } + jk_puts(s, "] \n"); + } + jk_puts(s, "</td>\n"); + } + if (cmd_props & JK_STATUS_CMD_PROP_DUMP_LINK) { + jk_puts(s, "<td>\n"); + jk_puts(s, "["); + status_write_uri(s, p, "Dump", JK_STATUS_CMD_DUMP, JK_STATUS_MIME_UNKNOWN, + NULL, NULL, 0, 0, NULL, l); + jk_puts(s, "] \n"); + jk_puts(s, "</td>\n"); + } + if (cmd_props & JK_STATUS_CMD_PROP_LINK_HELP && + (cmd == JK_STATUS_CMD_LIST || !read_only)) { + jk_puts(s, "<td>\n"); + jk_puts(s, "["); + if (cmd == JK_STATUS_CMD_LIST) { + jk_puts(s, "<b>S</b>=Show only this worker, "); + } + jk_puts(s, "<b>E</b>=Edit worker, <b>R</b>=Reset worker state, <b>T</b>=Try worker recovery"); + jk_puts(s, "]<br/>\n"); + jk_puts(s, "</td>\n"); + } + jk_puts(s, "</tr></table>\n"); + if (cmd == JK_STATUS_CMD_LIST) { + /* Step 2: Display configuration */ + if (list_workers(s, p, l) != JK_TRUE) { + err = "Error in listing the workers."; + } + } + else if (cmd == JK_STATUS_CMD_SHOW) { + /* Step 2: Display detailed configuration */ + if (show_worker(s, p, l) != JK_TRUE) { + err = "Error in showing this worker."; + } + } + else if (cmd == JK_STATUS_CMD_EDIT) { + /* Step 2: Display edit form */ + if (edit_worker(s, p, l) != JK_TRUE) { + err = "Error in generating this worker's configuration form."; + } + } + } + if (cmd == JK_STATUS_CMD_DUMP) { + if (dump_config(s, p, mime, l) == JK_FALSE) { + err = "Dumping configuration failed"; + } + } + if (cmd_props & JK_STATUS_CMD_PROP_LEGEND) { + display_legend(s, p, l); + } + } + } + if (err) { + jk_log(l, JK_LOG_WARNING, "Status worker '%s': %s", w->name, err); + if (mime == JK_STATUS_MIME_HTML) { + jk_putv(s, "<p><b>Result: ERROR - ", err, "</b><br/>", NULL); + jk_putv(s, "<a href=\"", s->req_uri, "\">JK Status Manager Start Page</a></p>", NULL); + } + else if (mime == JK_STATUS_MIME_XML) { + jk_print_xml_start_elt(s, w, 2, 0, "result"); + jk_print_xml_att_string(s, 4, "type", "ERROR"); + jk_print_xml_att_string(s, 4, "message", err); + jk_print_xml_stop_elt(s, 2, 1); + } + else if (mime == JK_STATUS_MIME_TXT) { + jk_puts(s, "Result:"); + jk_printf(s, " type=%s", "ERROR"); + jk_printf(s, " message=\"%s\"", err); + jk_puts(s, "\n"); + } + else { + jk_print_prop_att_string(s, w, "result", "type", "ERROR"); + jk_print_prop_att_string(s, w, "result", "message", err); + } + } + else { + if (mime == JK_STATUS_MIME_HTML) { + jk_putv(s, "<p><a href=\"", s->req_uri, "\">JK Status Manager Start Page</a></p>", NULL); + } + else if (mime == JK_STATUS_MIME_XML) { + jk_print_xml_start_elt(s, w, 2, 0, "result"); + jk_print_xml_att_string(s, 4, "type", "OK"); + jk_print_xml_att_string(s, 4, "message", "Action finished"); + jk_print_xml_stop_elt(s, 2, 1); + } + else if (mime == JK_STATUS_MIME_TXT) { + jk_puts(s, "Result:"); + jk_printf(s, " type=%s", "OK"); + jk_printf(s, " message=\"%s\"", "Action finished"); + jk_puts(s, "\n"); + } + else { + jk_print_prop_att_string(s, w, "result", "type", "OK"); + jk_print_prop_att_string(s, w, "result", "message", "Action finished"); + } + } + if (mime == JK_STATUS_MIME_HTML) { + if (w->css) { + jk_putv(s, "<hr/><div class=\"footer\">", JK_STATUS_COPYRIGHT, + "</div>\n", NULL); + } + else { + jk_putv(s, "<hr/><p align=\"center\"><small>", JK_STATUS_COPYRIGHT, + "</small></p>\n", NULL); + } + jk_puts(s, JK_STATUS_BEND); + } + else if (mime == JK_STATUS_MIME_XML) { + jk_print_xml_close_elt(s, w, 0, "status"); + } + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +static int JK_METHOD done(jk_endpoint_t **e, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + if (e && *e && (*e)->endpoint_private) { + status_endpoint_t *p = (*e)->endpoint_private; + + jk_map_free(&(p->req_params)); + free(p); + *e = NULL; + JK_TRACE_EXIT(l); + return JK_TRUE; + } + + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +static int JK_METHOD validate(jk_worker_t *pThis, + jk_map_t *props, + jk_worker_env_t *we, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + if (pThis && pThis->worker_private) { + JK_TRACE_EXIT(l); + return JK_TRUE; + } + + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +static int JK_METHOD init(jk_worker_t *pThis, + jk_map_t *props, + jk_worker_env_t *we, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + if (pThis && pThis->worker_private) { + status_worker_t *p = pThis->worker_private; + char **good_rating; + unsigned int num_of_good; + char **bad_rating; + unsigned int num_of_bad; + unsigned int i; + p->we = we; + p->css = jk_get_worker_style_sheet(props, p->name, NULL); + p->prefix = jk_get_worker_prop_prefix(props, p->name, JK_STATUS_PREFIX_DEF); + p->ns = jk_get_worker_name_space(props, p->name, JK_STATUS_NS_DEF); + p->xmlns = jk_get_worker_xmlns(props, p->name, JK_STATUS_XMLNS_DEF); + p->doctype = jk_get_worker_xml_doctype(props, p->name, NULL); + p->read_only = jk_get_is_read_only(props, p->name); + p->user_case_insensitive = jk_get_worker_user_case_insensitive(props, p->name); + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' is %s and has css '%s', prefix '%s', name space '%s', xml name space '%s', document type '%s'", + p->name, + p->read_only ? "read-only" : "read/write", + p->css ? p->css : "(null)", + p->prefix ? p->prefix : "(null)", + p->ns ? p->ns : "(null)", + p->xmlns ? p->xmlns : "(null)", + p->doctype ? p->doctype : "(null)"); + if (jk_get_worker_user_list(props, p->name, + &(p->user_names), + &(p->num_of_users)) && p->num_of_users) { + for (i = 0; i < p->num_of_users; i++) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' restricting access to user '%s' case %s", + p->name, p->user_names[i], + p->user_case_insensitive ? "insensitive" : "sensitive"); + } + } + if (jk_get_worker_good_rating(props, p->name, + &good_rating, + &num_of_good) && num_of_good) { + p->good_mask = 0; + for (i = 0; i < num_of_good; i++) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' rating as good: '%s'", + p->name, good_rating[i]); + p->good_mask |= status_get_rating(good_rating[i], l); + } + } + else { + p->good_mask = JK_STATUS_MASK_GOOD_DEF; + } + if (jk_get_worker_bad_rating(props, p->name, + &bad_rating, + &num_of_bad) && num_of_bad) { + p->bad_mask = 0; + for (i = 0; i < num_of_bad; i++) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' rating as bad: '%s'", + p->name, bad_rating[i]); + p->bad_mask |= status_get_rating(bad_rating[i], l); + } + } + else { + p->bad_mask = JK_STATUS_MASK_BAD_DEF; + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Status worker '%s' has good rating for '%08" JK_UINT32_T_HEX_FMT + "' and bad rating for '%08" JK_UINT32_T_HEX_FMT "'", + p->name, + p->good_mask, + p->bad_mask); + if (p->good_mask & p->bad_mask) + jk_log(l, JK_LOG_WARNING, + "Status worker '%s' has non empty intersection '%08" JK_UINT32_T_HEX_FMT + "' between good rating for '%08" JK_UINT32_T_HEX_FMT + "' and bad rating for '%08" JK_UINT32_T_HEX_FMT "'", + p->name, + p->good_mask & p->bad_mask, + p->good_mask, + p->bad_mask); + } + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +static int JK_METHOD get_endpoint(jk_worker_t *pThis, + jk_endpoint_t **pend, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + if (pThis && pThis->worker_private && pend) { + status_endpoint_t *p = (status_endpoint_t *) malloc(sizeof(status_endpoint_t)); + p->worker = pThis->worker_private; + p->endpoint.endpoint_private = p; + p->endpoint.service = service; + p->endpoint.done = done; + p->req_params = NULL; + p->msg = NULL; + *pend = &p->endpoint; + + JK_TRACE_EXIT(l); + return JK_TRUE; + } + else { + JK_LOG_NULL_PARAMS(l); + } + + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +static int JK_METHOD destroy(jk_worker_t **pThis, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + if (pThis && *pThis && (*pThis)->worker_private) { + status_worker_t *private_data = (*pThis)->worker_private; + + jk_close_pool(&private_data->p); + free(private_data); + + JK_TRACE_EXIT(l); + return JK_TRUE; + } + + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +int JK_METHOD status_worker_factory(jk_worker_t **w, + const char *name, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + if (NULL != name && NULL != w) { + status_worker_t *private_data = + (status_worker_t *) calloc(1, sizeof(status_worker_t)); + + jk_open_pool(&private_data->p, + private_data->buf, + sizeof(jk_pool_atom_t) * TINY_POOL_SIZE); + + private_data->name = name; + + 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; + JK_TRACE_EXIT(l); + return JK_STATUS_WORKER_TYPE; + } + else { + JK_LOG_NULL_PARAMS(l); + } + + JK_TRACE_EXIT(l); + return 0; +} diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_status.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_status.h new file mode 100644 index 00000000..59eb1260 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_status.h @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Status worker header file * + * Author: Mladen Turk <mturk@jboss.com> * + * Version: $Revision: 466585 $ * + ***************************************************************************/ + +#ifndef JK_STATUS_H +#define JK_STATUS_H + +#include "jk_logger.h" +#include "jk_service.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#define JK_STATUS_WORKER_NAME ("status") +#define JK_STATUS_WORKER_TYPE (6) + +int JK_METHOD status_worker_factory(jk_worker_t **w, + const char *name, jk_logger_t *l); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* JK_STATUS_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_status.lo b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_status.lo new file mode 100644 index 00000000..0185386d --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_status.lo @@ -0,0 +1,12 @@ +# jk_status.lo - a libtool object file +# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/jk_status.o' + +# Name of the non-PIC object. +non_pic_object='jk_status.o' + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_status.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_status.o Binary files differnew file mode 100644 index 00000000..3db458bf --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_status.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_types.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_types.h new file mode 100644 index 00000000..e8029377 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_types.h @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Platform specific, auto-detected types. * + * Author: Rainer Jung <rjung@apache.org> * + * Version: $Revision: 915199 $ * + ***************************************************************************/ + +#ifndef JK_TYPES_H +#define JK_TYPES_H + +/* GENERATED FILE WARNING! DO NOT EDIT jk_types.h + * + * You must modify jk_types.h.in instead. + * + */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* jk_uint32_t defines a four byte word */ +typedef unsigned int jk_uint32_t; + +/* And JK_UINT32_T_FMT */ +#define JK_UINT32_T_FMT "u" + +/* And JK_UINT32_T_HEX_FMT */ +#define JK_UINT32_T_HEX_FMT "x" + +/* jk_uint64_t defines a eight byte word */ +typedef unsigned long jk_uint64_t; + +/* And JK_UINT64_T_FMT */ +#define JK_UINT64_T_FMT "lu" + +/* And JK_UINT64_T_HEX_FMT */ +#define JK_UINT64_T_HEX_FMT "lx" + +/* And JK_PID_T_FMT */ +#define JK_PID_T_FMT "d" + +/* jk_pthread_t defines a eight byte word */ +typedef unsigned long jk_pthread_t; + +/* And JK_PTHREAD_T_FMT */ +#define JK_PTHREAD_T_FMT "lu" + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* JK_TYPES_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_types.h.in b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_types.h.in new file mode 100644 index 00000000..6301b240 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_types.h.in @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Platform specific, auto-detected types. * + * Author: Rainer Jung <rjung@apache.org> * + * Version: $Revision: 915199 $ * + ***************************************************************************/ + +#ifndef JK_TYPES_H +#define JK_TYPES_H + +/* GENERATED FILE WARNING! DO NOT EDIT jk_types.h + * + * You must modify jk_types.h.in instead. + * + */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* jk_uint32_t defines a four byte word */ +typedef unsigned @int32_value@ jk_uint32_t; + +/* And JK_UINT32_T_FMT */ +@uint32_t_fmt@ + +/* And JK_UINT32_T_HEX_FMT */ +@uint32_t_hex_fmt@ + +/* jk_uint64_t defines a eight byte word */ +typedef unsigned @int64_value@ jk_uint64_t; + +/* And JK_UINT64_T_FMT */ +@uint64_t_fmt@ + +/* And JK_UINT64_T_HEX_FMT */ +@uint64_t_hex_fmt@ + +/* And JK_PID_T_FMT */ +@pid_t_fmt@ + +/* jk_pthread_t defines a eight byte word */ +typedef unsigned @pthread_t_value@ jk_pthread_t; + +/* And JK_PTHREAD_T_FMT */ +@pthread_t_fmt@ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* JK_TYPES_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.c new file mode 100644 index 00000000..d652f769 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.c @@ -0,0 +1,1191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: URI to worker map object. * + * * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Author: Mladen Turk <mturk@apache.org> * + * Version: $Revision: 890739 $ * + ***************************************************************************/ + +#include "jk_pool.h" +#include "jk_util.h" +#include "jk_map.h" +#include "jk_mt.h" +#include "jk_uri_worker_map.h" +#include "jk_worker.h" +#include "jk_lb_worker.h" + +#ifdef WIN32 +#define JK_STRCMP strcasecmp +#define JK_STRNCMP strnicmp +#else +#define JK_STRCMP strcmp +#define JK_STRNCMP strncmp +#endif + +#define JK_UWMAP_EXTENSION_REPLY_TIMEOUT "reply_timeout=" +#define JK_UWMAP_EXTENSION_ACTIVE "active=" +#define JK_UWMAP_EXTENSION_DISABLED "disabled=" +#define JK_UWMAP_EXTENSION_STOPPED "stopped=" +#define JK_UWMAP_EXTENSION_FAIL_ON_STATUS "fail_on_status=" +#define JK_UWMAP_EXTENSION_USE_SRV_ERRORS "use_server_errors=" + +#define IND_SWITCH(x) (((x)+1) % 2) +#define IND_THIS(x) ((x)[uw_map->index]) +#define IND_NEXT(x) ((x)[IND_SWITCH(uw_map->index)]) + +#define STRNULL_FOR_NULL(x) ((x) ? (x) : "(null)") + +static const char *uri_worker_map_source_type[] = { + "unknown", + SOURCE_TYPE_TEXT_WORKERDEF, + SOURCE_TYPE_TEXT_JKMOUNT, + SOURCE_TYPE_TEXT_URIMAP, + SOURCE_TYPE_TEXT_DISCOVER, + NULL +}; + + +/* Return the string representation of the uwr source */ +const char *uri_worker_map_get_source(uri_worker_record_t *uwr, jk_logger_t *l) +{ + return uri_worker_map_source_type[uwr->source_type]; +} + +/* Return the string representation of the uwr match type */ +char *uri_worker_map_get_match(uri_worker_record_t *uwr, char *buf, jk_logger_t *l) +{ + unsigned int match; + + buf[0] = '\0'; + match = uwr->match_type; + + if (match & MATCH_TYPE_DISABLED) + strcat(buf, "Disabled "); +/* deprecated + if (match & MATCH_TYPE_STOPPED) + strcat(buf, "Stopped "); + */ + if (match & MATCH_TYPE_NO_MATCH) + strcat(buf, "Unmount "); + if (match & MATCH_TYPE_EXACT) + strcat(buf, "Exact"); + else if (match & MATCH_TYPE_WILDCHAR_PATH) + strcat(buf, "Wildchar"); +/* deprecated + else if (match & MATCH_TYPE_CONTEXT) + strcat(buf, "Context"); + else if (match & MATCH_TYPE_CONTEXT_PATH) + strcat(buf, "Context Path"); + else if (match & MATCH_TYPE_SUFFIX) + strcat(buf, "Suffix"); + else if (match & MATCH_TYPE_GENERAL_SUFFIX) + return "General Suffix"; + */ + else + strcat(buf, "Unknown"); + return buf; +} + +/* + * Given context uri, count the number of path tokens. + * + * Servlet specification 2.4, SRV.11.1 says + + * The container will recursively try tomatch the longest + * path-prefix. This is done by stepping down the path tree a + * directory at a time, using the / character as a path + * separator. The longest match determines the servlet selected. + * + * The implication seems to be `most uri path elements is most exact'. + * This is a little helper function to count uri tokens, so we can + * keep the worker map sorted with most specific first. + */ +static int worker_count_context_uri_tokens(const char * context) +{ + const char * c = context; + int count = 0; + while (c && *c) { + if ('/' == *c++) + count++; + } + return count; +} + +static int worker_compare(const void *elem1, const void *elem2) +{ + uri_worker_record_t *e1 = *(uri_worker_record_t **)elem1; + uri_worker_record_t *e2 = *(uri_worker_record_t **)elem2; + int e1_tokens = 0; + int e2_tokens = 0; + + e1_tokens = worker_count_context_uri_tokens(e1->context); + e2_tokens = worker_count_context_uri_tokens(e2->context); + + if (e1_tokens != e2_tokens) { + return (e2_tokens - e1_tokens); + } + /* given the same number of URI tokens, use character + * length as a tie breaker + */ + if(e2->context_len != e1->context_len) + return ((int)e2->context_len - (int)e1->context_len); + + return ((int)e2->source_type - (int)e1->source_type); +} + +static void worker_qsort(jk_uri_worker_map_t *uw_map) +{ + + /* Sort remaining args using Quicksort algorithm: */ + qsort((void *)IND_NEXT(uw_map->maps), IND_NEXT(uw_map->size), + sizeof(uri_worker_record_t *), worker_compare ); + +} + +/* Dump the map contents - only call if debug log is active. */ +static void uri_worker_map_dump(jk_uri_worker_map_t *uw_map, + const char *reason, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + if (uw_map) { + int i, off, k; + uri_worker_record_t *uwr = NULL; + char buf[32]; + jk_log(l, JK_LOG_DEBUG, "uri map dump %s: index=%d file='%s' reject_unsafe=%d " + "reload=%d modified=%d checked=%d", + reason, uw_map->index, STRNULL_FOR_NULL(uw_map->fname), uw_map->reject_unsafe, + uw_map->reload, uw_map->modified, uw_map->checked); + for(i=0;i<=1;i++) { + jk_log(l, JK_LOG_DEBUG, "generation %d: size=%d nosize=%d capacity=%d", + i, uw_map->size[i], uw_map->nosize[i], uw_map->capacity[i], uw_map->maps[i]); + } + + off = uw_map->index; + for(i=0;i<=1;i++) { + unsigned int j; + k = (i + off) % 2; + for (j = 0; j < uw_map->size[k]; j++) { + uwr = uw_map->maps[k][j]; + jk_log(l, JK_LOG_DEBUG, "%s (%d) map #%d: uri=%s worker=%s context=%s " + "source=%s type=%s len=%d", + i ? "NEXT" : "THIS", i, j, + STRNULL_FOR_NULL(uwr->uri), STRNULL_FOR_NULL(uwr->worker_name), + STRNULL_FOR_NULL(uwr->context), STRNULL_FOR_NULL(uri_worker_map_get_source(uwr,l)), + STRNULL_FOR_NULL(uri_worker_map_get_match(uwr,buf,l)), uwr->context_len); + } + } + } + JK_TRACE_EXIT(l); +} + + +int uri_worker_map_alloc(jk_uri_worker_map_t **uw_map_p, + jk_map_t *init_data, jk_logger_t *l) +{ + int i; + + JK_TRACE_ENTER(l); + + if (uw_map_p) { + int rc; + jk_uri_worker_map_t *uw_map; + *uw_map_p = (jk_uri_worker_map_t *)calloc(1, sizeof(jk_uri_worker_map_t)); + uw_map = *uw_map_p; + + JK_INIT_CS(&(uw_map->cs), rc); + if (rc == JK_FALSE) { + jk_log(l, JK_LOG_ERROR, + "creating thread lock (errno=%d)", + errno); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + jk_open_pool(&(uw_map->p), + uw_map->buf, sizeof(jk_pool_atom_t) * BIG_POOL_SIZE); + for(i=0;i<=1;i++) { + jk_open_pool(&(uw_map->p_dyn[i]), + uw_map->buf_dyn[i], sizeof(jk_pool_atom_t) * BIG_POOL_SIZE); + uw_map->size[i] = 0; + uw_map->nosize[i] = 0; + uw_map->capacity[i] = 0; + uw_map->maps[i] = NULL; + } + uw_map->index = 0; + uw_map->fname = NULL; + uw_map->reject_unsafe = 0; + uw_map->reload = JK_URIMAP_DEF_RELOAD; + uw_map->modified = 0; + uw_map->checked = 0; + + if (init_data) + rc = uri_worker_map_open(uw_map, init_data, l); + JK_TRACE_EXIT(l); + return rc; + } + + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + + return JK_FALSE; +} + +static int uri_worker_map_close(jk_uri_worker_map_t *uw_map, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + if (uw_map) { + int i; + JK_DELETE_CS(&(uw_map->cs), i); + jk_close_pool(&uw_map->p_dyn[0]); + jk_close_pool(&uw_map->p_dyn[1]); + jk_close_pool(&uw_map->p); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +int uri_worker_map_free(jk_uri_worker_map_t **uw_map, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + if (uw_map && *uw_map) { + uri_worker_map_close(*uw_map, l); + free(*uw_map); + *uw_map = NULL; + JK_TRACE_EXIT(l); + return JK_TRUE; + } + else + JK_LOG_NULL_PARAMS(l); + + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +/* + * Ensure there will be memory in context info to store Context Bases + */ + +#define UW_INC_SIZE 4 /* 4 URI->WORKER STEP */ + +static int uri_worker_map_realloc(jk_uri_worker_map_t *uw_map) +{ + if (IND_NEXT(uw_map->size) == IND_NEXT(uw_map->capacity)) { + uri_worker_record_t **uwr; + int capacity = IND_NEXT(uw_map->capacity) + UW_INC_SIZE; + + uwr = + (uri_worker_record_t **) jk_pool_alloc(&IND_NEXT(uw_map->p_dyn), + sizeof(uri_worker_record_t + *) * capacity); + + if (!uwr) + return JK_FALSE; + + if (IND_NEXT(uw_map->capacity) && IND_NEXT(uw_map->maps)) + memcpy(uwr, IND_NEXT(uw_map->maps), + sizeof(uri_worker_record_t *) * IND_NEXT(uw_map->capacity)); + + IND_NEXT(uw_map->maps) = uwr; + IND_NEXT(uw_map->capacity) = capacity; + } + + return JK_TRUE; +} + + +/* + * Delete all entries of a given source type + */ + +static int uri_worker_map_clear(jk_uri_worker_map_t *uw_map, + jk_logger_t *l) +{ + uri_worker_record_t *uwr = NULL; + unsigned int i; + unsigned int new_size = 0; + unsigned int new_nosize = 0; + + JK_TRACE_ENTER(l); + + IND_NEXT(uw_map->maps) = + (uri_worker_record_t **) jk_pool_alloc(&(IND_NEXT(uw_map->p_dyn)), + sizeof(uri_worker_record_t + *) * IND_THIS(uw_map->size)); + IND_NEXT(uw_map->capacity) = IND_THIS(uw_map->size); + IND_NEXT(uw_map->size) = 0; + IND_NEXT(uw_map->nosize) = 0; + for (i = 0; i < IND_THIS(uw_map->size); i++) { + uwr = IND_THIS(uw_map->maps)[i]; + if (uwr->source_type == SOURCE_TYPE_URIMAP) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "deleting map rule '%s=%s' source '%s'", + uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr, l)); + } + else { + IND_NEXT(uw_map->maps)[new_size] = uwr; + new_size++; + if (uwr->match_type & MATCH_TYPE_NO_MATCH) + new_nosize++; + } + } + IND_NEXT(uw_map->size) = new_size; + IND_NEXT(uw_map->nosize) = new_nosize; + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +static void extract_activation(jk_uri_worker_map_t *uw_map, + uri_worker_record_t *uwr, + lb_worker_t *lb, + int *activations, + char *workers, + int activation, + jk_logger_t *l) +{ + unsigned int i; + jk_pool_t *p; + char *worker; +#ifdef _MT_CODE_PTHREAD + char *lasts; +#endif + + JK_TRACE_ENTER(l); + + if (uwr->source_type == SOURCE_TYPE_URIMAP) + p = &IND_NEXT(uw_map->p_dyn); + else + p = &uw_map->p; + worker = jk_pool_strdup(p, workers); + +#ifdef _MT_CODE_PTHREAD + for (worker = strtok_r(worker, ", ", &lasts); + worker; worker = strtok_r(NULL, ", ", &lasts)) { +#else + for (worker = strtok(worker, ", "); worker; worker = strtok(NULL, ", ")) { +#endif + for (i=0; i<lb->num_of_workers; i++) { + if (!strcmp(worker, lb->lb_workers[i].name)) { + if (activations[i] != JK_LB_ACTIVATION_UNSET) + jk_log(l, JK_LOG_WARNING, + "inconsistent activation overwrite for member %s " + "of load balancer %s: '%s' replaced by '%s'", + worker, lb->name, + jk_lb_get_activation_direct(activations[i], l), + jk_lb_get_activation_direct(activation, l)); + activations[i] = activation; + break; + } + } + if (i >= lb->num_of_workers) + jk_log(l, JK_LOG_WARNING, + "could not find member %s of load balancer %s", + worker, lb->name); + } + + JK_TRACE_EXIT(l); + +} + +static void extract_fail_on_status(jk_uri_worker_map_t *uw_map, + uri_worker_record_t *uwr, + jk_logger_t *l) +{ + unsigned int i; + int j; + int cnt = 1; + jk_pool_t *p; + char *status; +#ifdef _MT_CODE_PTHREAD + char *lasts; +#endif + + JK_TRACE_ENTER(l); + + for (i=0; i<strlen(uwr->extensions.fail_on_status_str); i++) { + if (uwr->extensions.fail_on_status_str[i] == ',' || + uwr->extensions.fail_on_status_str[i] == ' ') + cnt++; + } + uwr->extensions.fail_on_status_size = cnt; + + if (uwr->source_type == SOURCE_TYPE_URIMAP) + p = &IND_NEXT(uw_map->p_dyn); + else + p = &uw_map->p; + status = jk_pool_strdup(p, uwr->extensions.fail_on_status_str); + uwr->extensions.fail_on_status = (int *)jk_pool_alloc(p, + uwr->extensions.fail_on_status_size * sizeof(int)); + if (!uwr->extensions.fail_on_status) { + jk_log(l, JK_LOG_ERROR, + "can't alloc extensions fail_on_status list"); + JK_TRACE_EXIT(l); + return; + } else if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Allocated fail_on_status array of size %d for worker %s", + uwr->extensions.fail_on_status_size, uwr->worker_name); + + + for (j=0; j<uwr->extensions.fail_on_status_size; j++) { + uwr->extensions.fail_on_status[j] = 0; + } + + cnt = 0; +#ifdef _MT_CODE_PTHREAD + for (status = strtok_r(status, ", ", &lasts); + status; status = strtok_r(NULL, ", ", &lasts)) { +#else + for (status = strtok(status, ", "); status; status = strtok(NULL, ", ")) { +#endif + uwr->extensions.fail_on_status[cnt] = atoi(status); + cnt++; + } + + JK_TRACE_EXIT(l); + +} + +void uri_worker_map_switch(jk_uri_worker_map_t *uw_map, jk_logger_t *l) +{ + int new_index; + + JK_TRACE_ENTER(l); + + if (uw_map) { + new_index = IND_SWITCH(uw_map->index); + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Switching uri worker map from index %d to index %d", + uw_map->index, new_index); + uw_map->index = new_index; + jk_reset_pool(&(IND_NEXT(uw_map->p_dyn))); + } + + JK_TRACE_EXIT(l); + +} + +void uri_worker_map_ext(jk_uri_worker_map_t *uw_map, jk_logger_t *l) +{ + unsigned int i; + + JK_TRACE_ENTER(l); + + for (i = 0; i < IND_NEXT(uw_map->size); i++) { + uri_worker_record_t *uwr = IND_NEXT(uw_map->maps)[i]; + jk_worker_t *jw; + if(uwr->match_type & MATCH_TYPE_NO_MATCH) + continue; + jw = wc_get_worker_for_name(uwr->worker_name, l); + if(!jw) { + jk_log(l, JK_LOG_ERROR, + "Could not find worker with name '%s' in uri map post processing.", + uwr->worker_name); + continue; + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Checking extension for worker %d: %s of type %s (%d)", + i, uwr->worker_name, wc_get_name_for_type(jw->type,l), jw->type); + + if (jw->type == JK_LB_WORKER_TYPE && + (uwr->extensions.active || uwr->extensions.disabled || uwr->extensions.stopped)) { + int j; + lb_worker_t *lb = (lb_worker_t *)jw->worker_private; + jk_pool_t *p; + if (!uwr->extensions.activation) { + uwr->extensions.activation_size = lb->num_of_workers; + if (uwr->source_type == SOURCE_TYPE_URIMAP) + p = &IND_NEXT(uw_map->p_dyn); + else + p = &uw_map->p; + uwr->extensions.activation = (int *)jk_pool_alloc(p, + uwr->extensions.activation_size * sizeof(int)); + if (!uwr->extensions.activation) { + jk_log(l, JK_LOG_ERROR, + "can't alloc extensions activation list"); + continue; + } else if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Allocated activations array of size %d for lb worker %s", + uwr->extensions.activation_size, uwr->worker_name); + for (j=0; j<uwr->extensions.activation_size; j++) { + uwr->extensions.activation[j] = JK_LB_ACTIVATION_UNSET; + } + } + if (uwr->extensions.active) + extract_activation(uw_map, uwr, lb, uwr->extensions.activation, + uwr->extensions.active, JK_LB_ACTIVATION_ACTIVE, l); + if (uwr->extensions.disabled) + extract_activation(uw_map, uwr, lb, uwr->extensions.activation, + uwr->extensions.disabled, JK_LB_ACTIVATION_DISABLED, l); + if (uwr->extensions.stopped) + extract_activation(uw_map, uwr, lb, uwr->extensions.activation, + uwr->extensions.stopped, JK_LB_ACTIVATION_STOPPED, l); + } + else if (uwr->extensions.active) { + jk_log(l, JK_LOG_WARNING, + "Worker %s is not of type lb, activation extension " + JK_UWMAP_EXTENSION_ACTIVE " for %s ignored", + uwr->worker_name, uwr->extensions.active); + } + else if (uwr->extensions.disabled) { + jk_log(l, JK_LOG_WARNING, + "Worker %s is not of type lb, activation extension " + JK_UWMAP_EXTENSION_DISABLED " for %s ignored", + uwr->worker_name, uwr->extensions.disabled); + } + else if (uwr->extensions.stopped) { + jk_log(l, JK_LOG_WARNING, + "Worker %s is not of type lb, activation extension " + JK_UWMAP_EXTENSION_STOPPED " for %s ignored", + uwr->worker_name, uwr->extensions.stopped); + } + if (uwr->extensions.fail_on_status_str) { + extract_fail_on_status(uw_map, uwr, l); + } + } + if (JK_IS_DEBUG_LEVEL(l)) + uri_worker_map_dump(uw_map, "after extension stripping", l); + + JK_TRACE_EXIT(l); + return; + +} + +/* Add new entry to NEXT generation */ +int uri_worker_map_add(jk_uri_worker_map_t *uw_map, + const char *puri, const char *worker, + unsigned int source_type, jk_logger_t *l) +{ + uri_worker_record_t *uwr = NULL; + char *uri; + jk_pool_t *p; + unsigned int match_type = 0; + + JK_TRACE_ENTER(l); + + if (*puri == '-') { + /* Disable urimap. + * This way you can disable already mounted + * context. + */ + match_type = MATCH_TYPE_DISABLED; + puri++; + } + if (*puri == '!') { + match_type |= MATCH_TYPE_NO_MATCH; + puri++; + } + + if (uri_worker_map_realloc(uw_map) == JK_FALSE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + if (source_type == SOURCE_TYPE_URIMAP) + p = &IND_NEXT(uw_map->p_dyn); + else + p = &uw_map->p; + + uwr = (uri_worker_record_t *)jk_pool_alloc(p, sizeof(uri_worker_record_t)); + if (!uwr) { + jk_log(l, JK_LOG_ERROR, + "can't alloc map entry"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + uri = jk_pool_strdup(p, puri); + if (!uri || !worker) { + jk_log(l, JK_LOG_ERROR, + "can't alloc uri/worker strings"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (*uri == '/') { + char *w; + char *param; +#ifdef _MT_CODE_PTHREAD + char *lasts = NULL; +#endif + + w = jk_pool_strdup(p, worker); + uwr->extensions.reply_timeout = -1; + uwr->extensions.active = NULL; + uwr->extensions.disabled = NULL; + uwr->extensions.stopped = NULL; + uwr->extensions.activation_size = 0; + uwr->extensions.activation = NULL; + uwr->extensions.fail_on_status_size = 0; + uwr->extensions.fail_on_status = NULL; + uwr->extensions.fail_on_status_str = NULL; + uwr->extensions.use_server_error_pages = 0; + +#ifdef _MT_CODE_PTHREAD + param = strtok_r(w, ";", &lasts); +#else + param = strtok(w, ";"); +#endif + if (param) { +#ifdef _MT_CODE_PTHREAD + for (param = strtok_r(NULL, ";", &lasts); param; param = strtok_r(NULL, ";", &lasts)) { +#else + for (param = strtok(NULL, ";"); param; param = strtok(NULL, ";")) { +#endif + if (!strncmp(param, JK_UWMAP_EXTENSION_REPLY_TIMEOUT, strlen(JK_UWMAP_EXTENSION_REPLY_TIMEOUT))) { + uwr->extensions.reply_timeout = atoi(param + strlen(JK_UWMAP_EXTENSION_REPLY_TIMEOUT)); + } + else if (!strncmp(param, JK_UWMAP_EXTENSION_USE_SRV_ERRORS, strlen(JK_UWMAP_EXTENSION_USE_SRV_ERRORS))) { + uwr->extensions.use_server_error_pages = atoi(param + strlen(JK_UWMAP_EXTENSION_USE_SRV_ERRORS)); + } + else if (!strncmp(param, JK_UWMAP_EXTENSION_ACTIVE, strlen(JK_UWMAP_EXTENSION_ACTIVE))) { + if (uwr->extensions.active) + jk_log(l, JK_LOG_WARNING, + "extension '%s' in uri worker map only allowed once", + JK_UWMAP_EXTENSION_ACTIVE); + else + uwr->extensions.active = param + strlen(JK_UWMAP_EXTENSION_ACTIVE); + } + else if (!strncmp(param, JK_UWMAP_EXTENSION_DISABLED, strlen(JK_UWMAP_EXTENSION_DISABLED))) { + if (uwr->extensions.disabled) + jk_log(l, JK_LOG_WARNING, + "extension '%s' in uri worker map only allowed once", + JK_UWMAP_EXTENSION_DISABLED); + else + uwr->extensions.disabled = param + strlen(JK_UWMAP_EXTENSION_DISABLED); + } + else if (!strncmp(param, JK_UWMAP_EXTENSION_STOPPED, strlen(JK_UWMAP_EXTENSION_STOPPED))) { + if (uwr->extensions.stopped) + jk_log(l, JK_LOG_WARNING, + "extension '%s' in uri worker map only allowed once", + JK_UWMAP_EXTENSION_STOPPED); + else + uwr->extensions.stopped = param + strlen(JK_UWMAP_EXTENSION_STOPPED); + } + else if (!strncmp(param, JK_UWMAP_EXTENSION_FAIL_ON_STATUS, strlen(JK_UWMAP_EXTENSION_FAIL_ON_STATUS))) { + if (uwr->extensions.fail_on_status_str) + jk_log(l, JK_LOG_WARNING, + "extension '%s' in uri worker map only allowed once", + JK_UWMAP_EXTENSION_FAIL_ON_STATUS); + else + uwr->extensions.fail_on_status_str = param + strlen(JK_UWMAP_EXTENSION_FAIL_ON_STATUS); + } + else { + jk_log(l, JK_LOG_WARNING, + "unknown extension '%s' in uri worker map", + param); + } + } + } + + uwr->source_type = source_type; + uwr->worker_name = w; + uwr->uri = uri; + uwr->context = uri; + uwr->context_len = strlen(uwr->context); + if (strchr(uri, '*') || + strchr(uri, '?')) { + /* Something like + * /context/ * /user/ * + * /context/ *.suffix + */ + match_type |= MATCH_TYPE_WILDCHAR_PATH; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "wildchar rule '%s=%s' source '%s' was added", + uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr, l)); + + } + else { + /* Something like: JkMount /login/j_security_check ajp13 */ + match_type |= MATCH_TYPE_EXACT; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "exact rule '%s=%s' source '%s' was added", + uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr, l)); + } + } + else { + /* + * JFC: please check... + * Not sure what to do, but I try to prevent problems. + * I have fixed jk_mount_context() in apaches/mod_jk.c so we should + * not arrive here when using Apache. + */ + jk_log(l, JK_LOG_ERROR, + "invalid context '%s': does not begin with '/'", + uri); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + uwr->match_type = match_type; + IND_NEXT(uw_map->maps)[IND_NEXT(uw_map->size)] = uwr; + IND_NEXT(uw_map->size)++; + if (match_type & MATCH_TYPE_NO_MATCH) { + /* If we split the mappings this one will be calculated */ + IND_NEXT(uw_map->nosize)++; + } + worker_qsort(uw_map); + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +int uri_worker_map_open(jk_uri_worker_map_t *uw_map, + jk_map_t *init_data, jk_logger_t *l) +{ + int rc = JK_TRUE; + + JK_TRACE_ENTER(l); + + if (uw_map) { + int sz = jk_map_size(init_data); + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "rule map size is %d", + sz); + + if (sz > 0) { + int i; + for (i = 0; i < sz; i++) { + const char *u = jk_map_name_at(init_data, i); + const char *w = jk_map_value_at(init_data, i); + /* Multiple mappings like : + * /servlets-examples|/ * + * will create two mappings: + * /servlets-examples + * and: + * /servlets-examples/ * + */ + if (strchr(u, '|')) { + char *s, *r = strdup(u); + s = strchr(r, '|'); + *(s++) = '\0'; + /* Add first mapping */ + if (!uri_worker_map_add(uw_map, r, w, SOURCE_TYPE_JKMOUNT, l)) { + jk_log(l, JK_LOG_ERROR, + "invalid mapping rule %s->%s", r, w); + rc = JK_FALSE; + } + for (; *s; s++) + *(s - 1) = *s; + *(s - 1) = '\0'; + /* add second mapping */ + if (!uri_worker_map_add(uw_map, r, w, SOURCE_TYPE_JKMOUNT, l)) { + jk_log(l, JK_LOG_ERROR, + "invalid mapping rule %s->%s", r, w); + rc = JK_FALSE; + } + free(r); + } + else if (!uri_worker_map_add(uw_map, u, w, SOURCE_TYPE_JKMOUNT, l)) { + jk_log(l, JK_LOG_ERROR, + "invalid mapping rule %s->%s", + u, w); + rc = JK_FALSE; + break; + } + if (rc == JK_FALSE) + break; + } + } + + if (rc == JK_FALSE) { + jk_log(l, JK_LOG_ERROR, + "there was an error, freeing buf"); + jk_close_pool(&uw_map->p_dyn[0]); + jk_close_pool(&uw_map->p_dyn[1]); + jk_close_pool(&uw_map->p); + } + else if (JK_IS_DEBUG_LEVEL(l)) + uri_worker_map_dump(uw_map, "after map open", l); + } + + JK_TRACE_EXIT(l); + return rc; +} + +static int find_match(jk_uri_worker_map_t *uw_map, + const char *url, jk_logger_t *l) +{ + unsigned int i; + + JK_TRACE_ENTER(l); + + for (i = 0; i < IND_THIS(uw_map->size); i++) { + uri_worker_record_t *uwr = IND_THIS(uw_map->maps)[i]; + + /* Check for match types */ + if ((uwr->match_type & MATCH_TYPE_DISABLED) || + (uwr->match_type & MATCH_TYPE_NO_MATCH)) + continue; + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, "Attempting to map context URI '%s=%s' source '%s'", + uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr, l)); + + if (uwr->match_type & MATCH_TYPE_WILDCHAR_PATH) { + /* Map is already sorted by context_len */ + if (jk_wildchar_match(url, uwr->context, +#ifdef WIN32 + 0 +#else + 0 +#endif + ) == 0) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Found a wildchar match '%s=%s'", + uwr->context, uwr->worker_name); + JK_TRACE_EXIT(l); + return i; + } + } + else if (JK_STRNCMP(uwr->context, url, uwr->context_len) == 0) { + if (strlen(url) == uwr->context_len) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Found an exact match '%s=%s'", + uwr->context, uwr->worker_name); + JK_TRACE_EXIT(l); + return i; + } + } + } + + JK_TRACE_EXIT(l); + return -1; +} + +static int is_nomatch(jk_uri_worker_map_t *uw_map, + const char *uri, int match, + jk_logger_t *l) +{ + unsigned int i; + const char *worker = IND_THIS(uw_map->maps)[match]->worker_name; + + JK_TRACE_ENTER(l); + + for (i = 0; i < IND_THIS(uw_map->size); i++) { + uri_worker_record_t *uwr = IND_THIS(uw_map->maps)[i]; + + /* Check only nomatch mappings */ + if (!(uwr->match_type & MATCH_TYPE_NO_MATCH) || + (uwr->match_type & MATCH_TYPE_DISABLED)) + continue; + /* Check only matching workers */ + if (strcmp(uwr->worker_name, worker) && + strcmp(uwr->worker_name, "*")) + continue; + if (uwr->match_type & MATCH_TYPE_WILDCHAR_PATH) { + /* Map is already sorted by context_len */ + if (jk_wildchar_match(uri, uwr->context, +#ifdef WIN32 + 0 +#else + 0 +#endif + ) == 0) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Found a wildchar no match '%s=%s' source '%s'", + uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr, l)); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + } + else if (JK_STRNCMP(uwr->context, uri, uwr->context_len) == 0) { + if (strlen(uri) == uwr->context_len) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Found an exact no match '%s=%s' source '%s'", + uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr, l)); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + } + } + + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +const char *map_uri_to_worker_ext(jk_uri_worker_map_t *uw_map, + const char *uri, const char *vhost, + rule_extension_t **extensions, + int *index, + jk_logger_t *l) +{ + unsigned int i; + unsigned int vhost_len; + int reject_unsafe; + int rv = -1; + char url[JK_MAX_URI_LEN+1]; + + JK_TRACE_ENTER(l); + + if (!uw_map || !uri || !extensions) { + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return NULL; + } + *extensions = NULL; + if (index) + *index = -1; + if (*uri != '/') { + jk_log(l, JK_LOG_WARNING, + "Uri %s is invalid. Uri must start with /", uri); + JK_TRACE_EXIT(l); + return NULL; + } + if (uw_map->fname) { + uri_worker_map_update(uw_map, 0, l); + if (!IND_THIS(uw_map->size)) { + jk_log(l, JK_LOG_INFO, + "No worker maps defined for %s.", + uw_map->fname); + JK_TRACE_EXIT(l); + return NULL; + } + } + /* Make the copy of the provided uri and strip + * everything after the first ';' char. + */ + reject_unsafe = uw_map->reject_unsafe; + vhost_len = 0; + /* + * In case we got a vhost, we prepend a slash + * and the vhost to the url in order to enable + * vhost mapping rules especially for IIS. + */ + if (vhost) { + int off = 0; + /* Add leading '/' if necessary */ + if (vhost[0] != '/') { + url[0] = '/'; + off = 1; + } + /* Size including leading slash. */ + vhost_len = strlen(vhost); + if (vhost_len + off >= JK_MAX_URI_LEN) { + vhost_len = 0; + jk_log(l, JK_LOG_WARNING, + "Host prefix %s for URI %s is invalid and will be ignored." + " It must be smaller than %d chars", + vhost, JK_MAX_URI_LEN - off); + } + else { + strncpy(&url[off], vhost, vhost_len + 1); + } + vhost_len += off; + } + for (i = 0; i < strlen(uri); i++) { + if (i == JK_MAX_URI_LEN) { + jk_log(l, JK_LOG_WARNING, + "URI %s is invalid. URI must be smaller than %d chars", + uri, JK_MAX_URI_LEN); + JK_TRACE_EXIT(l); + return NULL; + } + if (uri[i] == ';') + break; + else { + url[i + vhost_len] = uri[i]; + if (reject_unsafe && (uri[i] == '%' || uri[i] == '\\')) { + jk_log(l, JK_LOG_INFO, "Potentially unsafe request url '%s' rejected", uri); + JK_TRACE_EXIT(l); + return NULL; + } + } + } + url[i + vhost_len] = '\0'; + + if (JK_IS_DEBUG_LEVEL(l)) { + char *url_rewrite = strstr(uri, JK_PATH_SESSION_IDENTIFIER); + if (url_rewrite) + jk_log(l, JK_LOG_DEBUG, "Found session identifier '%s' in url '%s'", + url_rewrite, uri); + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, "Attempting to map URI '%s' from %d maps", + url, IND_THIS(uw_map->size)); + rv = find_match(uw_map, url, l); + /* If this doesn't find a match, try without the vhost. */ + if (rv < 0 && vhost_len) { + rv = find_match(uw_map, &url[vhost_len], l); + } + + /* In case we found a match, check for the unmounts. */ + if (rv >= 0 && IND_THIS(uw_map->nosize)) { + /* Again first including vhost. */ + int rc = is_nomatch(uw_map, url, rv, l); + /* If no unmount was find, try without vhost. */ + if (!rc && vhost_len) + rc = is_nomatch(uw_map, &url[vhost_len], rv, l); + if (rc) { + if (JK_IS_DEBUG_LEVEL(l)) { + jk_log(l, JK_LOG_DEBUG, + "Denying match for worker %s by nomatch rule", + IND_THIS(uw_map->maps)[rv]->worker_name); + } + rv = -1; + } + } + + if (rv >= 0) { + *extensions = &(IND_THIS(uw_map->maps)[rv]->extensions); + if (index) + *index = rv; + JK_TRACE_EXIT(l); + return IND_THIS(uw_map->maps)[rv]->worker_name; + } + JK_TRACE_EXIT(l); + return NULL; +} + +rule_extension_t *get_uri_to_worker_ext(jk_uri_worker_map_t *uw_map, + int index) +{ + if (index >= 0) { + return &(IND_THIS(uw_map->maps)[index]->extensions); + } + else { + return NULL; + } +} + +const char *map_uri_to_worker(jk_uri_worker_map_t *uw_map, + const char *uri, const char *vhost, + jk_logger_t *l) +{ + rule_extension_t *ext; + return map_uri_to_worker_ext(uw_map, uri, vhost, &ext, NULL, l); +} + +int uri_worker_map_load(jk_uri_worker_map_t *uw_map, + jk_logger_t *l) +{ + int rc = JK_FALSE; + jk_map_t *map; + + jk_map_alloc(&map); + if (jk_map_read_properties(map, NULL, uw_map->fname, &uw_map->modified, + JK_MAP_HANDLE_NORMAL, l)) { + int i; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Loading urimaps from %s with reload check interval %d seconds", + uw_map->fname, uw_map->reload); + uri_worker_map_clear(uw_map, l); + for (i = 0; i < jk_map_size(map); i++) { + const char *u = jk_map_name_at(map, i); + const char *w = jk_map_value_at(map, i); + /* Multiple mappings like : + * /servlets-examples|/ * + * will create two mappings: + * /servlets-examples + * and: + * /servlets-examples/ * + */ + if (strchr(u, '|')) { + char *s, *r = strdup(u); + s = strchr(r, '|'); + *(s++) = '\0'; + /* Add first mapping */ + if (!uri_worker_map_add(uw_map, r, w, SOURCE_TYPE_URIMAP, l)) { + jk_log(l, JK_LOG_ERROR, + "invalid mapping rule %s->%s", r, w); + } + for (; *s; s++) + *(s - 1) = *s; + *(s - 1) = '\0'; + /* add second mapping */ + if (!uri_worker_map_add(uw_map, r, w, SOURCE_TYPE_URIMAP, l)) { + jk_log(l, JK_LOG_ERROR, + "invalid mapping rule %s->%s", r, w); + } + free(r); + } + else if (!uri_worker_map_add(uw_map, u, w, SOURCE_TYPE_URIMAP, l)) { + jk_log(l, JK_LOG_ERROR, + "invalid mapping rule %s->%s", + u, w); + } + } + uw_map->checked = time(NULL); + if (JK_IS_DEBUG_LEVEL(l)) + uri_worker_map_dump(uw_map, "after file load", l); + rc = JK_TRUE; + } + jk_map_free(&map); + return rc; +} + +int uri_worker_map_update(jk_uri_worker_map_t *uw_map, + int force, jk_logger_t *l) +{ + int rc = JK_TRUE; + time_t now = time(NULL); + + if (force || (uw_map->reload > 0 && difftime(now, uw_map->checked) > + uw_map->reload)) { + struct stat statbuf; + uw_map->checked = now; + if ((rc = jk_stat(uw_map->fname, &statbuf)) == -1) { + jk_log(l, JK_LOG_ERROR, + "Unable to stat the %s (errno=%d)", + uw_map->fname, errno); + return JK_FALSE; + } + if (statbuf.st_mtime == uw_map->modified) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "File %s is not modified", + uw_map->fname); + return JK_TRUE; + } + JK_ENTER_CS(&(uw_map->cs), rc); + /* Check if some other thread updated status */ + if (statbuf.st_mtime == uw_map->modified) { + JK_LEAVE_CS(&(uw_map->cs), rc); + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "File %s is not modified", + uw_map->fname); + return JK_TRUE; + } + rc = uri_worker_map_load(uw_map, l); + uri_worker_map_ext(uw_map, l); + uri_worker_map_switch(uw_map, l); + JK_LEAVE_CS(&(uw_map->cs), rc); + jk_log(l, JK_LOG_INFO, + "Reloaded urimaps from %s", uw_map->fname); + } + return JK_TRUE; +} diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.h new file mode 100644 index 00000000..30091dc4 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.h @@ -0,0 +1,208 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: URI to worker mapper header file * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Version: $Revision: 705283 $ * + ***************************************************************************/ + +#ifndef JK_URI_WORKER_MAP_H +#define JK_URI_WORKER_MAP_H + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#include "jk_global.h" +#include "jk_map.h" +#include "jk_logger.h" +#include "jk_mt.h" + +#define MATCH_TYPE_EXACT 0x0001 +/* deprecated +#define MATCH_TYPE_CONTEXT 0x0002 + */ +/* match all context path URIs with a path component suffix */ +/* deprecated +#define MATCH_TYPE_CONTEXT_PATH 0x0004 + */ +/* deprecated +#define MATCH_TYPE_SUFFIX 0x0010 + */ +/* match all URIs of the form *ext */ +/* deprecated +#define MATCH_TYPE_GENERAL_SUFFIX 0x0020 + */ +/* match multiple wild characters (*) and (?) */ +#define MATCH_TYPE_WILDCHAR_PATH 0x0040 +#define MATCH_TYPE_NO_MATCH 0x1000 +#define MATCH_TYPE_DISABLED 0x2000 +/* deprecated +#define MATCH_TYPE_STOPPED 0x4000 + */ + +#define SOURCE_TYPE_WORKERDEF 0x0001 +#define SOURCE_TYPE_JKMOUNT 0x0002 +#define SOURCE_TYPE_URIMAP 0x0003 +#define SOURCE_TYPE_DISCOVER 0x0004 +#define SOURCE_TYPE_TEXT_WORKERDEF ("worker definition") +#define SOURCE_TYPE_TEXT_JKMOUNT ("JkMount") +#define SOURCE_TYPE_TEXT_URIMAP ("uriworkermap") +#define SOURCE_TYPE_TEXT_DISCOVER ("ajp14") + +#define JK_MAX_URI_LEN 4095 + +struct rule_extension +{ + /* reply_timeout overwrite */ + int reply_timeout; + /* activation state overwrites for load balancers */ + /* Number of elements in the array activations. */ + int activation_size; + /* Dynamically allocated array with one entry per lb member. */ + int *activation; + /* Temporary storage for the original extension strings. */ + char *active; + char *disabled; + char *stopped; + /* fail_on_status overwrites */ + /* Number of elements in the array fail_on_status. */ + int fail_on_status_size; + /* Dynamically allocated array with one entry per status. */ + int *fail_on_status; + /* Temporary storage for the original extension strings. */ + char *fail_on_status_str; + /* Use server error pages for responses >= 400. */ + int use_server_error_pages; +}; +typedef struct rule_extension rule_extension_t; + +struct uri_worker_record +{ + /* Original uri for logging */ + char *uri; + + /* Name of worker mapped */ + const char *worker_name; + + /* Base context */ + const char *context; + + /* Match type */ + unsigned int match_type; + + /* Definition source type */ + unsigned int source_type; + + /* char length of the context */ + size_t context_len; + + /* extended mapping properties */ + rule_extension_t extensions; +}; +typedef struct uri_worker_record uri_worker_record_t; + +struct jk_uri_worker_map +{ + /* Memory Pool */ + jk_pool_t p; + jk_pool_atom_t buf[BIG_POOL_SIZE]; + + /* Index 0 or 1, which map instance do we use */ + /* Needed to make map reload more atomically */ + int index; + + /* Memory Pool - cleared when doing reload */ + /* Use this pool to allocate objects, that are deleted */ + /* when the map gets dynamically reloaded from uriworkermap.properties. */ + jk_pool_t p_dyn[2]; + jk_pool_atom_t buf_dyn[2][BIG_POOL_SIZE]; + + /* map URI->WORKER */ + uri_worker_record_t **maps[2]; + + /* Map Number */ + unsigned int size[2]; + + /* Map Capacity */ + unsigned int capacity[2]; + + /* NoMap Number */ + unsigned int nosize[2]; + + /* Dynamic config support */ + + JK_CRIT_SEC cs; + /* should we forward potentially unsafe URLs */ + int reject_unsafe; + /* uriworkermap filename */ + const char *fname; + /* uriworkermap reload check interval */ + int reload; + /* Last modified time */ + time_t modified; + /* Last checked time */ + time_t checked; +}; +typedef struct jk_uri_worker_map jk_uri_worker_map_t; + +const char *uri_worker_map_get_source(uri_worker_record_t *uwr, jk_logger_t *l); + +char *uri_worker_map_get_match(uri_worker_record_t *uwr, char *buf, jk_logger_t *l); + +int uri_worker_map_alloc(jk_uri_worker_map_t **uw_map, + jk_map_t *init_data, jk_logger_t *l); + +int uri_worker_map_free(jk_uri_worker_map_t **uw_map, jk_logger_t *l); + +int uri_worker_map_open(jk_uri_worker_map_t *uw_map, + jk_map_t *init_data, jk_logger_t *l); + +void uri_worker_map_switch(jk_uri_worker_map_t *uw_map, jk_logger_t *l); + +void uri_worker_map_ext(jk_uri_worker_map_t *uw_map, jk_logger_t *l); + +int uri_worker_map_add(jk_uri_worker_map_t *uw_map, + const char *puri, const char *worker, + unsigned int source_type, jk_logger_t *l); + +const char *map_uri_to_worker(jk_uri_worker_map_t *uw_map, + const char *uri, const char *vhost, + jk_logger_t *l); + +const char *map_uri_to_worker_ext(jk_uri_worker_map_t *uw_map, + const char *uri, const char *vhost, + rule_extension_t **extensions, + int *index, + jk_logger_t *l); + +rule_extension_t *get_uri_to_worker_ext(jk_uri_worker_map_t *uw_map, + int index); + +int uri_worker_map_load(jk_uri_worker_map_t *uw_map, + jk_logger_t *l); + +int uri_worker_map_update(jk_uri_worker_map_t *uw_map, + int force, jk_logger_t *l); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* JK_URI_WORKER_MAP_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.lo b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.lo new file mode 100644 index 00000000..3d3b423a --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.lo @@ -0,0 +1,12 @@ +# jk_uri_worker_map.lo - a libtool object file +# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/jk_uri_worker_map.o' + +# Name of the non-PIC object. +non_pic_object='jk_uri_worker_map.o' + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.o Binary files differnew file mode 100644 index 00000000..c402e1fc --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_url.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_url.c new file mode 100644 index 00000000..884f01d0 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_url.c @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: URL manipulation subroutines. (ported from mod_proxy). * + * Version: $Revision: 531816 $ * + ***************************************************************************/ + +#include "jk_global.h" +#include "jk_url.h" + +#ifdef HAVE_APR +#define JK_ISXDIGIT(x) apr_isxdigit((x)) +#define JK_ISDIGIT(x) apr_isdigit((x)) +#define JK_ISUPPER(x) apr_isupper((x)) +#define JK_ISALNUM(x) apr_isalnum((x)) +#else +#define JK_ISXDIGIT(x) isxdigit((int)(unsigned char)((x))) +#define JK_ISDIGIT(x) isdigit((int)(unsigned char)((x))) +#define JK_ISUPPER(x) isupper((int)(unsigned char)((x))) +#define JK_ISALNUM(x) isalnum((int)(unsigned char)((x))) +#endif + +static void jk_c2hex(int ch, char *x) +{ +#if !CHARSET_EBCDIC + int i; + + x[0] = '%'; + i = (ch & 0xF0) >> 4; + if (i >= 10) { + x[1] = ('A' - 10) + i; + } + else { + x[1] = '0' + i; + } + + i = ch & 0x0F; + if (i >= 10) { + x[2] = ('A' - 10) + i; + } + else { + x[2] = '0' + i; + } +#else /*CHARSET_EBCDIC*/ + static const char ntoa[] = { "0123456789ABCDEF" }; + char buf[1]; + + ch &= 0xFF; + + buf[0] = ch; + jk_xlate_to_ascii(buf, 1); + + x[0] = '%'; + x[1] = ntoa[(buf[0] >> 4) & 0x0F]; + x[2] = ntoa[buf[0] & 0x0F]; + x[3] = '\0'; +#endif /*CHARSET_EBCDIC*/ +} + +/* + * Convert a URL-encoded string to canonical form. + * It encodes those which must be encoded, and does not touch + * those which must not be touched. + * String x must be '\0'-terminated. + * String y must be pre-allocated with len maxlen + * (including the terminating '\0'). + */ +int jk_canonenc(const char *x, char *y, int maxlen) +{ + int i, j; + int ch = x[0]; + char *allowed; /* characters which should not be encoded */ + char *reserved; /* characters which much not be en/de-coded */ + +/* + * N.B. in addition to :@&=, this allows ';' in an http path + * and '?' in an ftp path -- this may be revised + */ + allowed = "~$-_.+!*'(),;:@&="; + reserved = "/"; + + for (i = 0, j = 0; ch != '\0' && j < maxlen; i++, j++, ch=x[i]) { +/* always handle '/' first */ + if (strchr(reserved, ch)) { + y[j] = ch; + continue; + } +/* recode it, if necessary */ + if (!JK_ISALNUM(ch) && !strchr(allowed, ch)) { + if (j+2<maxlen) { + jk_c2hex(ch, &y[j]); + j += 2; + } + else { + return JK_FALSE; + } + } + else { + y[j] = ch; + } + } + if (j<maxlen) { + y[j] = '\0'; + return JK_TRUE; + } + else { + return JK_FALSE; + } +} diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_url.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_url.h new file mode 100644 index 00000000..a7f332e2 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_url.h @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: URL manipulation subroutines header file. (mod_proxy) * + * Version: $Revision: 500534 $ * + ***************************************************************************/ +#ifndef _JK_URL_H +#define _JK_URL_H + +#include "jk_global.h" +#include "jk_pool.h" +#include "jk_util.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* + * Do a canonical encoding of the url x. + * String y contains the result and is pre-allocated + * for at least maxlen bytes, including a '\0' terminator. + */ +int jk_canonenc(const char *x, char *y, int maxlen); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _JK_URL_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_url.lo b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_url.lo new file mode 100644 index 00000000..8b3fcdd8 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_url.lo @@ -0,0 +1,12 @@ +# jk_url.lo - a libtool object file +# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/jk_url.o' + +# Name of the non-PIC object. +non_pic_object='jk_url.o' + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_url.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_url.o Binary files differnew file mode 100644 index 00000000..fd792890 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_url.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_util.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_util.c new file mode 100644 index 00000000..c7a16c46 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_util.c @@ -0,0 +1,2253 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Utility functions (mainly configuration) * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Author: Henri Gomez <hgomez@apache.org> * + * Author: Rainer Jung <rjung@apache.org> * + * Version: $Revision: 1078846 $ * + ***************************************************************************/ + + +#include "jk_util.h" +#include "jk_ajp12_worker.h" +#include "jk_ajp13_worker.h" +#include "jk_ajp14_worker.h" +#include "jk_lb_worker.h" +#include "jk_mt.h" + +#define SYSPROPS_OF_WORKER ("sysprops") +#define STDERR_OF_WORKER ("stderr") +#define STDOUT_OF_WORKER ("stdout") +#define SECRET_OF_WORKER ("secret") +#define MX_OF_WORKER ("mx") +#define MS_OF_WORKER ("ms") +#define CP_OF_WORKER ("class_path") +#define BRIDGE_OF_WORKER ("bridge") +#define JVM_OF_WORKER ("jvm_lib") +#define LIBPATH_OF_WORKER ("ld_path") +#define CMD_LINE_OF_WORKER ("cmd_line") +#define NATIVE_LIB_OF_WORKER ("native_lib") +#define REFERENCE_OF_WORKER ("reference") +#define HOST_OF_WORKER ("host") +#define PORT_OF_WORKER ("port") +#define TYPE_OF_WORKER ("type") +#define CACHE_OF_WORKER_DEPRECATED ("cachesize") +#define CACHE_OF_WORKER ("connection_pool_size") +#define CACHE_OF_WORKER_MIN ("connection_pool_minsize") +#define CACHE_TIMEOUT_DEPRECATED ("cache_timeout") +#define CACHE_TIMEOUT_OF_WORKER ("connection_pool_timeout") +#define CACHE_ACQUIRE_OF_WORKER ("connection_acquire_timeout") +#define RECOVERY_OPTS_OF_WORKER ("recovery_options") +#define CONNECT_TIMEOUT_OF_WORKER ("connect_timeout") +#define PREPOST_TIMEOUT_OF_WORKER ("prepost_timeout") +#define REPLY_TIMEOUT_OF_WORKER ("reply_timeout") +#define SOCKET_TIMEOUT_OF_WORKER ("socket_timeout") +#define SOCKET_CONNECT_TIMEOUT_OF_WORKER ("socket_connect_timeout") +#define PING_TIMEOUT_OF_WORKER ("ping_timeout") +#define PING_MODE_OF_WORKER ("ping_mode") +#define SOCKET_BUFFER_OF_WORKER ("socket_buffer") +#define SOCKET_KEEPALIVE_OF_WORKER ("socket_keepalive") +#define CONN_PING_INTERVAL_OF_WORKER ("connection_ping_interval") +#define RECYCLE_TIMEOUT_DEPRECATED ("recycle_timeout") +#define LOAD_FACTOR_OF_WORKER ("lbfactor") +#define DISTANCE_OF_WORKER ("distance") +#define BALANCED_WORKERS_DEPRECATED ("balanced_workers") +#define BALANCE_WORKERS ("balance_workers") +#define STICKY_SESSION ("sticky_session") +#define STICKY_SESSION_FORCE ("sticky_session_force") +#define SESSION_COOKIE_OF_WORKER ("session_cookie") +#define SESSION_PATH_OF_WORKER ("session_path") + +#define LOCAL_WORKER_DEPRECATED ("local_worker") +#define LOCAL_WORKER_ONLY_DEPRECATED ("local_worker_only") +#define JVM_ROUTE_OF_WORKER_DEPRECATED ("jvm_route") +#define ROUTE_OF_WORKER ("route") +#define DOMAIN_OF_WORKER ("domain") +#define REDIRECT_OF_WORKER ("redirect") +#define MOUNT_OF_WORKER ("mount") +#define METHOD_OF_WORKER ("method") +#define LOCK_OF_WORKER ("lock") +#define IS_WORKER_DISABLED_DEPRECATED ("disabled") +#define IS_WORKER_STOPPED_DEPRECATED ("stopped") +#define ACTIVATION_OF_WORKER ("activation") +#define WORKER_RECOVER_TIME ("recover_time") +#define WORKER_ERROR_ESCALATION_TIME ("error_escalation_time") +#define MAX_REPLY_TIMEOUTS_OF_WORKER ("max_reply_timeouts") +#define RETRY_INTERVAL_OF_WORKER ("retry_interval") +#define WORKER_MAX_PACKET_SIZE ("max_packet_size") +#define STYLE_SHEET_OF_WORKER ("css") +#define NAMESPACE_OF_WORKER ("ns") +#define XML_NAMESPACE_OF_WORKER ("xmlns") +#define XML_DOCTYPE_OF_WORKER ("doctype") +#define PROP_PREFIX_OF_WORKER ("prefix") + +#define READ_ONLY_OF_WORKER ("read_only") +#define USER_OF_WORKER ("user") +#define USER_CASE_OF_WORKER ("user_case_insensitive") +#define GOOD_RATING_OF_WORKER ("good") +#define BAD_RATING_OF_WORKER ("bad") + +#define DEFAULT_WORKER_TYPE JK_AJP13_WORKER_NAME +#define SECRET_KEY_OF_WORKER ("secretkey") +#define RETRIES_OF_WORKER ("retries") +#define STATUS_FAIL_OF_WORKER ("fail_on_status") + +#define DEFAULT_WORKER JK_AJP13_WORKER_NAME +#define WORKER_LIST_PROPERTY_NAME ("worker.list") +#define LIST_PROPERTY_NAME ("list") +#define WORKER_MAINTAIN_PROPERTY_NAME ("worker.maintain") +#define MAINTAIN_PROPERTY_NAME ("maintain") +#define DEFAULT_MAINTAIN_TIME (60) +#define DEFAULT_LB_FACTOR (1) +#define DEFAULT_DISTANCE (0) + +#define TOMCAT32_BRIDGE_NAME ("tomcat32") +#define TOMCAT33_BRIDGE_NAME ("tomcat33") +#define TOMCAT40_BRIDGE_NAME ("tomcat40") +#define TOMCAT41_BRIDGE_NAME ("tomcat41") +#define TOMCAT50_BRIDGE_NAME ("tomcat5") + +#define HUGE_BUFFER_SIZE (8*1024) + +#define MAKE_WORKER_PARAM(P) \ + strcpy(buf, "worker."); \ + strcat(buf, wname); \ + strcat(buf, "."); \ + strcat(buf, P) + +/* + * define the log format, we're using by default the one from error.log + * + * [Mon Mar 26 19:44:48.123 2001] [jk_uri_worker_map.c (155)]: Into jk_uri_worker_map_t::uri_worker_map_alloc + * log format used by apache in error.log + */ +#define JK_TIME_CONV_MILLI "%Q" +#define JK_TIME_CONV_MICRO "%q" +#define JK_TIME_PATTERN_MILLI "000" +#define JK_TIME_PATTERN_MICRO "000000" +#define JK_TIME_FORMAT_NONE "[%a %b %d %H:%M:%S %Y] " +#define JK_TIME_FORMAT_MILLI "[%a %b %d %H:%M:%S." JK_TIME_CONV_MILLI " %Y] " +#define JK_TIME_FORMAT_MICRO "[%a %b %d %H:%M:%S." JK_TIME_CONV_MICRO " %Y] " +#define JK_TIME_SUBSEC_NONE (0) +#define JK_TIME_SUBSEC_MILLI (1) +#define JK_TIME_SUBSEC_MICRO (2) + +/* Visual C++ Toolkit 2003 support */ +#if defined (_MSC_VER) && (_MSC_VER == 1310) + extern long _ftol(double); /* defined by VC6 C libs */ + extern long _ftol2(double dblSource) { return _ftol(dblSource); } +#endif + +static const char *list_properties[] = { + BALANCE_WORKERS, + MOUNT_OF_WORKER, + USER_OF_WORKER, + GOOD_RATING_OF_WORKER, + BAD_RATING_OF_WORKER, + STATUS_FAIL_OF_WORKER, + "list", + NULL +}; + +static const char *unique_properties[] = { + SECRET_OF_WORKER, + REFERENCE_OF_WORKER, + HOST_OF_WORKER, + PORT_OF_WORKER, + TYPE_OF_WORKER, + CACHE_OF_WORKER_DEPRECATED, + CACHE_OF_WORKER, + CACHE_OF_WORKER_MIN, + CACHE_TIMEOUT_DEPRECATED, + CACHE_TIMEOUT_OF_WORKER, + CACHE_ACQUIRE_OF_WORKER, + RECOVERY_OPTS_OF_WORKER, + CONNECT_TIMEOUT_OF_WORKER, + PREPOST_TIMEOUT_OF_WORKER, + PING_TIMEOUT_OF_WORKER, + PING_MODE_OF_WORKER, + REPLY_TIMEOUT_OF_WORKER, + SOCKET_TIMEOUT_OF_WORKER, + SOCKET_CONNECT_TIMEOUT_OF_WORKER, + SOCKET_BUFFER_OF_WORKER, + SOCKET_KEEPALIVE_OF_WORKER, + CONN_PING_INTERVAL_OF_WORKER, + RECYCLE_TIMEOUT_DEPRECATED, + LOAD_FACTOR_OF_WORKER, + STICKY_SESSION, + STICKY_SESSION_FORCE, + SESSION_COOKIE_OF_WORKER, + SESSION_PATH_OF_WORKER, + LOCAL_WORKER_DEPRECATED, + LOCAL_WORKER_ONLY_DEPRECATED, + JVM_ROUTE_OF_WORKER_DEPRECATED, + ROUTE_OF_WORKER, + DOMAIN_OF_WORKER, + REDIRECT_OF_WORKER, + METHOD_OF_WORKER, + LOCK_OF_WORKER, + IS_WORKER_DISABLED_DEPRECATED, + IS_WORKER_STOPPED_DEPRECATED, + ACTIVATION_OF_WORKER, + WORKER_RECOVER_TIME, + WORKER_ERROR_ESCALATION_TIME, + MAX_REPLY_TIMEOUTS_OF_WORKER, + RETRY_INTERVAL_OF_WORKER, + WORKER_MAX_PACKET_SIZE, + STYLE_SHEET_OF_WORKER, + READ_ONLY_OF_WORKER, + RETRIES_OF_WORKER, + WORKER_MAINTAIN_PROPERTY_NAME, + NAMESPACE_OF_WORKER, + XML_NAMESPACE_OF_WORKER, + XML_DOCTYPE_OF_WORKER, + PROP_PREFIX_OF_WORKER, + USER_CASE_OF_WORKER, + NULL +}; + +static const char *deprecated_properties[] = { + SYSPROPS_OF_WORKER, + STDERR_OF_WORKER, + STDOUT_OF_WORKER, + MX_OF_WORKER, + MS_OF_WORKER, + CP_OF_WORKER, + BRIDGE_OF_WORKER, + JVM_OF_WORKER, + LIBPATH_OF_WORKER, + CMD_LINE_OF_WORKER, + NATIVE_LIB_OF_WORKER, + CACHE_OF_WORKER_DEPRECATED, + CACHE_TIMEOUT_DEPRECATED, + RECYCLE_TIMEOUT_DEPRECATED, + BALANCED_WORKERS_DEPRECATED, + JVM_ROUTE_OF_WORKER_DEPRECATED, + LOCAL_WORKER_DEPRECATED, + LOCAL_WORKER_ONLY_DEPRECATED, + IS_WORKER_DISABLED_DEPRECATED, + IS_WORKER_STOPPED_DEPRECATED, + NULL +}; + +static const char *supported_properties[] = { + SYSPROPS_OF_WORKER, + STDERR_OF_WORKER, + STDOUT_OF_WORKER, + SECRET_OF_WORKER, + MX_OF_WORKER, + MS_OF_WORKER, + CP_OF_WORKER, + BRIDGE_OF_WORKER, + JVM_OF_WORKER, + LIBPATH_OF_WORKER, + CMD_LINE_OF_WORKER, + NATIVE_LIB_OF_WORKER, + REFERENCE_OF_WORKER, + HOST_OF_WORKER, + PORT_OF_WORKER, + TYPE_OF_WORKER, + CACHE_OF_WORKER_DEPRECATED, + CACHE_OF_WORKER, + CACHE_OF_WORKER_MIN, + CACHE_TIMEOUT_DEPRECATED, + CACHE_TIMEOUT_OF_WORKER, + CACHE_ACQUIRE_OF_WORKER, + RECOVERY_OPTS_OF_WORKER, + CONNECT_TIMEOUT_OF_WORKER, + PREPOST_TIMEOUT_OF_WORKER, + PING_TIMEOUT_OF_WORKER, + PING_MODE_OF_WORKER, + REPLY_TIMEOUT_OF_WORKER, + SOCKET_TIMEOUT_OF_WORKER, + SOCKET_CONNECT_TIMEOUT_OF_WORKER, + SOCKET_BUFFER_OF_WORKER, + SOCKET_KEEPALIVE_OF_WORKER, + CONN_PING_INTERVAL_OF_WORKER, + RECYCLE_TIMEOUT_DEPRECATED, + LOAD_FACTOR_OF_WORKER, + DISTANCE_OF_WORKER, + BALANCED_WORKERS_DEPRECATED, + BALANCE_WORKERS, + STICKY_SESSION, + STICKY_SESSION_FORCE, + SESSION_COOKIE_OF_WORKER, + SESSION_PATH_OF_WORKER, + LOCAL_WORKER_DEPRECATED, + LOCAL_WORKER_ONLY_DEPRECATED, + JVM_ROUTE_OF_WORKER_DEPRECATED, + ROUTE_OF_WORKER, + DOMAIN_OF_WORKER, + REDIRECT_OF_WORKER, + MOUNT_OF_WORKER, + METHOD_OF_WORKER, + LOCK_OF_WORKER, + IS_WORKER_DISABLED_DEPRECATED, + IS_WORKER_STOPPED_DEPRECATED, + ACTIVATION_OF_WORKER, + WORKER_RECOVER_TIME, + WORKER_ERROR_ESCALATION_TIME, + MAX_REPLY_TIMEOUTS_OF_WORKER, + RETRY_INTERVAL_OF_WORKER, + WORKER_MAX_PACKET_SIZE, + STYLE_SHEET_OF_WORKER, + NAMESPACE_OF_WORKER, + XML_NAMESPACE_OF_WORKER, + XML_DOCTYPE_OF_WORKER, + PROP_PREFIX_OF_WORKER, + READ_ONLY_OF_WORKER, + USER_OF_WORKER, + USER_CASE_OF_WORKER, + GOOD_RATING_OF_WORKER, + BAD_RATING_OF_WORKER, + SECRET_KEY_OF_WORKER, + RETRIES_OF_WORKER, + STATUS_FAIL_OF_WORKER, + LIST_PROPERTY_NAME, + MAINTAIN_PROPERTY_NAME, + NULL +}; + +static const char *jk_level_verbs[] = { + "[" JK_LOG_TRACE_VERB "] ", + "[" JK_LOG_DEBUG_VERB "] ", + "[" JK_LOG_INFO_VERB "] ", + "[" JK_LOG_WARN_VERB "] ", + "[" JK_LOG_ERROR_VERB "] ", + "[" JK_LOG_EMERG_VERB "] ", + NULL +}; + +const char *jk_get_bool(int v) +{ + if (v == 0) + return "False"; + else + return "True"; +} + +int jk_get_bool_code(const char *v, int def) +{ + if (!v) { + return def; + } + else if (!strcasecmp(v, "off") || + *v == 'F' || *v == 'f' || + *v == 'N' || *v == 'n' || + (*v == '0' && *(v + 1) == '\0')) { + return 0; + } + else if (!strcasecmp(v, "on") || + *v == 'T' || *v == 't' || + *v == 'Y' || *v == 'y' || + (*v == '1' && *(v + 1) == '\0')) { + return 1; + } + return def; +} + +/* Sleep for 100ms */ +void jk_sleep(int ms) +{ +#ifdef OS2 + DosSleep(ms); +#elif defined(BEOS) + snooze(ms * 1000); +#elif defined(NETWARE) + delay(ms); +#elif defined(WIN32) + Sleep(ms); +#else + struct timeval tv; + tv.tv_usec = (ms % 1000) * 1000; + tv.tv_sec = ms / 1000; + select(0, NULL, NULL, NULL, &tv); +#endif +} + +/* Replace the first occurence of a sub second time format character + * by a series of zero digits with the right precision. + * We format our timestamp with strftime, but this can not handle + * sub second timestamps. + * So we first patch the milliseconds or microseconds literally into + * the format string, and then pass it on the strftime. + * In order to do that efficiently, we prepare a format string, that + * already has placeholder digits for the sub second time stamp + * and we save the position and time precision of this placeholder. + */ +void jk_set_time_fmt(jk_logger_t *l, const char *jk_log_fmt) +{ + if (l) { + char *s; + + if (!jk_log_fmt) { +#ifndef NO_GETTIMEOFDAY + jk_log_fmt = JK_TIME_FORMAT_MILLI; +#else + jk_log_fmt = JK_TIME_FORMAT_NONE; +#endif + } + l->log_fmt_type = JK_TIME_SUBSEC_NONE; + l->log_fmt_offset = 0; + l->log_fmt_size = 0; + l->log_fmt = jk_log_fmt; + +/* Look for the first occurence of JK_TIME_CONV_MILLI */ + if ((s = strstr(jk_log_fmt, JK_TIME_CONV_MILLI))) { + size_t offset = s - jk_log_fmt; + size_t len = strlen(JK_TIME_PATTERN_MILLI); + +/* If we don't have enough space in our fixed-length char array, + * we simply stick to the default format, ignoring JK_TIME_CONV_MILLI. + * Otherwise we replace the first occurence of JK_TIME_CONV_MILLI by JK_TIME_PATTERN_MILLI. + */ + if (offset + len < JK_TIME_MAX_SIZE) { + l->log_fmt_type = JK_TIME_SUBSEC_MILLI; + l->log_fmt_offset = offset; + strncpy(l->log_fmt_subsec, jk_log_fmt, offset); + strncpy(l->log_fmt_subsec + offset, JK_TIME_PATTERN_MILLI, len); + strncpy(l->log_fmt_subsec + offset + len, + s + strlen(JK_TIME_CONV_MILLI), + JK_TIME_MAX_SIZE - offset - len - 1); +/* Now we put a stop mark into the string to make it's length at most JK_TIME_MAX_SIZE-1 + * plus terminating '\0'. + */ + l->log_fmt_subsec[JK_TIME_MAX_SIZE-1] = '\0'; + l->log_fmt_size = strlen(l->log_fmt_subsec); + } +/* Look for the first occurence of JK_TIME_CONV_MICRO */ + } + else if ((s = strstr(jk_log_fmt, JK_TIME_CONV_MICRO))) { + size_t offset = s - jk_log_fmt; + size_t len = strlen(JK_TIME_PATTERN_MICRO); + +/* If we don't have enough space in our fixed-length char array, + * we simply stick to the default format, ignoring JK_TIME_CONV_MICRO. + * Otherwise we replace the first occurence of JK_TIME_CONV_MICRO by JK_TIME_PATTERN_MICRO. + */ + if (offset + len < JK_TIME_MAX_SIZE) { + l->log_fmt_type = JK_TIME_SUBSEC_MICRO; + l->log_fmt_offset = offset; + strncpy(l->log_fmt_subsec, jk_log_fmt, offset); + strncpy(l->log_fmt_subsec + offset, JK_TIME_PATTERN_MICRO, len); + strncpy(l->log_fmt_subsec + offset + len, + s + strlen(JK_TIME_CONV_MICRO), + JK_TIME_MAX_SIZE - offset - len - 1); +/* Now we put a stop mark into the string to make it's length at most JK_TIME_MAX_SIZE-1 + * plus terminating '\0'. + */ + l->log_fmt_subsec[JK_TIME_MAX_SIZE-1] = '\0'; + l->log_fmt_size = strlen(l->log_fmt_subsec); + } + } + jk_log(l, JK_LOG_DEBUG, "Pre-processed log time stamp format is '%s'", + l->log_fmt_type == JK_TIME_SUBSEC_NONE ? l->log_fmt : l->log_fmt_subsec); + } +} + +static int set_time_str(char *str, int len, jk_logger_t *l) +{ + time_t t; + struct tm *tms; +#ifdef _MT_CODE_PTHREAD + struct tm res; +#endif + int done; +/* We want to use a fixed maximum size buffer here. + * If we would dynamically adjust it to the real format + * string length, we could support longer format strings, + * but we would have to allocate and free for each log line. + */ + char log_fmt[JK_TIME_MAX_SIZE]; + + if (!l || !l->log_fmt) { + return 0; + } + + log_fmt[0] = '\0'; + +#ifndef NO_GETTIMEOFDAY + if ( l->log_fmt_type != JK_TIME_SUBSEC_NONE ) { + struct timeval tv; + int rc = 0; + +#ifdef WIN32 + gettimeofday(&tv, NULL); +#else + rc = gettimeofday(&tv, NULL); +#endif + if (rc == 0) { +/* We need this subsec buffer, because we convert + * the integer with sprintf(), but we don't + * want to write the terminating '\0' into our + * final log format string. + */ + char subsec[7]; + t = tv.tv_sec; + strncpy(log_fmt, l->log_fmt_subsec, l->log_fmt_size + 1); + if (l->log_fmt_type == JK_TIME_SUBSEC_MILLI) { + sprintf(subsec, "%03d", (int)(tv.tv_usec/1000)); + strncpy(log_fmt + l->log_fmt_offset, subsec, 3); + } + else if (l->log_fmt_type == JK_TIME_SUBSEC_MICRO) { + sprintf(subsec, "%06d", (int)(tv.tv_usec)); + strncpy(log_fmt + l->log_fmt_offset, subsec, 6); + } + } + else { + t = time(NULL); + } + } + else { + t = time(NULL); + } +#else + t = time(NULL); +#endif +#ifdef _MT_CODE_PTHREAD + tms = localtime_r(&t, &res); +#else + tms = localtime(&t); +#endif + if (log_fmt[0]) + done = (int)strftime(str, len, log_fmt, tms); + else + done = (int)strftime(str, len, l->log_fmt, tms); + return done; + +} + +static int JK_METHOD log_to_file(jk_logger_t *l, int level, int used, char *what) +{ + if (l && + (l->level <= level || level == JK_LOG_REQUEST_LEVEL) && + l->logger_private && what) { + jk_file_logger_t *p = l->logger_private; + if (p->logfile) { + what[used++] = '\n'; + what[used] = '\0'; +#if defined(JK_LOG_LOCKING) +#if defined(WIN32) && defined(_MSC_VER) + LockFile((HANDLE)_get_osfhandle(_fileno(p->logfile)), + 0, 0, 1, 0); +#endif +#endif + fputs(what, p->logfile); + /* [V] Flush the dam' thing! */ + fflush(p->logfile); +#if defined(JK_LOG_LOCKING) +#if defined(WIN32) && defined(_MSC_VER) + UnlockFile((HANDLE)_get_osfhandle(_fileno(p->logfile)), + 0, 0, 1, 0); +#endif +#endif + } + return JK_TRUE; + } + return JK_FALSE; +} + +int jk_parse_log_level(const char *level) +{ + if (0 == strcasecmp(level, JK_LOG_TRACE_VERB)) { + return JK_LOG_TRACE_LEVEL; + } + + if (0 == strcasecmp(level, JK_LOG_DEBUG_VERB)) { + return JK_LOG_DEBUG_LEVEL; + } + + if (0 == strcasecmp(level, JK_LOG_INFO_VERB)) { + return JK_LOG_INFO_LEVEL; + } + + if (0 == strcasecmp(level, JK_LOG_WARN_VERB)) { + return JK_LOG_WARNING_LEVEL; + } + + if (0 == strcasecmp(level, JK_LOG_ERROR_VERB)) { + return JK_LOG_ERROR_LEVEL; + } + + if (0 == strcasecmp(level, JK_LOG_EMERG_VERB)) { + return JK_LOG_EMERG_LEVEL; + } + + return JK_LOG_DEF_LEVEL; +} + +int jk_open_file_logger(jk_logger_t **l, const char *file, int level) +{ + if (l && file) { + + jk_logger_t *rc = (jk_logger_t *)malloc(sizeof(jk_logger_t)); + jk_file_logger_t *p = (jk_file_logger_t *) malloc(sizeof(jk_file_logger_t)); + if (rc && p) { + rc->log = log_to_file; + rc->level = level; + rc->logger_private = p; +#if defined(AS400) && !defined(AS400_UTF8) + p->logfile = fopen(file, "a+, o_ccsid=0"); +#elif defined(WIN32) && defined(_MSC_VER) + p->logfile = fopen(file, "a+c"); +#else + p->logfile = fopen(file, "a+"); +#endif + if (p->logfile) { + *l = rc; + jk_set_time_fmt(rc, NULL); + return JK_TRUE; + } + } + if (rc) { + free(rc); + } + if (p) { + free(p); + } + + *l = NULL; + } + return JK_FALSE; +} + +int jk_attach_file_logger(jk_logger_t **l, int fd, int level) +{ + if (l && fd >= 0) { + + jk_logger_t *rc = (jk_logger_t *)malloc(sizeof(jk_logger_t)); + jk_file_logger_t *p = (jk_file_logger_t *) malloc(sizeof(jk_file_logger_t)); + if (rc && p) { + rc->log = log_to_file; + rc->level = level; + rc->logger_private = p; +#if defined(AS400) && !defined(AS400_UTF8) + p->logfile = fdopen(fd, "a+, o_ccsid=0"); +#elif defined(WIN32) && defined(_MSC_VER) + p->logfile = fdopen(fd, "a+c"); +#else + p->logfile = fdopen(fd, "a+"); +#endif + if (p->logfile) { + *l = rc; + jk_set_time_fmt(rc, NULL); + return JK_TRUE; + } + } + if (rc) { + free(rc); + } + if (p) { + free(p); + } + + *l = NULL; + } + return JK_FALSE; +} + +int jk_close_file_logger(jk_logger_t **l) +{ + if (l && *l) { + jk_file_logger_t *p = (*l)->logger_private; + if (p) { + fflush(p->logfile); + fclose(p->logfile); + free(p); + } + free(*l); + *l = NULL; + + return JK_TRUE; + } + return JK_FALSE; +} + +int jk_log(jk_logger_t *l, + const char *file, int line, const char *funcname, int level, + const char *fmt, ...) +{ + int rc = 0; + /* + * Need to reserve space for terminating zero byte + * and platform specific line endings added during the call + * to the output routing. + */ + static int usable_size = HUGE_BUFFER_SIZE - 3; + if (!l || !file || !fmt) { + return -1; + } + + if ((l->level <= level) || (level == JK_LOG_REQUEST_LEVEL)) { +#ifdef NETWARE + /* On NetWare, this can get called on a thread that has a limited stack so */ + /* we will allocate and free the temporary buffer in this function */ + char *buf; +#else + char buf[HUGE_BUFFER_SIZE]; +#endif + char *f = (char *)(file + strlen(file) - 1); + va_list args; + int used = 0; + + while (f != file && '\\' != *f && '/' != *f) { + f--; + } + if (f != file) { + f++; + } + +#ifdef NETWARE + buf = (char *)malloc(HUGE_BUFFER_SIZE); + if (NULL == buf) + return -1; +#endif + used = set_time_str(buf, usable_size, l); + + if (line) { /* line==0 only used for request log item */ + /* Log [pid:threadid] for all levels except REQUEST. */ + /* This information helps to correlate lines from different logs. */ + /* Performance is no issue, because with production log levels */ + /* we only call it often, if we have a lot of errors */ + rc = snprintf(buf + used, usable_size - used, + "[%" JK_PID_T_FMT ":%" JK_PTHREAD_T_FMT "] ", getpid(), jk_gettid()); + used += rc; + if (rc < 0 ) { + return 0; + } + + rc = (int)strlen(jk_level_verbs[level]); + if (usable_size - used >= rc) { + strncpy(buf + used, jk_level_verbs[level], rc); + used += rc; + } + else { + return 0; /* [V] not sure what to return... */ + } + + if (funcname) { + rc = (int)strlen(funcname); + if (usable_size - used >= rc + 2) { + strncpy(buf + used, funcname, rc); + used += rc; + strncpy(buf + used, "::", 2); + used += 2; + } + else { + return 0; /* [V] not sure what to return... */ + } + } + + rc = (int)strlen(f); + if (usable_size - used >= rc) { + strncpy(buf + used, f, rc); + used += rc; + } + else { + return 0; /* [V] not sure what to return... */ + } + + rc = snprintf(buf + used, usable_size - used, + " (%d): ", line); + used += rc; + if (rc < 0 || usable_size - used < 0) { + return 0; /* [V] not sure what to return... */ + } + } + + va_start(args, fmt); + rc = vsnprintf(buf + used, usable_size - used, fmt, args); + va_end(args); + if ( rc <= usable_size - used ) { + used += rc; + } else { + used = usable_size; + } + l->log(l, level, used, buf); + +#ifdef NETWARE + free(buf); +#endif + } + + return rc; +} + +const char *jk_get_worker_type(jk_map_t *m, const char *wname) +{ + char buf[1024]; + + if (!m || !wname) { + return NULL; + } + MAKE_WORKER_PARAM(TYPE_OF_WORKER); + return jk_map_get_string(m, buf, DEFAULT_WORKER_TYPE); +} + +const char *jk_get_worker_route(jk_map_t *m, const char *wname, const char *def) +{ + char buf[1024]; + const char *v; + if (!m || !wname) { + return NULL; + } + MAKE_WORKER_PARAM(ROUTE_OF_WORKER); + v = jk_map_get_string(m, buf, NULL); + if (v) { + return v; + } + /* Try old jvm_route directive */ + MAKE_WORKER_PARAM(JVM_ROUTE_OF_WORKER_DEPRECATED); + return jk_map_get_string(m, buf, def); +} + +const char *jk_get_worker_domain(jk_map_t *m, const char *wname, const char *def) +{ + char buf[1024]; + if (!m || !wname) { + return NULL; + } + MAKE_WORKER_PARAM(DOMAIN_OF_WORKER); + return jk_map_get_string(m, buf, def); +} + +const char *jk_get_worker_redirect(jk_map_t *m, const char *wname, const char *def) +{ + char buf[1024]; + if (!m || !wname) { + return NULL; + } + MAKE_WORKER_PARAM(REDIRECT_OF_WORKER); + return jk_map_get_string(m, buf, def); +} + +const char *jk_get_worker_secret(jk_map_t *m, const char *wname) +{ + char buf[1024]; + + if (!m || !wname) { + return NULL; + } + + MAKE_WORKER_PARAM(SECRET_OF_WORKER); + + return jk_map_get_string(m, buf, NULL); +} + +/* [V] I suggest that the following general purpose functions be used. */ +/* More should be added (double etc.), but now these were enough for me. */ +/* Functions that can be simulated with these should be "deprecated". */ + +int jk_get_worker_str_prop(jk_map_t *m, + const char *wname, const char *pname, const char **prop) +{ + char buf[1024]; + + if (m && prop && wname && pname) { + MAKE_WORKER_PARAM(pname); + *prop = jk_map_get_string(m, buf, NULL); + if (*prop) { + return JK_TRUE; + } + } + return JK_FALSE; +} + +int jk_get_worker_int_prop(jk_map_t *m, + const char *wname, const char *pname, int *prop) +{ + char buf[1024]; + + if (m && prop && wname && pname) { + int i; + MAKE_WORKER_PARAM(pname); + i = jk_map_get_int(m, buf, -1); + if (-1 != i) { + *prop = i; + return JK_TRUE; + } + } + return JK_FALSE; +} + +const char *jk_get_worker_host(jk_map_t *m, const char *wname, const char *def) +{ + char buf[1024]; + + if (!m || !wname) { + return NULL; + } + + MAKE_WORKER_PARAM(HOST_OF_WORKER); + + return jk_map_get_string(m, buf, def); +} + +int jk_get_worker_port(jk_map_t *m, const char *wname, int def) +{ + char buf[1024]; + + if (!m || !wname) { + return -1; + } + + MAKE_WORKER_PARAM(PORT_OF_WORKER); + + return jk_map_get_int(m, buf, def); +} + +static int def_cache_size = -1; +int jk_get_worker_def_cache_size(int protocol) +{ + if (def_cache_size < 1) { + if (protocol == AJP14_PROTO) + def_cache_size = AJP14_DEF_CACHE_SZ; + else + def_cache_size = AJP13_DEF_CACHE_SZ; + } + return def_cache_size; +} + +void jk_set_worker_def_cache_size(int sz) +{ + def_cache_size = sz; +} + +int jk_get_worker_cache_size(jk_map_t *m, const char *wname, int def) +{ + char buf[1024]; + int rv; + + if (!m || !wname) { + return -1; + } + + MAKE_WORKER_PARAM(CACHE_OF_WORKER); + if ((rv = jk_map_get_int(m, buf, -1)) >= 0) + return rv; + MAKE_WORKER_PARAM(CACHE_OF_WORKER_DEPRECATED); + return jk_map_get_int(m, buf, def); +} + +int jk_get_worker_cache_size_min(jk_map_t *m, const char *wname, int def) +{ + char buf[1024]; + + if (!m || !wname) { + return -1; + } + + MAKE_WORKER_PARAM(CACHE_OF_WORKER_MIN); + return jk_map_get_int(m, buf, def); +} + +int jk_get_worker_cache_acquire_timeout(jk_map_t *m, const char *wname, int def) +{ + char buf[1024]; + + if (!m || !wname) { + return -1; + } + + MAKE_WORKER_PARAM(CACHE_ACQUIRE_OF_WORKER); + return jk_map_get_int(m, buf, def); +} + +int jk_get_worker_socket_timeout(jk_map_t *m, const char *wname, int def) +{ + char buf[1024]; + + if (!m || !wname) { + return -1; + } + + MAKE_WORKER_PARAM(SOCKET_TIMEOUT_OF_WORKER); + + return jk_map_get_int(m, buf, def); +} + +int jk_get_worker_socket_connect_timeout(jk_map_t *m, const char *wname, int def) +{ + char buf[1024]; + + if (!m || !wname) { + return -1; + } + + MAKE_WORKER_PARAM(SOCKET_CONNECT_TIMEOUT_OF_WORKER); + + return jk_map_get_int(m, buf, def); +} + +int jk_get_worker_recover_timeout(jk_map_t *m, const char *wname, int def) +{ + char buf[1024]; + + if (!m || !wname) { + return -1; + } + + MAKE_WORKER_PARAM(WORKER_RECOVER_TIME); + + return jk_map_get_int(m, buf, def); +} + +int jk_get_worker_error_escalation_time(jk_map_t *m, const char *wname, int def) +{ + char buf[1024]; + + if (!m || !wname) { + return -1; + } + + MAKE_WORKER_PARAM(WORKER_ERROR_ESCALATION_TIME); + + return jk_map_get_int(m, buf, def); +} + +int jk_get_worker_max_reply_timeouts(jk_map_t *m, const char *wname, int def) +{ + char buf[1024]; + + if (!m || !wname) { + return -1; + } + + MAKE_WORKER_PARAM(MAX_REPLY_TIMEOUTS_OF_WORKER); + + return jk_map_get_int(m, buf, def); +} + +int jk_get_worker_retry_interval(jk_map_t *m, const char *wname, int def) +{ + char buf[1024]; + + if (!m || !wname) { + return -1; + } + + MAKE_WORKER_PARAM(RETRY_INTERVAL_OF_WORKER); + + return jk_map_get_int(m, buf, def); +} + +int jk_get_worker_socket_buffer(jk_map_t *m, const char *wname, int def) +{ + char buf[1024]; + int i; + if (!m || !wname) { + return -1; + } + + MAKE_WORKER_PARAM(SOCKET_BUFFER_OF_WORKER); + + i = jk_map_get_int(m, buf, 0); + if (i > 0 && i < def) + i = def; + return i; +} + +int jk_get_worker_socket_keepalive(jk_map_t *m, const char *wname, int def) +{ + char buf[1024]; + + if (!m || !wname) { + return -1; + } + + MAKE_WORKER_PARAM(SOCKET_KEEPALIVE_OF_WORKER); + + return jk_map_get_bool(m, buf, def); +} + +int jk_get_worker_conn_ping_interval(jk_map_t *m, const char *wname, int def) +{ + char buf[1024]; + + if (!m || !wname) { + return -1; + } + + MAKE_WORKER_PARAM(CONN_PING_INTERVAL_OF_WORKER); + + return jk_map_get_int(m, buf, def); +} + +int jk_get_worker_cache_timeout(jk_map_t *m, const char *wname, int def) +{ + char buf[1024]; + int rv; + + if (!m || !wname) { + return -1; + } + + MAKE_WORKER_PARAM(CACHE_TIMEOUT_OF_WORKER); + if ((rv = jk_map_get_int(m, buf, -1)) >= 0) + return rv; + MAKE_WORKER_PARAM(CACHE_TIMEOUT_DEPRECATED); + + return jk_map_get_int(m, buf, def); +} + +int jk_get_worker_connect_timeout(jk_map_t *m, const char *wname, int def) +{ + char buf[1024]; + + if (!m || !wname) { + return -1; + } + + MAKE_WORKER_PARAM(CONNECT_TIMEOUT_OF_WORKER); + + return jk_map_get_int(m, buf, def); +} + +int jk_get_worker_prepost_timeout(jk_map_t *m, const char *wname, int def) +{ + char buf[1024]; + + if (!m || !wname) { + return -1; + } + + MAKE_WORKER_PARAM(PREPOST_TIMEOUT_OF_WORKER); + + return jk_map_get_int(m, buf, def); +} + +int jk_get_worker_ping_timeout(jk_map_t *m, const char *wname, int def) +{ + char buf[1024]; + + if (!m || !wname) { + return -1; + } + + MAKE_WORKER_PARAM(PING_TIMEOUT_OF_WORKER); + + return jk_map_get_int(m, buf, def); +} + +int jk_get_worker_ping_mode(jk_map_t *m, const char *wname, int def) +{ + char buf[1024]; + const char *v; + + if (!m || !wname) { + return def; + } + + MAKE_WORKER_PARAM(PING_MODE_OF_WORKER); + + v = jk_map_get_string(m, buf, NULL); + return jk_ajp_get_cping_mode(v, def); +} + +int jk_get_worker_reply_timeout(jk_map_t *m, const char *wname, int def) +{ + char buf[1024]; + + if (!m || !wname) { + return -1; + } + + MAKE_WORKER_PARAM(REPLY_TIMEOUT_OF_WORKER); + + return jk_map_get_int(m, buf, def); +} + +int jk_get_worker_recycle_timeout(jk_map_t *m, const char *wname, int def) +{ + return def; +} + +int jk_get_worker_retries(jk_map_t *m, const char *wname, int def) +{ + char buf[1024]; + int rv; + if (!m || !wname) { + return -1; + } + + MAKE_WORKER_PARAM(RETRIES_OF_WORKER); + + rv = jk_map_get_int(m, buf, def); + if (rv < 1) + rv = 1; + + return rv; +} + +int jk_get_worker_recovery_opts(jk_map_t *m, const char *wname, int def) +{ + char buf[1024]; + + if (!m || !wname) { + return -1; + } + + MAKE_WORKER_PARAM(RECOVERY_OPTS_OF_WORKER); + + return jk_map_get_int(m, buf, def); +} + +const char *jk_get_worker_secret_key(jk_map_t *m, const char *wname) +{ + char buf[1024]; + + if (!m || !wname) { + return NULL; + } + + MAKE_WORKER_PARAM(SECRET_KEY_OF_WORKER); + return jk_map_get_string(m, buf, NULL); +} + +int jk_get_worker_list(jk_map_t *m, char ***list, unsigned *num_of_workers) +{ + if (m && list && num_of_workers) { + char **ar = jk_map_get_string_list(m, + WORKER_LIST_PROPERTY_NAME, + num_of_workers, + DEFAULT_WORKER); + if (ar) { + *list = ar; + return JK_TRUE; + } + *list = NULL; + *num_of_workers = 0; + } + + return JK_FALSE; +} + +int jk_get_is_worker_disabled(jk_map_t *m, const char *wname) +{ + int rc = JK_TRUE; + char buf[1024]; + if (m && wname) { + int value; + MAKE_WORKER_PARAM(IS_WORKER_DISABLED_DEPRECATED); + value = jk_map_get_bool(m, buf, 0); + if (!value) + rc = JK_FALSE; + } + return rc; +} + +int jk_get_is_worker_stopped(jk_map_t *m, const char *wname) +{ + int rc = JK_TRUE; + char buf[1024]; + if (m && wname) { + int value; + MAKE_WORKER_PARAM(IS_WORKER_STOPPED_DEPRECATED); + value = jk_map_get_bool(m, buf, 0); + if (!value) + rc = JK_FALSE; + } + return rc; +} + +int jk_get_worker_activation(jk_map_t *m, const char *wname) +{ + char buf[1024]; + const char *v; + if (!m || !wname) { + return JK_LB_ACTIVATION_ACTIVE; + } + + MAKE_WORKER_PARAM(ACTIVATION_OF_WORKER); + v = jk_map_get_string(m, buf, NULL); + if (v) { + return jk_lb_get_activation_code(v); + } + else if (jk_get_is_worker_stopped(m, wname)) + return JK_LB_ACTIVATION_STOPPED; + else if (jk_get_is_worker_disabled(m, wname)) + return JK_LB_ACTIVATION_DISABLED; + else + return JK_LB_ACTIVATION_DEF; +} + +int jk_get_lb_factor(jk_map_t *m, const char *wname) +{ + char buf[1024]; + + if (!m || !wname) { + return DEFAULT_LB_FACTOR; + } + + MAKE_WORKER_PARAM(LOAD_FACTOR_OF_WORKER); + + return jk_map_get_int(m, buf, DEFAULT_LB_FACTOR); +} + +int jk_get_distance(jk_map_t *m, const char *wname) +{ + char buf[1024]; + + if (!m || !wname) { + return DEFAULT_DISTANCE; + } + + MAKE_WORKER_PARAM(DISTANCE_OF_WORKER); + + return jk_map_get_int(m, buf, DEFAULT_DISTANCE); +} + +int jk_get_is_sticky_session(jk_map_t *m, const char *wname) +{ + int rc = JK_TRUE; + char buf[1024]; + if (m && wname) { + int value; + MAKE_WORKER_PARAM(STICKY_SESSION); + value = jk_map_get_bool(m, buf, 1); + if (!value) + rc = JK_FALSE; + } + return rc; +} + +int jk_get_is_sticky_session_force(jk_map_t *m, const char *wname) +{ + int rc = JK_FALSE; + char buf[1024]; + if (m && wname) { + int value; + MAKE_WORKER_PARAM(STICKY_SESSION_FORCE); + value = jk_map_get_bool(m, buf, 0); + if (value) + rc = JK_TRUE; + } + return rc; +} + +int jk_get_lb_method(jk_map_t *m, const char *wname) +{ + char buf[1024]; + const char *v; + if (!m || !wname) { + return JK_LB_METHOD_DEF; + } + + MAKE_WORKER_PARAM(METHOD_OF_WORKER); + v = jk_map_get_string(m, buf, NULL); + return jk_lb_get_method_code(v); +} + +int jk_get_lb_lock(jk_map_t *m, const char *wname) +{ + char buf[1024]; + const char *v; + if (!m || !wname) { + return JK_LB_LOCK_DEF; + } + + MAKE_WORKER_PARAM(LOCK_OF_WORKER); + v = jk_map_get_string(m, buf, NULL); + return jk_lb_get_lock_code(v); +} + +int jk_get_max_packet_size(jk_map_t *m, const char *wname) +{ + char buf[1024]; + int sz; + + if (!m || !wname) { + return DEF_BUFFER_SZ; + } + + MAKE_WORKER_PARAM(WORKER_MAX_PACKET_SIZE); + sz = jk_map_get_int(m, buf, DEF_BUFFER_SZ); + sz = JK_ALIGN(sz, 1024); + if (sz < DEF_BUFFER_SZ) + sz = DEF_BUFFER_SZ; + else if (sz > 64*1024) + sz = 64*1024; + + return sz; +} + +int jk_get_worker_fail_on_status(jk_map_t *m, const char *wname, + int *list, unsigned int list_size) +{ + char buf[1024]; + if (!m || !wname || !list) { + return 0; + } + MAKE_WORKER_PARAM(STATUS_FAIL_OF_WORKER); + if (list_size) { + return jk_map_get_int_list(m, buf, + list, list_size, + NULL); + } + + return 0; +} + +int jk_get_worker_user_case_insensitive(jk_map_t *m, const char *wname) +{ + int rc = JK_FALSE; + char buf[1024]; + if (m && wname) { + int value; + MAKE_WORKER_PARAM(USER_CASE_OF_WORKER); + value = jk_map_get_bool(m, buf, 0); + if (value) + rc = JK_TRUE; + } + return rc; + +} + +const char *jk_get_worker_style_sheet(jk_map_t *m, const char *wname, const char *def) +{ + char buf[1024]; + + if (!m || !wname) { + return NULL; + } + + MAKE_WORKER_PARAM(STYLE_SHEET_OF_WORKER); + + return jk_map_get_string(m, buf, def); +} + +const char *jk_get_worker_name_space(jk_map_t *m, const char *wname, const char *def) +{ + const char *rc; + char buf[1024]; + if (!m || !wname) { + return NULL; + } + MAKE_WORKER_PARAM(NAMESPACE_OF_WORKER); + rc = jk_map_get_string(m, buf, def); + if (*rc == '-') + return ""; + else + return rc; +} + +const char *jk_get_worker_xmlns(jk_map_t *m, const char *wname, const char *def) +{ + const char *rc; + char buf[1024]; + if (!m || !wname) { + return NULL; + } + MAKE_WORKER_PARAM(XML_NAMESPACE_OF_WORKER); + rc = jk_map_get_string(m, buf, def); + if (*rc == '-') + return ""; + else + return rc; +} + +const char *jk_get_worker_xml_doctype(jk_map_t *m, const char *wname, const char *def) +{ + char buf[1024]; + if (!m || !wname) { + return NULL; + } + MAKE_WORKER_PARAM(XML_DOCTYPE_OF_WORKER); + return jk_map_get_string(m, buf, def); +} + +const char *jk_get_worker_prop_prefix(jk_map_t *m, const char *wname, const char *def) +{ + char buf[1024]; + if (!m || !wname) { + return NULL; + } + MAKE_WORKER_PARAM(PROP_PREFIX_OF_WORKER); + return jk_map_get_string(m, buf, def); +} + +int jk_get_is_read_only(jk_map_t *m, const char *wname) +{ + int rc = JK_FALSE; + char buf[1024]; + if (m && wname) { + int value; + MAKE_WORKER_PARAM(READ_ONLY_OF_WORKER); + value = jk_map_get_bool(m, buf, 0); + if (value) + rc = JK_TRUE; + } + return rc; +} + +int jk_get_worker_user_list(jk_map_t *m, + const char *wname, + char ***list, unsigned int *num) +{ + char buf[1024]; + + if (m && list && num && wname) { + char **ar = NULL; + + MAKE_WORKER_PARAM(USER_OF_WORKER); + ar = jk_map_get_string_list(m, buf, num, NULL); + if (ar) { + *list = ar; + return JK_TRUE; + } + *list = NULL; + *num = 0; + } + + return JK_FALSE; +} + +int jk_get_worker_good_rating(jk_map_t *m, + const char *wname, + char ***list, unsigned int *num) +{ + char buf[1024]; + + if (m && list && num && wname) { + char **ar = NULL; + + MAKE_WORKER_PARAM(GOOD_RATING_OF_WORKER); + ar = jk_map_get_string_list(m, buf, num, NULL); + if (ar) { + *list = ar; + return JK_TRUE; + } + *list = NULL; + *num = 0; + } + + return JK_FALSE; +} + +int jk_get_worker_bad_rating(jk_map_t *m, + const char *wname, + char ***list, unsigned int *num) +{ + char buf[1024]; + + if (m && list && num && wname) { + char **ar = NULL; + + MAKE_WORKER_PARAM(BAD_RATING_OF_WORKER); + ar = jk_map_get_string_list(m, buf, num, NULL); + if (ar) { + *list = ar; + return JK_TRUE; + } + *list = NULL; + *num = 0; + } + + return JK_FALSE; +} + +int jk_get_lb_worker_list(jk_map_t *m, + const char *wname, + char ***list, unsigned int *num_of_workers) +{ + char buf[1024]; + + if (m && list && num_of_workers && wname) { + char **ar = NULL; + + MAKE_WORKER_PARAM(BALANCE_WORKERS); + ar = jk_map_get_string_list(m, buf, num_of_workers, NULL); + if (ar) { + *list = ar; + return JK_TRUE; + } + /* Try old balanced_workers directive */ + MAKE_WORKER_PARAM(BALANCED_WORKERS_DEPRECATED); + ar = jk_map_get_string_list(m, buf, num_of_workers, NULL); + if (ar) { + *list = ar; + return JK_TRUE; + } + *list = NULL; + *num_of_workers = 0; + } + + return JK_FALSE; +} + +int jk_get_worker_mount_list(jk_map_t *m, + const char *wname, + char ***list, unsigned int *num_of_maps) +{ + char buf[1024]; + + if (m && list && num_of_maps && wname) { + char **ar = NULL; + + MAKE_WORKER_PARAM(MOUNT_OF_WORKER); + ar = jk_map_get_string_list(m, buf, num_of_maps, NULL); + if (ar) { + *list = ar; + return JK_TRUE; + } + *list = NULL; + *num_of_maps = 0; + } + + return JK_FALSE; +} + +int jk_get_worker_maintain_time(jk_map_t *m) +{ + return jk_map_get_int(m, WORKER_MAINTAIN_PROPERTY_NAME, + DEFAULT_MAINTAIN_TIME); +} + +int jk_get_worker_mx(jk_map_t *m, const char *wname, unsigned *mx) +{ + char buf[1024]; + + if (m && mx && wname) { + int i; + MAKE_WORKER_PARAM(MX_OF_WORKER); + + i = jk_map_get_int(m, buf, -1); + if (-1 != i) { + *mx = (unsigned)i; + return JK_TRUE; + } + } + + return JK_FALSE; +} + +int jk_get_worker_ms(jk_map_t *m, const char *wname, unsigned *ms) +{ + char buf[1024]; + + if (m && ms && wname) { + int i; + MAKE_WORKER_PARAM(MS_OF_WORKER); + + i = jk_map_get_int(m, buf, -1); + if (-1 != i) { + *ms = (unsigned)i; + return JK_TRUE; + } + } + + return JK_FALSE; +} + +int jk_get_worker_classpath(jk_map_t *m, const char *wname, const char **cp) +{ + char buf[1024]; + + if (m && cp && wname) { + MAKE_WORKER_PARAM(CP_OF_WORKER); + + *cp = jk_map_get_string(m, buf, NULL); + if (*cp) { + return JK_TRUE; + } + } + + return JK_FALSE; +} + +int jk_get_worker_bridge_type(jk_map_t *m, const char *wname, unsigned *bt) +{ + char buf[1024]; + const char *type; + + if (m && bt && wname) { + MAKE_WORKER_PARAM(BRIDGE_OF_WORKER); + + type = jk_map_get_string(m, buf, NULL); + + if (type) { + if (!strcasecmp(type, TOMCAT32_BRIDGE_NAME)) + *bt = TC32_BRIDGE_TYPE; + else if (!strcasecmp(type, TOMCAT33_BRIDGE_NAME)) + *bt = TC33_BRIDGE_TYPE; + else if (!strcasecmp(type, TOMCAT40_BRIDGE_NAME)) + *bt = TC40_BRIDGE_TYPE; + else if (!strcasecmp(type, TOMCAT41_BRIDGE_NAME)) + *bt = TC41_BRIDGE_TYPE; + else if (!strcasecmp(type, TOMCAT50_BRIDGE_NAME)) + *bt = TC50_BRIDGE_TYPE; + + return JK_TRUE; + } + } + + return JK_FALSE; +} + +int jk_get_worker_jvm_path(jk_map_t *m, const char *wname, const char **vm_path) +{ + char buf[1024]; + + if (m && vm_path && wname) { + MAKE_WORKER_PARAM(JVM_OF_WORKER); + + *vm_path = jk_map_get_string(m, buf, NULL); + if (*vm_path) { + return JK_TRUE; + } + } + + return JK_FALSE; +} + +/* [V] This is unused. currently. */ +int jk_get_worker_callback_dll(jk_map_t *m, const char *wname, const char **cb_path) +{ + char buf[1024]; + + if (m && cb_path && wname) { + MAKE_WORKER_PARAM(NATIVE_LIB_OF_WORKER); + + *cb_path = jk_map_get_string(m, buf, NULL); + if (*cb_path) { + return JK_TRUE; + } + } + + return JK_FALSE; +} + +int jk_get_worker_cmd_line(jk_map_t *m, const char *wname, const char **cmd_line) +{ + char buf[1024]; + + if (m && cmd_line && wname) { + MAKE_WORKER_PARAM(CMD_LINE_OF_WORKER); + + *cmd_line = jk_map_get_string(m, buf, NULL); + if (*cmd_line) { + return JK_TRUE; + } + } + + return JK_FALSE; +} + + +int jk_stat(const char *f, struct stat * statbuf) +{ + int rc; +/** + * i5/OS V5R4 expect filename in ASCII for fopen but required them in EBCDIC for stat() + */ +#ifdef AS400_UTF8 + char *ptr; + + ptr = (char *)malloc(strlen(f) + 1); + jk_ascii2ebcdic((char *)f, ptr); + rc = stat(ptr, statbuf); + free(ptr); +#else + rc = stat(f, statbuf); +#endif + + return (rc); +} + + +int jk_file_exists(const char *f) +{ + if (f) { + struct stat st; + + if ((0 == jk_stat(f, &st)) && (st.st_mode & S_IFREG)) + return JK_TRUE; + } + + return JK_FALSE; +} + +static int jk_is_some_property(const char *prp_name, const char *suffix, const char *sep) +{ + char buf[1024]; + + if (prp_name && suffix) { + size_t prp_name_len; + size_t suffix_len; + strcpy(buf, sep); + strcat(buf, suffix); + prp_name_len = strlen(prp_name); + suffix_len = strlen(buf); + if (prp_name_len >= suffix_len) { + const char *prp_suffix = prp_name + prp_name_len - suffix_len; + if (0 == strcmp(buf, prp_suffix)) { + return JK_TRUE; + } + } + } + + return JK_FALSE; +} + +int jk_is_path_property(const char *prp_name) +{ + return jk_is_some_property(prp_name, "path", "_"); +} + +int jk_is_cmd_line_property(const char *prp_name) +{ + return jk_is_some_property(prp_name, CMD_LINE_OF_WORKER, "."); +} + +int jk_is_list_property(const char *prp_name) +{ + const char **props = &list_properties[0]; + while (*props) { + if (jk_is_some_property(prp_name, *props, ".")) + return JK_TRUE; + props++; + } + return JK_FALSE; +} + +int jk_is_unique_property(const char *prp_name) +{ + const char **props = &unique_properties[0]; + while (*props) { + if (jk_is_some_property(prp_name, *props, ".")) + return JK_TRUE; + props++; + } + return JK_FALSE; +} + +int jk_is_deprecated_property(const char *prp_name) +{ + const char **props = &deprecated_properties[0]; + while (*props) { + if (jk_is_some_property(prp_name, *props, ".")) + return JK_TRUE; + props++; + } + return JK_FALSE; +} +/* + * Check that property is a valid one (to prevent user typos). + * Only property starting with worker. + */ +int jk_is_valid_property(const char *prp_name) +{ + const char **props; + if (memcmp(prp_name, "worker.", 7)) + return JK_TRUE; + + props = &supported_properties[0]; + while (*props) { + if (jk_is_some_property(prp_name, *props, ".")) + return JK_TRUE; + props++; + } + return JK_FALSE; +} + +int jk_get_worker_stdout(jk_map_t *m, const char *wname, const char **stdout_name) +{ + char buf[1024]; + + if (m && stdout_name && wname) { + MAKE_WORKER_PARAM(STDOUT_OF_WORKER); + + *stdout_name = jk_map_get_string(m, buf, NULL); + if (*stdout_name) { + return JK_TRUE; + } + } + + return JK_FALSE; +} + +int jk_get_worker_stderr(jk_map_t *m, const char *wname, const char **stderr_name) +{ + char buf[1024]; + + if (m && stderr_name && wname) { + MAKE_WORKER_PARAM(STDERR_OF_WORKER); + + *stderr_name = jk_map_get_string(m, buf, NULL); + if (*stderr_name) { + return JK_TRUE; + } + } + + return JK_FALSE; +} + +int jk_get_worker_sysprops(jk_map_t *m, const char *wname, const char **sysprops) +{ + char buf[1024]; + + if (m && sysprops && wname) { + MAKE_WORKER_PARAM(SYSPROPS_OF_WORKER); + + *sysprops = jk_map_get_string(m, buf, NULL); + if (*sysprops) { + return JK_TRUE; + } + } + + return JK_FALSE; +} + +int jk_get_worker_libpath(jk_map_t *m, const char *wname, const char **libpath) +{ + char buf[1024]; + + if (m && libpath && wname) { + MAKE_WORKER_PARAM(LIBPATH_OF_WORKER); + + *libpath = jk_map_get_string(m, buf, NULL); + if (*libpath) { + return JK_TRUE; + } + } + + return JK_FALSE; +} + +const char *jk_get_lb_session_cookie(jk_map_t *m, const char *wname, const char *def) +{ + char buf[1024]; + if (!m || !wname) { + return NULL; + } + MAKE_WORKER_PARAM(SESSION_COOKIE_OF_WORKER); + return jk_map_get_string(m, buf, def); +} + +const char *jk_get_lb_session_path(jk_map_t *m, const char *wname, const char *def) +{ + char buf[1024]; + if (!m || !wname) { + return NULL; + } + MAKE_WORKER_PARAM(SESSION_PATH_OF_WORKER); + return jk_map_get_string(m, buf, def); +} + + +int is_http_status_fail(unsigned int http_status_fail_num, + int *http_status_fail, int status) +{ + unsigned int i; + int soft_status = -1 * status; + for (i = 0; i < http_status_fail_num; i++) { + if (http_status_fail[i] == status) + return 1; + else if (http_status_fail[i] == soft_status) + return -1; + } + return 0; +} + +char **jk_parse_sysprops(jk_pool_t *p, const char *sysprops) +{ + char **rc = NULL; +#ifdef _MT_CODE_PTHREAD + char *lasts; +#endif + + if (p && sysprops) { + char *prps = jk_pool_strdup(p, sysprops); + if (prps && strlen(prps)) { + unsigned num_of_prps; + + for (num_of_prps = 1; *sysprops; sysprops++) { + if ('*' == *sysprops) { + num_of_prps++; + } + } + + rc = jk_pool_alloc(p, (num_of_prps + 1) * sizeof(char *)); + if (rc) { + unsigned i = 0; +#ifdef _MT_CODE_PTHREAD + char *tmp = strtok_r(prps, "*", &lasts); +#else + char *tmp = strtok(prps, "*"); +#endif + + while (tmp && i < num_of_prps) { + rc[i] = tmp; +#ifdef _MT_CODE_PTHREAD + tmp = strtok_r(NULL, "*", &lasts); +#else + tmp = strtok(NULL, "*"); +#endif + i++; + } + rc[i] = NULL; + } + } + } + + return rc; +} + +void jk_append_libpath(jk_pool_t *p, const char *libpath) +{ + char *env = NULL; + char *current = getenv(PATH_ENV_VARIABLE); + + if (current) { + env = jk_pool_alloc(p, strlen(PATH_ENV_VARIABLE) + + strlen(current) + strlen(libpath) + 5); + if (env) { + sprintf(env, "%s=%s%c%s", + PATH_ENV_VARIABLE, libpath, PATH_SEPERATOR, current); + } + } + else { + env = jk_pool_alloc(p, strlen(PATH_ENV_VARIABLE) + + strlen(libpath) + 5); + if (env) { + sprintf(env, "%s=%s", PATH_ENV_VARIABLE, libpath); + } + } + + if (env) { + putenv(env); + } +} + +void jk_init_ws_service(jk_ws_service_t *s) +{ + s->ws_private = NULL; + s->pool = NULL; + s->method = NULL; + s->protocol = NULL; + s->req_uri = NULL; + s->remote_addr = NULL; + s->remote_port = NULL; + s->remote_host = NULL; + s->remote_user = NULL; + s->auth_type = NULL; + s->query_string = NULL; + s->server_name = NULL; + s->server_port = 80; + s->server_software = NULL; + s->content_length = 0; + s->is_chunked = 0; + s->no_more_chunks = 0; + s->content_read = 0; + s->is_ssl = JK_FALSE; + s->ssl_cert = NULL; + s->ssl_cert_len = 0; + s->ssl_cipher = NULL; + s->ssl_session = NULL; + s->ssl_key_size = -1; + s->headers_names = NULL; + s->headers_values = NULL; + s->num_headers = 0; + s->attributes_names = NULL; + s->attributes_values = NULL; + s->num_attributes = 0; + s->route = NULL; + s->activation = JK_LB_ACTIVATION_ACTIVE; + s->secret = NULL; + s->reco_buf = NULL; + s->reco_status = RECO_NONE; + s->flush_packets = JK_FALSE; + s->flush_header = JK_FALSE; + s->extension.reply_timeout = -1; + s->extension.use_server_error_pages = 0; + s->extension.activation = NULL; + s->extension.fail_on_status_size = 0; + s->extension.fail_on_status = NULL; + s->response_started = JK_FALSE; + s->response_blocked = JK_FALSE; + s->http_response_status = JK_HTTP_OK; + s->uw_map = NULL; + s->start_response = NULL; + s->read = NULL; + s->write = NULL; + s->flush = NULL; + s->done = NULL; + s->disable_reuse = JK_FALSE; + s->add_log_items = NULL; + s->next_vhost = NULL; + s->vhost_to_text = NULL; + s->vhost_to_uw_map = NULL; +} + +/* Match = 0, NoMatch = 1, Abort = -1 + * Based loosely on sections of wildmat.c by Rich Salz + */ +int jk_wildchar_match(const char *str, const char *exp, int icase) +{ + int x, y; + + for (x = 0, y = 0; exp[y]; ++y, ++x) { + if (!str[x] && exp[y] != '*') + return -1; + if (exp[y] == '*') { + while (exp[++y] == '*'); + if (!exp[y]) + return 0; + while (str[x]) { + int ret; + if ((ret = jk_wildchar_match(&str[x++], &exp[y], icase)) != 1) + return ret; + } + return -1; + } + else if (exp[y] != '?') { + if (icase && (tolower(str[x]) != tolower(exp[y]))) + return 1; + else if (!icase && str[x] != exp[y]) + return 1; + } + } + return (str[x] != '\0'); +} + +#ifdef _MT_CODE_PTHREAD +jk_pthread_t jk_gettid() +{ + union { + pthread_t tid; + jk_uint64_t alignme; + } u; +#ifdef AS400 + /* OS400 use 64 bits ThreadId */ + pthread_id_np_t tid; +#endif /* AS400 */ + u.tid = pthread_self(); +#ifdef AS400 + /* Get only low 32 bits for now */ + pthread_getunique_np(&(u.tid), &tid); + return ((jk_uint32_t)(tid.intId.lo & 0xFFFFFFFF)); +#else + return ((jk_pthread_t)u.tid); +#endif /* AS400 */ +} +#endif + +/*** + * ASCII <-> EBCDIC conversions + * + * For now usefull only in i5/OS V5R4 where UTF and EBCDIC mode are mixed + */ + +#ifdef AS400_UTF8 + +/* EBCDIC to ASCII translation table */ +static u_char ebcdic_to_ascii[256] = +{ + 0x00,0x01,0x02,0x03,0x20,0x09,0x20,0x7f, /* 00-07 */ + 0x20,0x20,0x20,0x0b,0x0c,0x0d,0x0e,0x0f, /* 08-0f */ + 0x10,0x11,0x12,0x13,0x20,0x0a,0x08,0x20, /* 10-17 */ + 0x18,0x19,0x20,0x20,0x20,0x1d,0x1e,0x1f, /* 18-1f */ + 0x20,0x20,0x1c,0x20,0x20,0x0a,0x17,0x1b, /* 20-27 */ + 0x20,0x20,0x20,0x20,0x20,0x05,0x06,0x07, /* 28-2f */ + 0x20,0x20,0x16,0x20,0x20,0x20,0x20,0x04, /* 30-37 */ + 0x20,0x20,0x20,0x20,0x14,0x15,0x20,0x1a, /* 38-3f */ + 0x20,0x20,0x83,0x84,0x85,0xa0,0xc6,0x86, /* 40-47 */ + 0x87,0xa4,0xbd,0x2e,0x3c,0x28,0x2b,0x7c, /* 48-4f */ + 0x26,0x82,0x88,0x89,0x8a,0xa1,0x8c,0x8b, /* 50-57 */ + 0x8d,0xe1,0x21,0x24,0x2a,0x29,0x3b,0xaa, /* 58-5f */ + 0x2d,0x2f,0xb6,0x8e,0xb7,0xb5,0xc7,0x8f, /* 60-67 */ + 0x80,0xa5,0xdd,0x2c,0x25,0x5f,0x3e,0x3f, /* 68-6f */ + 0x9b,0x90,0xd2,0xd3,0xd4,0xd6,0xd7,0xd8, /* 70-77 */ + 0xde,0x60,0x3a,0x23,0x40,0x27,0x3d,0x22, /* 78-7f */ + 0x9d,0x61,0x62,0x63,0x64,0x65,0x66,0x67, /* 80-87 */ + 0x68,0x69,0xae,0xaf,0xd0,0xec,0xe7,0xf1, /* 88-8f */ + 0xf8,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70, /* 90-97 */ + 0x71,0x72,0xa6,0xa7,0x91,0xf7,0x92,0xcf, /* 98-9f */ + 0xe6,0x7e,0x73,0x74,0x75,0x76,0x77,0x78, /* a8-a7 */ + 0x79,0x7a,0xad,0xa8,0xd1,0xed,0xe8,0xa9, /* a8-af */ + 0x5e,0x9c,0xbe,0xfa,0xb8,0x15,0x14,0xac, /* b0-b7 */ + 0xab,0xf3,0x5b,0x5d,0xee,0xf9,0xef,0x9e, /* b8-bf */ + 0x7b,0x41,0x42,0x43,0x44,0x45,0x46,0x47, /* c0-c7 */ + 0x48,0x49,0xf0,0x93,0x94,0x95,0xa2,0xe4, /* c8-cf */ + 0x7d,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50, /* d0-d7 */ + 0x51,0x52,0xfb,0x96,0x81,0x97,0xa3,0x98, /* d8-df */ + 0x5c,0xf6,0x53,0x54,0x55,0x56,0x57,0x58, /* e0-e7 */ + 0x59,0x5a,0xfc,0xe2,0x99,0xe3,0xe0,0xe5, /* e8-ef */ + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, /* f0-f7 */ + 0x38,0x39,0xfd,0xea,0x9a,0xeb,0xe9,0xff /* f8-ff */ +}; + +/* ASCII to EBCDIC translation table */ +static u_char ascii_to_ebcdic[256] = +{ + 0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f, /* 00-07 */ + 0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f, /* 08-0f */ + 0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26, /* 10-17 */ + 0x18,0x19,0x3f,0x27,0x22,0x1d,0x1e,0x1f, /* 18-1f */ + 0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, /* 20-27 */ + 0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61, /* 28-2f */ + 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, /* 30-37 */ + 0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f, /* 38-3f */ + 0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, /* 40-47 */ + 0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6, /* 48-4f */ + 0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, /* 50-57 */ + 0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d, /* 58-5f */ + 0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, /* 60-67 */ + 0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96, /* 68-6f */ + 0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, /* 70-77 */ + 0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07, /* 78-7f */ + 0x68,0xdc,0x51,0x42,0x43,0x44,0x47,0x48, /* 80-87 */ + 0x52,0x53,0x54,0x57,0x56,0x58,0x63,0x67, /* 88-8f */ + 0x71,0x9c,0x9e,0xcb,0xcc,0xcd,0xdb,0xdd, /* 90-97 */ + 0xdf,0xec,0xfc,0x70,0xb1,0x80,0xbf,0x40, /* 98-9f */ + 0x45,0x55,0xee,0xde,0x49,0x69,0x9a,0x9b, /* a8-a7 */ + 0xab,0xaf,0x5f,0xb8,0xb7,0xaa,0x8a,0x8b, /* a8-af */ + 0x40,0x40,0x40,0x40,0x40,0x65,0x62,0x64, /* b0-b7 */ + 0xb4,0x40,0x40,0x40,0x40,0x4a,0xb2,0x40, /* b8-bf */ + 0x40,0x40,0x40,0x40,0x40,0x40,0x46,0x66, /* c0-c7 */ + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x9f, /* c8-cf */ + 0x8c,0xac,0x72,0x73,0x74,0x89,0x75,0x76, /* d0-d7 */ + 0x77,0x40,0x40,0x40,0x40,0x6a,0x78,0x40, /* d8-df */ + 0xee,0x59,0xeb,0xed,0xcf,0xef,0xa0,0x8e, /* e0-e7 */ + 0xae,0xfe,0xfb,0xfd,0x8d,0xad,0xbc,0xbe, /* e8-ef */ + 0xca,0x8f,0x40,0xb9,0xb6,0xb5,0xe1,0x9d, /* f0-f7 */ + 0x90,0xbd,0xb3,0xda,0xea,0xfa,0x40,0x40 /* f8-ff */ +}; + +void jk_ascii2ebcdic(char *src, char *dst) { + char c; + + while ((c = *src++) != 0) { + *dst++ = ascii_to_ebcdic[(unsigned int)c]; + } + + *dst = 0; +} + +void jk_ebcdic2ascii(char *src, char *dst) { + char c; + + while ((c = *src++) != 0) { + *dst++ = ebcdic_to_ascii[(unsigned int)c]; + } + + *dst = 0; +} + +#endif diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_util.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_util.h new file mode 100644 index 00000000..b76d0283 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_util.h @@ -0,0 +1,269 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Various utility functions * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Author: Henri Gomez <hgomez@apache.org> * + * Author: Rainer Jung <rjung@apache.org> * + * Version: $Revision: 751914 $ * + ***************************************************************************/ +#ifndef _JK_UTIL_H +#define _JK_UTIL_H + +#include "jk_global.h" +#include "jk_logger.h" +#include "jk_map.h" +#include "jk_pool.h" +#include "jk_service.h" + +#define JK_SLEEP_DEF (100) + +const char *jk_get_bool(int v); + +int jk_get_bool_code(const char *v, int def); + +void jk_sleep(int ms); + +void jk_set_time_fmt(jk_logger_t *l, const char *jk_log_fmt); + +int jk_parse_log_level(const char *level); + +int jk_open_file_logger(jk_logger_t **l, const char *file, int level); + +int jk_attach_file_logger(jk_logger_t **l, int fd, int level); + +int jk_close_file_logger(jk_logger_t **l); + +int jk_log(jk_logger_t *l, + const char *file, int line, const char *funcname, int level, + const char *fmt, ...); + +/* [V] Two general purpose functions. Should ease the function bloat. */ +int jk_get_worker_str_prop(jk_map_t *m, + const char *wname, const char *pname, const char **prop); + +int jk_get_worker_int_prop(jk_map_t *m, + const char *wname, const char *pname, int *prop); + +const char *jk_get_worker_host(jk_map_t *m, const char *wname, const char *def); + +const char *jk_get_worker_type(jk_map_t *m, const char *wname); + +int jk_get_worker_port(jk_map_t *m, const char *wname, int def); + +int jk_get_worker_cache_size(jk_map_t *m, const char *wname, int def); + +int jk_get_worker_cache_size_min(jk_map_t *m, const char *wname, int def); + +int jk_get_worker_cache_acquire_timeout(jk_map_t *m, const char *wname, int def); + +int jk_get_worker_socket_timeout(jk_map_t *m, const char *wname, int def); + +int jk_get_worker_socket_connect_timeout(jk_map_t *m, const char *wname, int def); + +int jk_get_worker_socket_buffer(jk_map_t *m, const char *wname, int def); + +int jk_get_worker_socket_keepalive(jk_map_t *m, const char *wname, int def); + +int jk_get_worker_conn_ping_interval(jk_map_t *m, const char *wname, int def); + +int jk_get_worker_cache_timeout(jk_map_t *m, const char *wname, int def); + +int jk_get_worker_recovery_opts(jk_map_t *m, const char *wname, int def); + +int jk_get_worker_connect_timeout(jk_map_t *m, const char *wname, int def); + +int jk_get_worker_reply_timeout(jk_map_t *m, const char *wname, int def); + +int jk_get_worker_prepost_timeout(jk_map_t *m, const char *wname, int def); + +int jk_get_worker_ping_timeout(jk_map_t *m, const char *wname, int def); + +int jk_get_worker_ping_mode(jk_map_t *m, const char *wname, int def); + +int jk_get_worker_recycle_timeout(jk_map_t *m, const char *wname, int def); + +int jk_get_worker_recover_timeout(jk_map_t *m, const char *wname, int def); + +int jk_get_worker_error_escalation_time(jk_map_t *m, const char *wname, int def); + +int jk_get_worker_max_reply_timeouts(jk_map_t *m, const char *wname, int def); + +int jk_get_worker_retry_interval(jk_map_t *m, const char *wname, int def); + +const char *jk_get_worker_route(jk_map_t *m, const char *wname, const char *def); + +const char *jk_get_worker_domain(jk_map_t *m, const char *wname, const char *def); + +const char *jk_get_worker_redirect(jk_map_t *m, const char *wname, const char *def); + +const char *jk_get_worker_secret_key(jk_map_t *m, const char *wname); + +const char *jk_get_lb_session_cookie(jk_map_t *m, const char *wname, const char *def); + +const char *jk_get_lb_session_path(jk_map_t *m, const char *wname, const char *def); + +int jk_get_worker_retries(jk_map_t *m, const char *wname, int def); + +int jk_get_is_worker_disabled(jk_map_t *m, const char *wname); + +int jk_get_is_worker_stopped(jk_map_t *m, const char *wname); + +int jk_get_worker_activation(jk_map_t *m, const char *wname); + +int jk_get_worker_list(jk_map_t *m, char ***list, unsigned *num_of_workers); + +int jk_get_lb_factor(jk_map_t *m, const char *wname); + +int jk_get_distance(jk_map_t *m, const char *wname); + +int jk_get_is_sticky_session(jk_map_t *m, const char *wname); + +int jk_get_is_sticky_session_force(jk_map_t *m, const char *wname); + +int jk_get_lb_method(jk_map_t *m, const char *wname); + +int jk_get_lb_lock(jk_map_t *m, const char *wname); + +int jk_get_lb_worker_list(jk_map_t *m, + const char *lb_wname, + char ***list, unsigned int *num_of_workers); +int jk_get_worker_mount_list(jk_map_t *m, + const char *wname, + char ***list, unsigned int *num_of_maps); +const char *jk_get_worker_secret(jk_map_t *m, const char *wname); + +int jk_get_worker_mx(jk_map_t *m, const char *wname, unsigned *mx); + +int jk_get_worker_ms(jk_map_t *m, const char *wname, unsigned *ms); + +int jk_get_worker_classpath(jk_map_t *m, const char *wname, const char **cp); + + +int jk_get_worker_bridge_type(jk_map_t *m, const char *wname, unsigned *bt); + +int jk_get_worker_jvm_path(jk_map_t *m, const char *wname, const char **vm_path); + +int jk_get_worker_callback_dll(jk_map_t *m, + const char *wname, const char **cb_path); + +int jk_get_worker_cmd_line(jk_map_t *m, const char *wname, const char **cmd_line); + +int jk_file_exists(const char *f); + +int jk_is_list_property(const char *prp_name); + +int jk_is_path_property(const char *prp_name); + +int jk_is_cmd_line_property(const char *prp_name); + +int jk_is_unique_property(const char *prp_name); + +int jk_is_deprecated_property(const char *prp_name); + +int jk_is_valid_property(const char *prp_name); + +int jk_get_worker_stdout(jk_map_t *m, const char *wname, const char **stdout_name); + +int jk_get_worker_stderr(jk_map_t *m, const char *wname, const char **stderr_name); + +int jk_get_worker_sysprops(jk_map_t *m, const char *wname, const char **sysprops); + +int jk_get_worker_libpath(jk_map_t *m, const char *wname, const char **libpath); + +char **jk_parse_sysprops(jk_pool_t *p, const char *sysprops); + + +void jk_append_libpath(jk_pool_t *p, const char *libpath); + +void jk_set_worker_def_cache_size(int sz); + +int jk_get_worker_def_cache_size(int protocol); + +int jk_get_worker_maintain_time(jk_map_t *m); + +int jk_get_max_packet_size(jk_map_t *m, const char *wname); + +const char *jk_get_worker_style_sheet(jk_map_t *m, const char *wname, const char *def); + +int jk_get_is_read_only(jk_map_t *m, const char *wname); + +int jk_get_worker_user_list(jk_map_t *m, + const char *wname, + char ***list, unsigned int *num); + +int jk_get_worker_good_rating(jk_map_t *m, + const char *wname, + char ***list, unsigned int *num); + +int jk_get_worker_bad_rating(jk_map_t *m, + const char *wname, + char ***list, unsigned int *num); + +const char *jk_get_worker_name_space(jk_map_t *m, const char *wname, const char *def); + +const char *jk_get_worker_xmlns(jk_map_t *m, const char *wname, const char *def); + +const char *jk_get_worker_xml_doctype(jk_map_t *m, const char *wname, const char *def); + +const char *jk_get_worker_prop_prefix(jk_map_t *m, const char *wname, const char *def); + +int jk_get_worker_fail_on_status(jk_map_t *m, const char *wname, + int *list, unsigned int list_size); + +int jk_get_worker_user_case_insensitive(jk_map_t *m, const char *wname); + +int is_http_status_fail(unsigned int http_status_fail_num, + int *http_status_fail, int status); + +int jk_wildchar_match(const char *str, const char *exp, int icase); + +#define TC32_BRIDGE_TYPE 32 +#define TC33_BRIDGE_TYPE 33 +#define TC40_BRIDGE_TYPE 40 +#define TC41_BRIDGE_TYPE 41 +#define TC50_BRIDGE_TYPE 50 + +#ifdef AS400 + +#define S_IFREG _S_IFREG + +#ifdef AS400_UTF8 + +void jk_ascii2ebcdic(char *src, char *dst); +void jk_ebcdic2ascii(char *src, char *dst); + +#endif /* AS400_UTF8 */ + +#endif + +/* i5/OS V5R4 need ASCII-EBCDIC conversion before stat() call */ +/* added a stat() mapper function, jk_stat, for such purpose */ + +int jk_stat(const char *f, struct stat * statbuf); + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _JK_UTIL_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_util.lo b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_util.lo new file mode 100644 index 00000000..a7acb278 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_util.lo @@ -0,0 +1,12 @@ +# jk_util.lo - a libtool object file +# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/jk_util.o' + +# Name of the non-PIC object. +non_pic_object='jk_util.o' + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_util.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_util.o Binary files differnew file mode 100644 index 00000000..5d343b71 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_util.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_version.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_version.h new file mode 100644 index 00000000..9cbba921 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_version.h @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: JK version header file * + * Version: $Revision: 1141394 $ * + ***************************************************************************/ + +#ifndef __JK_VERSION_H +#define __JK_VERSION_H + +/************** START OF AREA TO MODIFY BEFORE RELEASING *************/ +#define JK_VERMAJOR 1 +#define JK_VERMINOR 2 +#define JK_VERFIX 32 + +/* set JK_VERISRELEASE to 1 when release (do not forget to commit!) */ +#define JK_VERISRELEASE 1 +/* Beta number */ +#define JK_VERBETA 0 +#define JK_BETASTRING "0" +/* Release candidate */ +#define JK_VERRC 0 +#define JK_RCSTRING "0" +/* Source Control Revision as a suffix, e.g. "-r12345" */ +#define JK_REVISION " ()" + +/************** END OF AREA TO MODIFY BEFORE RELEASING *************/ + +#if !defined(PACKAGE) +#if defined(JK_ISAPI) +#define PACKAGE "isapi_redirector" +#define JK_DLL_SUFFIX "dll" +#elif defined(JK_NSAPI) +#define PACKAGE "nsapi_redirector" +#define JK_DLL_SUFFIX "dll" +#else +#define PACKAGE "mod_jk" +#define JK_DLL_SUFFIX "so" +#endif +#endif + +/* Build JK_EXPOSED_VERSION and JK_VERSION */ +#define JK_EXPOSED_VERSION_INT PACKAGE "/" JK_VERSTRING + +#if (JK_VERBETA != 0) +#define JK_EXPOSED_VERSION JK_EXPOSED_VERSION_INT "-beta-" JK_BETASTRING +#else +#undef JK_VERBETA +#define JK_VERBETA 255 +#if (JK_VERRC != 0) +#define JK_EXPOSED_VERSION JK_EXPOSED_VERSION_INT "-rc-" JK_RCSTRING +#elif (JK_VERISRELEASE == 1) +#define JK_EXPOSED_VERSION JK_EXPOSED_VERSION_INT +#else +#define JK_EXPOSED_VERSION JK_EXPOSED_VERSION_INT "-dev" JK_REVISION +#endif +#endif +#define JK_FULL_EXPOSED_VERSION JK_EXPOSED_VERSION JK_REVISION + +#define JK_MAKEVERSION(major, minor, fix, beta) \ + (((major) << 24) + ((minor) << 16) + ((fix) << 8) + (beta)) + +#define JK_VERSION JK_MAKEVERSION(JK_VERMAJOR, JK_VERMINOR, JK_VERFIX, JK_VERBETA) + +/** Properly quote a value as a string in the C preprocessor */ +#define JK_STRINGIFY(n) JK_STRINGIFY_HELPER(n) +/** Helper macro for JK_STRINGIFY */ +#define JK_STRINGIFY_HELPER(n) #n +#define JK_VERSTRING \ + JK_STRINGIFY(JK_VERMAJOR) "." \ + JK_STRINGIFY(JK_VERMINOR) "." \ + JK_STRINGIFY(JK_VERFIX) + +/* macro for Win32 .rc files using numeric csv representation */ +#define JK_VERSIONCSV JK_VERMAJOR ##, \ + ##JK_VERMINOR ##, \ + ##JK_VERFIX + + +#endif /* __JK_VERSION_H */ + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_worker.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_worker.c new file mode 100644 index 00000000..b75ae933 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_worker.c @@ -0,0 +1,351 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Workers controller * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Author: Henri Gomez <hgomez@apache.org> * + * Version: $Revision: 708019 $ * + ***************************************************************************/ + +#define _PLACE_WORKER_LIST_HERE +#include "jk_worker_list.h" +#include "jk_worker.h" +#include "jk_util.h" +#include "jk_mt.h" + +static void close_workers(jk_logger_t *l); + +static worker_factory get_factory_for(const char *type); + +static int build_worker_map(jk_map_t *init_data, + char **worker_list, + unsigned num_of_workers, + jk_worker_env_t *we, jk_logger_t *l); + +/* Global worker list */ +static jk_map_t *worker_map; +#if _MT_CODE +static JK_CRIT_SEC worker_lock; +#endif +static int worker_maintain_time = 0; + +int wc_open(jk_map_t *init_data, jk_worker_env_t *we, jk_logger_t *l) +{ + int rc; + JK_TRACE_ENTER(l); + + if (!jk_map_alloc(&worker_map)) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + JK_INIT_CS(&worker_lock, rc); + if (rc == JK_FALSE) { + jk_log(l, JK_LOG_ERROR, + "creating thread lock (errno=%d)", + errno); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + jk_map_dump(init_data, l); + we->init_data = init_data; + if (!jk_get_worker_list(init_data, &(we->worker_list), + &we->num_of_workers)) { + JK_TRACE_EXIT(l); + we->num_of_workers = 0; + we->worker_list = NULL; + return JK_FALSE; + } + + worker_maintain_time = jk_get_worker_maintain_time(init_data); + if(worker_maintain_time < 0) + worker_maintain_time = 0; + + if (!build_worker_map(init_data, we->worker_list, + we->num_of_workers, we, l)) { + close_workers(l); + we->num_of_workers = 0; + we->worker_list = NULL; + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + + +void wc_close(jk_logger_t *l) +{ + int rc; + JK_TRACE_ENTER(l); + JK_DELETE_CS(&worker_lock, rc); + close_workers(l); + JK_TRACE_EXIT(l); +} + +jk_worker_t *wc_get_worker_for_name(const char *name, jk_logger_t *l) +{ + jk_worker_t *rc; + + JK_TRACE_ENTER(l); + if (!name) { + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return NULL; + } + + rc = jk_map_get(worker_map, name, NULL); + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, "%s a worker %s", + rc ? "found" : "did not find", name); + JK_TRACE_EXIT(l); + return rc; +} + +int wc_create_worker(const char *name, int use_map, + jk_map_t *init_data, + jk_worker_t **rc, jk_worker_env_t *we, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + if (rc) { + const char *type = jk_get_worker_type(init_data, name); + worker_factory fac = get_factory_for(type); + jk_worker_t *w = NULL; + unsigned int i, num_of_maps; + char **map_names; + int wtype; + + *rc = NULL; + + if (!fac) { + jk_log(l, JK_LOG_ERROR, "Unknown worker type %s for worker %s", + type, name); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "about to create instance %s of %s", name, + type); + + if (((wtype = fac(&w, name, l)) == 0) || !w) { + jk_log(l, JK_LOG_ERROR, + "factory for %s failed for %s", type, + name); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "about to validate and init %s", name); + if (!w->validate(w, init_data, we, l)) { + w->destroy(&w, l); + jk_log(l, JK_LOG_ERROR, + "validate failed for %s", name); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (!w->init(w, init_data, we, l)) { + w->destroy(&w, l); + jk_log(l, JK_LOG_ERROR, "init failed for %s", + name); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + if (use_map && + jk_get_worker_mount_list(init_data, name, + &map_names, + &num_of_maps) && num_of_maps) { + for (i = 0; i < num_of_maps; i++) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "mounting %s to worker %s", + map_names[i], name); + if (uri_worker_map_add(we->uri_to_worker, map_names[i], + name, SOURCE_TYPE_WORKERDEF, l) == JK_FALSE) { + w->destroy(&w, l); + jk_log(l, JK_LOG_ERROR, + "mounting %s failed for %s", + map_names[i], name); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + } + w->type = wtype; + *rc = w; + JK_TRACE_EXIT(l); + return JK_TRUE; + } + + JK_LOG_NULL_PARAMS(l); + return JK_FALSE; +} + +static void close_workers(jk_logger_t *l) +{ + int sz = jk_map_size(worker_map); + + JK_TRACE_ENTER(l); + + if (sz > 0) { + int i; + for (i = 0; i < sz; i++) { + jk_worker_t *w = jk_map_value_at(worker_map, i); + if (w) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "close_workers will destroy worker %s", + jk_map_name_at(worker_map, i)); + w->destroy(&w, l); + } + } + } + jk_map_free(&worker_map); + JK_TRACE_EXIT(l); +} + +static int build_worker_map(jk_map_t *init_data, + char **worker_list, + unsigned num_of_workers, + jk_worker_env_t *we, jk_logger_t *l) +{ + unsigned i; + + JK_TRACE_ENTER(l); + + for (i = 0; i < num_of_workers; i++) { + jk_worker_t *w = NULL; + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "creating worker %s", worker_list[i]); + + if (wc_create_worker(worker_list[i], 1, init_data, &w, we, l)) { + jk_worker_t *oldw = NULL; + if (!jk_map_put(worker_map, worker_list[i], w, (void *)&oldw)) { + w->destroy(&w, l); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (oldw) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "removing old %s worker", + worker_list[i]); + oldw->destroy(&oldw, l); + } + } + else { + jk_log(l, JK_LOG_ERROR, + "failed to create worker %s", + worker_list[i]); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + } + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +static worker_factory get_factory_for(const char *type) +{ + worker_factory_record_t *factory = &worker_factories[0]; + while (factory->name) { + if (0 == strcmp(factory->name, type)) { + return factory->fac; + } + + factory++; + } + + return NULL; +} + +const char *wc_get_name_for_type(int type, jk_logger_t *l) +{ + worker_factory_record_t *factory = &worker_factories[0]; + while (factory->name) { + if (type == factory->type) { + jk_log(l, JK_LOG_DEBUG, + "Found worker type '%s'", + factory->name); + return factory->name; + } + + factory++; + } + + return NULL; +} + +void wc_maintain(jk_logger_t *l) +{ + static time_t last_maintain = 0; + static int running_maintain = 0; + int sz = jk_map_size(worker_map); + + JK_TRACE_ENTER(l); + + /* Only proceed if all of the below hold true: + * - there are workers + * - maintenance wasn't disabled by configuration + * - time since last maintenance is big enough + */ + if (sz > 0 && worker_maintain_time > 0 && + difftime(time(NULL), last_maintain) >= worker_maintain_time) { + int i; + JK_ENTER_CS(&worker_lock, i); + if (running_maintain || + difftime(time(NULL), last_maintain) < worker_maintain_time) { + /* Already in maintain */ + JK_LEAVE_CS(&worker_lock, i); + JK_TRACE_EXIT(l); + return; + } + /* Set the maintain run flag so other threads skip + * the maintain until we are finished. + */ + running_maintain = 1; + JK_LEAVE_CS(&worker_lock, i); + + for (i = 0; i < sz; i++) { + jk_worker_t *w = jk_map_value_at(worker_map, i); + if (w && w->maintain) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Maintaining worker %s", + jk_map_name_at(worker_map, i)); + w->maintain(w, time(NULL), l); + } + } + JK_ENTER_CS(&worker_lock, i); + last_maintain = time(NULL); + running_maintain = 0; + JK_LEAVE_CS(&worker_lock, i); + } + JK_TRACE_EXIT(l); +} diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_worker.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_worker.h new file mode 100644 index 00000000..18e9097c --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_worker.h @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Workers controller header file * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Version: $Revision: 466585 $ * + ***************************************************************************/ + +#ifndef JK_WORKER_H +#define JK_WORKER_H + +#include "jk_logger.h" +#include "jk_service.h" +#include "jk_map.h" +#include "jk_uri_worker_map.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +int wc_open(jk_map_t *init_data, jk_worker_env_t *we, jk_logger_t *l); + +void wc_close(jk_logger_t *l); + +jk_worker_t *wc_get_worker_for_name(const char *name, jk_logger_t *l); + +const char *wc_get_name_for_type(int type, jk_logger_t *l); + +int wc_create_worker(const char *name, int use_map, + jk_map_t *init_data, + jk_worker_t **rc, + jk_worker_env_t *we, jk_logger_t *l); + +void wc_maintain(jk_logger_t *l); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* JK_WORKER_H */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_worker.lo b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_worker.lo new file mode 100644 index 00000000..45a6af4b --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_worker.lo @@ -0,0 +1,12 @@ +# jk_worker.lo - a libtool object file +# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/jk_worker.o' + +# Name of the non-PIC object. +non_pic_object='jk_worker.o' + diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_worker.o b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_worker.o Binary files differnew file mode 100644 index 00000000..756f2510 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_worker.o diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_worker_list.h b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_worker_list.h new file mode 100644 index 00000000..59518b2a --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_worker_list.h @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Worker list * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Author: Henri Gomez <hgomez@apache.org> * + * Version: $Revision: 466585 $ * + ***************************************************************************/ + +/* + * This file includes a list of all the possible workers in the jk library + * plus their factories. + * + * If you want to add a worker just place it in the worker_factories array + * with its unique name and factory. + * + * If you want to remove a worker, hjust comment out its line in the + * worker_factories array as well as its header file. For example, look + * at what we have done to the ajp23 worker. + * + * Note: This file should be included only in the jk_worker controller. + * Currently the jk_worker controller is located in jk_worker.c + */ +#ifdef _PLACE_WORKER_LIST_HERE +#ifndef _JK_WORKER_LIST_H +#define _JK_WORKER_LIST_H + +#include "jk_ajp12_worker.h" +#include "jk_ajp13_worker.h" +#include "jk_ajp14_worker.h" +#ifdef HAVE_JNI +#include "jk_jni_worker.h" +#endif +#include "jk_lb_worker.h" +#include "jk_status.h" + +struct worker_factory_record +{ + const char *name; + int type; + worker_factory fac; +}; +typedef struct worker_factory_record worker_factory_record_t; + +static worker_factory_record_t worker_factories[] = { + /* + * AJPv12 worker, this is the stable worker. + */ + {JK_AJP12_WORKER_NAME, JK_AJP12_WORKER_TYPE, ajp12_worker_factory}, + /* + * AJPv13 worker, fast bi-directional worker. + */ + {JK_AJP13_WORKER_NAME, JK_AJP13_WORKER_TYPE, ajp13_worker_factory}, + /* + * AJPv14 worker, next generation fast bi-directional worker. + */ + {JK_AJP14_WORKER_NAME, JK_AJP14_WORKER_TYPE, ajp14_worker_factory}, + /* + * In process JNI based worker. Requires the server to be + * multithreaded and to use native threads. + */ +#ifdef HAVE_JNI + {JK_JNI_WORKER_NAME, JK_JNI_WORKER_TYPE, jni_worker_factory}, +#endif + /* + * Load balancing worker. Performs round robin with sticky + * session load balancing. + */ + {JK_LB_WORKER_NAME, JK_LB_WORKER_TYPE, lb_worker_factory}, + + /* + * Status worker. Performs display display and + * worker management. + */ + {JK_STATUS_WORKER_NAME, JK_STATUS_WORKER_TYPE, status_worker_factory}, + + /* + * Marks the end of the worker factory list. + */ + {NULL, 0, NULL} +}; +#endif /* _JK_WORKER_LIST_H */ +#endif /* _PLACE_WORKER_LIST_HERE */ diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/list.mk b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/list.mk new file mode 100644 index 00000000..51fa1e0e --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/list.mk @@ -0,0 +1,27 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +## Object needed for mod_jk for Apache-1.3 +APACHE_OBJECTS= ${JK}jk_ajp12_worker${OEXT} ${JK}jk_connect${OEXT} \ + ${JK}jk_msg_buff${OEXT} ${JK}jk_util${OEXT} \ + ${JK}jk_ajp13${OEXT} ${JK}jk_pool${OEXT} \ + ${JK}jk_worker${OEXT} ${JK}jk_ajp13_worker${OEXT} \ + ${JK}jk_lb_worker${OEXT} ${JK}jk_sockbuf${OEXT} \ + ${JK}jk_map${OEXT} ${JK}jk_uri_worker_map${OEXT} \ + ${JK}jk_ajp14${OEXT} ${JK}jk_ajp14_worker${OEXT} \ + ${JK}jk_md5${OEXT} ${JK}jk_shm${OEXT} ${JK}jk_jni_worker${OEXT} \ + ${JK}jk_ajp_common${OEXT} ${JK}jk_context${OEXT} \ + ${JK}jk_url${OEXT} \ + ${JK}jk_status${OEXT} diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/list.mk.in b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/list.mk.in new file mode 100644 index 00000000..abc7ffe5 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/list.mk.in @@ -0,0 +1,27 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +## Object needed for mod_jk for Apache-1.3 +APACHE_OBJECTS= ${JK}jk_ajp12_worker${OEXT} ${JK}jk_connect${OEXT} \ + ${JK}jk_msg_buff${OEXT} ${JK}jk_util${OEXT} \ + ${JK}jk_ajp13${OEXT} ${JK}jk_pool${OEXT} \ + ${JK}jk_worker${OEXT} ${JK}jk_ajp13_worker${OEXT} \ + ${JK}jk_lb_worker${OEXT} ${JK}jk_sockbuf${OEXT} \ + ${JK}jk_map${OEXT} ${JK}jk_uri_worker_map${OEXT} \ + ${JK}jk_ajp14${OEXT} ${JK}jk_ajp14_worker${OEXT} \ + ${JK}jk_md5${OEXT} ${JK}jk_shm${OEXT} @JK_JNI_WORKER@ \ + ${JK}jk_ajp_common${OEXT} ${JK}jk_context${OEXT} \ + ${JK}jk_url${OEXT} \ + ${JK}jk_status${OEXT} diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/stamp-h1 b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/stamp-h1 new file mode 100644 index 00000000..8189b45b --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/stamp-h1 @@ -0,0 +1 @@ +timestamp for common/config.h |