summaryrefslogtreecommitdiffstats
path: root/rubbos/app/tomcat-connectors-1.2.32-src/native/common
diff options
context:
space:
mode:
authorhongbotian <hongbo.tianhongbo@huawei.com>2015-11-30 02:41:33 -0500
committerhongbotian <hongbo.tianhongbo@huawei.com>2015-11-30 02:43:36 -0500
commit9401f816dd0d9d550fe98a8507224bde51c4b847 (patch)
tree94f2d7a7893a787bafdca8b5ef063ea316938874 /rubbos/app/tomcat-connectors-1.2.32-src/native/common
parente8ec7aa8e38a93f5b034ac74cebce5de23710317 (diff)
upload tomcat
JIRA: BOTTLENECK-7 Change-Id: I875d474869efd76ca203c30b60ebc0c3ee606d0e Signed-off-by: hongbotian <hongbo.tianhongbo@huawei.com>
Diffstat (limited to 'rubbos/app/tomcat-connectors-1.2.32-src/native/common')
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.indent.pro18
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp12_worker.obin0 -> 72992 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp13.obin0 -> 11264 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp13_worker.obin0 -> 35280 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp14.obin0 -> 74416 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp14_worker.obin0 -> 70736 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp_common.obin0 -> 291472 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_connect.obin0 -> 84960 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_context.obin0 -> 19080 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_jni_worker.obin0 -> 16128 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_lb_worker.obin0 -> 172368 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_map.obin0 -> 83792 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_md5.obin0 -> 20208 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_msg_buff.obin0 -> 23520 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_pool.obin0 -> 13048 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_shm.obin0 -> 60272 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_sockbuf.obin0 -> 13680 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_status.obin0 -> 828736 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_uri_worker_map.obin0 -> 126944 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_url.obin0 -> 9312 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_util.obin0 -> 244016 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_worker.obin0 -> 55776 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/Makefile49
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/Makefile.in49
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/ap_snprintf.c1178
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/ap_snprintf.h150
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/config.h110
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/config.h.in109
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk.rc74
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp12_worker.c682
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp12_worker.h45
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp12_worker.lo12
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp12_worker.obin0 -> 71160 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13.c50
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13.h126
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13.lo12
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13.obin0 -> 11104 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13_worker.c94
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13_worker.h50
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13_worker.lo12
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13_worker.obin0 -> 35184 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14.c695
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14.h307
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14.lo12
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14.obin0 -> 73016 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14_worker.c404
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14_worker.h52
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14_worker.lo12
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14_worker.obin0 -> 69632 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp_common.c3383
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp_common.h467
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp_common.lo12
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp_common.obin0 -> 283648 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.c1190
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.h78
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.lo12
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.obin0 -> 83736 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_context.c296
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_context.h138
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_context.lo12
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_context.obin0 -> 19176 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_global.h405
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.c1267
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.h45
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.lo12
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.obin0 -> 15984 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_lb_worker.c1823
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_lb_worker.h222
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_lb_worker.lo12
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_lb_worker.obin0 -> 170152 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_logger.h139
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_map.c889
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_map.h95
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_map.lo12
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_map.obin0 -> 90080 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_md5.c475
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_md5.h84
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_md5.lo12
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_md5.obin0 -> 20768 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_msg_buff.c382
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_msg_buff.h154
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_msg_buff.lo12
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_msg_buff.obin0 -> 24304 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_mt.h150
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_nwmain.c103
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_pool.c165
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_pool.h126
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_pool.lo12
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_pool.obin0 -> 12968 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_service.h546
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_shm.c812
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_shm.h258
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_shm.lo12
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_shm.obin0 -> 59384 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_sockbuf.c195
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_sockbuf.h45
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_sockbuf.lo12
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_sockbuf.obin0 -> 13624 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_status.c5200
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_status.h44
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_status.lo12
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_status.obin0 -> 806096 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_types.h69
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_types.h.in69
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.c1191
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.h208
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.lo12
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.obin0 -> 124368 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_url.c124
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_url.h44
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_url.lo12
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_url.obin0 -> 9200 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_util.c2253
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_util.h269
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_util.lo12
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_util.obin0 -> 243024 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_version.h96
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_worker.c351
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_worker.h55
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_worker.lo12
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_worker.obin0 -> 54176 bytes
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_worker_list.h98
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/list.mk27
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/list.mk.in27
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/stamp-h11
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
new file mode 100644
index 00000000..43f069c5
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp12_worker.o
Binary files differ
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
new file mode 100644
index 00000000..65a3b17c
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp13.o
Binary files differ
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
new file mode 100644
index 00000000..6964abbf
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp13_worker.o
Binary files differ
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
new file mode 100644
index 00000000..052f3ef2
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp14.o
Binary files differ
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
new file mode 100644
index 00000000..87fafdbf
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp14_worker.o
Binary files differ
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
new file mode 100644
index 00000000..a20eca35
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_ajp_common.o
Binary files differ
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
new file mode 100644
index 00000000..007bd0d3
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_connect.o
Binary files differ
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
new file mode 100644
index 00000000..48f29a7d
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_context.o
Binary files differ
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
new file mode 100644
index 00000000..01dc3d23
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_jni_worker.o
Binary files differ
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
new file mode 100644
index 00000000..ed0cc246
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_lb_worker.o
Binary files differ
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
new file mode 100644
index 00000000..4ccd1aac
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_map.o
Binary files differ
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
new file mode 100644
index 00000000..b9780541
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_md5.o
Binary files differ
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
new file mode 100644
index 00000000..7b0c05b4
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_msg_buff.o
Binary files differ
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
new file mode 100644
index 00000000..52c12aa9
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_pool.o
Binary files differ
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
new file mode 100644
index 00000000..96025d9f
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_shm.o
Binary files differ
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
new file mode 100644
index 00000000..248f7d0c
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_sockbuf.o
Binary files differ
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
new file mode 100644
index 00000000..763f6b40
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_status.o
Binary files differ
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
new 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
Binary files differ
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
new file mode 100644
index 00000000..c0d52ee0
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_url.o
Binary files differ
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
new file mode 100644
index 00000000..0bfdc8b4
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_util.o
Binary files differ
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
new file mode 100644
index 00000000..e6530d0d
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/.libs/jk_worker.o
Binary files differ
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
new file mode 100644
index 00000000..3ab1134b
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp12_worker.o
Binary files differ
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
new file mode 100644
index 00000000..872b5f5f
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13.o
Binary files differ
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
new file mode 100644
index 00000000..b8f3d642
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp13_worker.o
Binary files differ
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
new file mode 100644
index 00000000..f3f783c5
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14.o
Binary files differ
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
new file mode 100644
index 00000000..604ad3b1
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp14_worker.o
Binary files differ
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
new file mode 100644
index 00000000..2e6679aa
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_ajp_common.o
Binary files differ
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
new file mode 100644
index 00000000..d33c04e2
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.o
Binary files differ
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
new file mode 100644
index 00000000..88da42a1
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_context.o
Binary files differ
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
new file mode 100644
index 00000000..9f00e3e5
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_jni_worker.o
Binary files differ
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
new file mode 100644
index 00000000..d8b71999
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_lb_worker.o
Binary files differ
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
new file mode 100644
index 00000000..5274ff78
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_map.o
Binary files differ
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
new file mode 100644
index 00000000..d3a98259
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_md5.o
Binary files differ
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
new file mode 100644
index 00000000..3f0a0391
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_msg_buff.o
Binary files differ
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
new file mode 100644
index 00000000..e2e72173
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_pool.o
Binary files differ
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
new file mode 100644
index 00000000..8f02d766
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_shm.o
Binary files differ
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
new file mode 100644
index 00000000..53350c5d
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_sockbuf.o
Binary files differ
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 &#169; 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>&nbsp;</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 ? "&amp;" : "?",
+ 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", "&amp;",
+ 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 ? "&amp;" : "?",
+ JK_STATUS_ARG_MIME, status_mime_text(mime));
+ started=1;
+ }
+ if (worker && worker[0]) {
+ jk_printf(s, "%s%s=%s", started ? "&amp;" : "?",
+ 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 ? "&amp;" : "?",
+ JK_STATUS_ARG_SUB_WORKER, sub_worker);
+ started=1;
+ }
+ if (attribute && attribute[0]) {
+ jk_printf(s, "%s%s=%s", started ? "&amp;" : "?",
+ 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 ? "&amp;" : "?",
+ 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 ? "&amp;" : "?",
+ 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 ? "&amp;" : "?", k, v);
+ started=1;
+ }
+ if (opt | add_options | rm_options)
+ jk_printf(s, "%s%s=%u", started ? "&amp;" : "?",
+ 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 : "&nbsp;") : "&nbsp",
+ wr->domain ? (*wr->domain ? wr->domain : "&nbsp;") : "&nbsp",
+ rs_min,
+ rs_max,
+ delta_reset,
+ rc_time > 0 ? buf_time : "&nbsp;");
+ 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 : "&nbsp;");
+ }
+
+ }
+ 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, "]&nbsp;&nbsp;");
+ 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, "&nbsp;&nbsp;|&nbsp;&nbsp;");
+ 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, "&nbsp;&nbsp;|&nbsp;&nbsp;");
+ 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, "&nbsp;&nbsp;|&nbsp;&nbsp;");
+ 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, "]&nbsp;&nbsp;[");
+ }
+ 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, "&nbsp;</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, "&nbsp;</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, "]&nbsp;&nbsp;");
+ 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>&nbsp;&nbsp;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>&nbsp;&nbsp;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>&nbsp;&nbsp;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>&nbsp;&nbsp;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>&nbsp;&nbsp;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>&nbsp;&nbsp;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>&nbsp;&nbsp;</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>&nbsp;&nbsp;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>&nbsp;&nbsp;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>&nbsp;&nbsp;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:&nbsp;<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, "/>&nbsp;|&nbsp;\n");
+ jk_printf(s, "Disabled:&nbsp;<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, "/>&nbsp;|&nbsp;\n");
+ jk_printf(s, "Stopped:&nbsp;<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>&nbsp;&nbsp;&nbsp;</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>&nbsp;&nbsp;|&nbsp;&nbsp;</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, "]&nbsp;&nbsp;");
+ 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, "]&nbsp;&nbsp;\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, "]&nbsp;&nbsp;\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
new file mode 100644
index 00000000..3db458bf
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_status.o
Binary files differ
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
new file mode 100644
index 00000000..c402e1fc
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.o
Binary files differ
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
new file mode 100644
index 00000000..fd792890
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_url.o
Binary files differ
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
new file mode 100644
index 00000000..5d343b71
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_util.o
Binary files differ
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
new file mode 100644
index 00000000..756f2510
--- /dev/null
+++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_worker.o
Binary files differ
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