Return-Path: Delivered-To: apmail-jakarta-tomcat-dev-archive@jakarta.apache.org Received: (qmail 83269 invoked by uid 500); 26 Mar 2001 22:47:05 -0000 Mailing-List: contact tomcat-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: list-post: Reply-To: tomcat-dev@jakarta.apache.org Delivered-To: mailing list tomcat-dev@jakarta.apache.org Received: (qmail 83260 invoked from network); 26 Mar 2001 22:47:03 -0000 Message-ID: <361024C34A6DD2118689006097AE2B4D0102C95A@css4.cs> From: GOMEZ Henri To: tomcat-dev@jakarta.apache.org Cc: "Dan Milstein (E-mail)" , "Costin Manolache (E-mail)" Subject: RE: ajp13 and tomcat restart - next (final) release + AJ13 PROPOS AL Date: Tue, 27 Mar 2001 00:46:55 +0200 MIME-Version: 1.0 X-Mailer: Internet Mail Service (5.5.2650.21) Content-Type: multipart/mixed; boundary="----_=_NextPart_000_01C0B646.A855F368" X-Spam-Rating: h31.sny.collab.net 1.6.2 0/1000/N This message is in MIME format. Since your mail reader does not understand this format, some or all of this message may not be legible. ------_=_NextPart_000_01C0B646.A855F368 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable >Looks about ready for more general testing. I like the new >ajp13_operation. Two things: > > 1) l. 648 (op->recoverable =3D JK_FALSE). I set op->recoverable to JK_FALSE just after =20 detected upload mode (dropped var) Find included the latest .c since I miss diff cmd under W2K rigth now. Where could we put code in Ajp13Interceptor which could be informed of context load/unload ? I'd like to add context/webapp load/unload=20 =E0 la mod_warp :) will be new cmds in JK : LOADEDCONTEXT + WEBAPP STRING #define JK_AJP13_LOADED_CONTEXT (unsigned char)8 UNLOADEDCONTEXT + WEBAPP STRING #define JK_AJP13_UNLOADED_CONTEXT (unsigned char)9 Another proposal Strongest ACL=20 (LOGIN + SECRET STRING + PROTOCOL SETS) #define JK_AJP13_LOGIN (unsigned char)10 Comments ? ------_=_NextPart_000_01C0B646.A855F368 Content-Type: application/octet-stream; name="jk_ajp13_worker.c" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="jk_ajp13_worker.c" /*=0A= * Copyright (c) 1997-1999 The Java Apache Project. All rights = reserved.=0A= *=0A= * Redistribution and use in source and binary forms, with or = without=0A= * modification, are permitted provided that the following = conditions=0A= * are met:=0A= *=0A= * 1. Redistributions of source code must retain the above copyright=0A= * notice, this list of conditions and the following disclaimer.=0A= *=0A= * 2. Redistributions in binary form must reproduce the above = copyright=0A= * notice, this list of conditions and the following disclaimer = in=0A= * the documentation and/or other materials provided with the=0A= * distribution.=0A= *=0A= * 3. All advertising materials mentioning features or use of this=0A= * software must display the following acknowledgment:=0A= * "This product includes software developed by the Java Apache =0A= * Project for use in the Apache JServ servlet engine project=0A= * ."=0A= *=0A= * 4. The names "Apache JServ", "Apache JServ Servlet Engine" and =0A= * "Java Apache Project" must not be used to endorse or promote = products =0A= * derived from this software without prior written permission.=0A= *=0A= * 5. Products derived from this software may not be called "Apache = JServ"=0A= * nor may "Apache" nor "Apache JServ" appear in their names without = =0A= * prior written permission of the Java Apache Project.=0A= *=0A= * 6. Redistributions of any form whatsoever must retain the = following=0A= * acknowledgment:=0A= * "This product includes software developed by the Java Apache =0A= * Project for use in the Apache JServ servlet engine project=0A= * ."=0A= * =0A= * THIS SOFTWARE IS PROVIDED BY THE JAVA APACHE PROJECT "AS IS" AND = ANY=0A= * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, = THE=0A= * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A = PARTICULAR=0A= * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JAVA APACHE PROJECT = OR=0A= * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,=0A= * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT=0A= * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;=0A= * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)=0A= * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN = CONTRACT,=0A= * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)=0A= * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF = ADVISED=0A= * OF THE POSSIBILITY OF SUCH DAMAGE.=0A= *=0A= * This software consists of voluntary contributions made by many=0A= * individuals on behalf of the Java Apache Group. For more = information=0A= * on the Java Apache Project and the Apache JServ Servlet Engine = project,=0A= * please see .=0A= *=0A= */=0A= =0A= /***********************************************************************= ****=0A= * Description: Bi-directional protocol. = *=0A= * Author: Henri = *=0A= * Author: Gal Shachor = *=0A= * Version: $Revision: 1.5 $ = *=0A= = ************************************************************************= ***/=0A= =0A= #include "jk_pool.h"=0A= #include "jk_connect.h"=0A= #include "jk_util.h"=0A= #include "jk_msg_buff.h"=0A= #include "jk_ajp13.h"=0A= #include "jk_mt.h"=0A= =0A= #define AJP_DEF_HOST ("localhost")=0A= #define AJP_DEF_PORT (8008)=0A= #define READ_BUF_SIZE (8*1024)=0A= #define DEF_RETRY_ATTEMPTS (1)=0A= #define DEF_CACHE_SZ (1)=0A= #define JK_INTERNAL_ERROR (-2)=0A= #define MAX_SEND_BODY_SZ (DEF_BUFFER_SZ - 6)=0A= =0A= struct ajp13_operation;=0A= typedef struct ajp13_operation ajp13_operation_t;=0A= =0A= struct ajp13_endpoint;=0A= typedef struct ajp13_endpoint ajp13_endpoint_t;=0A= =0A= struct ajp13_worker {=0A= struct sockaddr_in worker_inet_addr; /* Contains host and port = */=0A= unsigned connect_retry_attempts;=0A= char *name; =0A= =0A= /*=0A= * Open connections cache...=0A= *=0A= * 1. Critical section object to protect the cache.=0A= * 2. Cache size.=0A= * 3. An array of "open" endpoints.=0A= */=0A= JK_CRIT_SEC cs;=0A= unsigned ep_cache_sz;=0A= ajp13_endpoint_t **ep_cache;=0A= =0A= jk_worker_t worker; =0A= };=0A= typedef struct ajp13_worker ajp13_worker_t;=0A= =0A= struct ajp13_endpoint { =0A= ajp13_worker_t *worker;=0A= =0A= jk_pool_t pool;=0A= jk_pool_atom_t buf[BIG_POOL_SIZE];=0A= =0A= int sd;=0A= int reuse;=0A= jk_endpoint_t endpoint;=0A= =0A= unsigned left_bytes_to_send;=0A= };=0A= =0A= /* =0A= * little struct to avoid multiples ptr passing=0A= * this struct is ready to hold upload file fd=0A= * to add upload persistant storage=0A= */=0A= struct ajp13_operation {=0A= jk_msg_buf_t *request; /* original request storage */=0A= jk_msg_buf_t *reply; /* reply storage (chuncked by ajp13 */=0A= int uploadfd; /* future persistant storage id */=0A= int recoverable; /* if exchange could be conducted on another TC = */=0A= };=0A= =0A= static void reset_endpoint(ajp13_endpoint_t *ep)=0A= {=0A= ep->reuse =3D JK_FALSE; =0A= jk_reset_pool(&(ep->pool));=0A= }=0A= =0A= static void close_endpoint(ajp13_endpoint_t *ep)=0A= {=0A= reset_endpoint(ep);=0A= if(ep->sd > 0) {=0A= jk_close_socket(ep->sd);=0A= } =0A= free(ep);=0A= }=0A= =0A= =0A= static void reuse_connection(ajp13_endpoint_t *ep,=0A= jk_logger_t *l)=0A= {=0A= ajp13_worker_t *w =3D ep->worker;=0A= =0A= if(w->ep_cache_sz) {=0A= int rc;=0A= JK_ENTER_CS(&w->cs, rc);=0A= if(rc) {=0A= unsigned i;=0A= =0A= for(i =3D 0 ; i < w->ep_cache_sz ; i++) {=0A= if(w->ep_cache[i]) {=0A= ep->sd =3D w->ep_cache[i]->sd;=0A= w->ep_cache[i]->sd =3D -1;=0A= close_endpoint(w->ep_cache[i]);=0A= w->ep_cache[i] =3D NULL;=0A= break;=0A= }=0A= }=0A= JK_LEAVE_CS(&w->cs, rc);=0A= }=0A= }=0A= }=0A= =0A= static void connect_to_tomcat(ajp13_endpoint_t *ep,=0A= jk_logger_t *l)=0A= {=0A= unsigned attempt;=0A= =0A= for(attempt =3D 0 ; attempt < ep->worker->connect_retry_attempts ; = attempt++) {=0A= ep->sd =3D jk_open_socket(&ep->worker->worker_inet_addr, =0A= JK_TRUE, =0A= l);=0A= if(ep->sd >=3D 0) {=0A= jk_log(l, =0A= JK_LOG_DEBUG, =0A= "In jk_endpoint_t::connect_to_tomcat, connected sd = =3D %d\n", ep->sd);=0A= return;=0A= }=0A= } =0A= =0A= jk_log(l, =0A= JK_LOG_ERROR, =0A= "In jk_endpoint_t::connect_to_tomcat, failed errno =3D = %d\n", errno);=0A= }=0A= =0A= static int connection_tcp_send_message(ajp13_endpoint_t *ep, =0A= jk_msg_buf_t *msg, =0A= jk_logger_t *l ) =0A= {=0A= jk_b_end(msg);=0A= =0A= if(0 > jk_tcp_socket_sendfull(ep->sd, =0A= jk_b_get_buff(msg),=0A= jk_b_get_len(msg))) {=0A= return JK_FALSE;=0A= }=0A= =0A= return JK_TRUE;=0A= }=0A= =0A= static int connection_tcp_get_message(ajp13_endpoint_t *ep, =0A= jk_msg_buf_t *msg, =0A= jk_logger_t *l) =0A= {=0A= unsigned char head[4];=0A= int rc;=0A= int msglen;=0A= =0A= rc =3D jk_tcp_socket_recvfull(ep->sd, head, 4);=0A= =0A= if(rc < 0) {=0A= jk_log(l, JK_LOG_ERROR, =0A= "connection_tcp_get_message: Error - = jk_tcp_socket_recvfull failed\n");=0A= return JK_FALSE;=0A= }=0A= =0A= if((head[0] !=3D 'A') || (head[1] !=3D 'B' )) {=0A= jk_log(l, JK_LOG_ERROR, =0A= "connection_tcp_get_message: Error - Wrong message = format\n");=0A= return JK_FALSE;=0A= }=0A= =0A= msglen =3D ((head[2]&0xff)<<8);=0A= msglen +=3D (head[3] & 0xFF);=0A= =0A= if(msglen > jk_b_get_size(msg)) {=0A= jk_log(l, JK_LOG_ERROR, =0A= "connection_tcp_get_message: Error - Wrong message = size\n");=0A= return JK_FALSE;=0A= }=0A= =0A= jk_b_set_len(msg, msglen);=0A= jk_b_set_pos(msg, 0); =0A= =0A= rc =3D jk_tcp_socket_recvfull(ep->sd, jk_b_get_buff(msg), = msglen);=0A= if(rc < 0) {=0A= jk_log(l, JK_LOG_ERROR, =0A= "connection_tcp_get_message: Error - = jk_tcp_socket_recvfull failed\n");=0A= return JK_FALSE;=0A= }=0A= =0A= return JK_TRUE;=0A= }=0A= =0A= static int read_fully_from_server(jk_ws_service_t *s, =0A= unsigned char *buf, =0A= unsigned len)=0A= {=0A= unsigned rdlen =3D 0;=0A= =0A= while(rdlen < len) {=0A= unsigned this_time =3D 0;=0A= if(!s->read(s, buf + rdlen, len - rdlen, &this_time)) {=0A= return -1;=0A= }=0A= =0A= if(0 =3D=3D this_time) {=0A= break;=0A= }=0A= rdlen +=3D this_time;=0A= }=0A= =0A= return (int)rdlen;=0A= }=0A= =0A= static int read_into_msg_buff(ajp13_endpoint_t *ep,=0A= jk_ws_service_t *r, =0A= jk_msg_buf_t *msg, =0A= jk_logger_t *l,=0A= unsigned len)=0A= {=0A= unsigned char *read_buf =3D jk_b_get_buff(msg); = =0A= =0A= jk_b_reset(msg);=0A= =0A= read_buf +=3D 4; /* leave some space for the buffer headers */=0A= read_buf +=3D 2; /* leave some space for the read length */=0A= =0A= if(read_fully_from_server(r, read_buf, len) < 0) {=0A= jk_log(l, JK_LOG_ERROR, =0A= "read_into_msg_buff: Error - read_fully_from_server = failed\n");=0A= return JK_FALSE; =0A= } =0A= =0A= ep->left_bytes_to_send -=3D len;=0A= =0A= if(0 !=3D jk_b_append_int(msg, (unsigned short)len)) {=0A= jk_log(l, JK_LOG_ERROR, =0A= "read_into_msg_buff: Error - jk_b_append_int = failed\n");=0A= return JK_FALSE;=0A= }=0A= =0A= jk_b_set_len(msg, jk_b_get_len(msg) + len);=0A= =0A= return JK_TRUE;=0A= }=0A= =0A= static int ajp13_process_callback(jk_msg_buf_t *msg, =0A= ajp13_endpoint_t *ep,=0A= jk_ws_service_t *r, =0A= jk_logger_t *l) =0A= {=0A= int code =3D (int)jk_b_get_byte(msg);=0A= =0A= switch(code) {=0A= case JK_AJP13_SEND_HEADERS:=0A= {=0A= jk_res_data_t res;=0A= if(!ajp13_unmarshal_response(msg,=0A= &res,=0A= &ep->pool,=0A= l)) {=0A= jk_log(l, JK_LOG_ERROR, =0A= "Error ajp13_process_callback - = ajp13_unmarshal_response failed\n");=0A= return JK_AJP13_ERROR;=0A= }=0A= if(!r->start_response(r, =0A= res.status, =0A= res.msg, =0A= (const char * const = *)res.header_names,=0A= (const char * const = *)res.header_values,=0A= res.num_headers)) {=0A= jk_log(l, JK_LOG_ERROR, =0A= "Error ajp13_process_callback - = start_response failed\n");=0A= return JK_INTERNAL_ERROR;=0A= }=0A= }=0A= break;=0A= =0A= case JK_AJP13_SEND_BODY_CHUNK:=0A= {=0A= unsigned len =3D (unsigned)jk_b_get_int(msg);=0A= if(!r->write(r, jk_b_get_buff(msg) + jk_b_get_pos(msg), = len)) {=0A= jk_log(l, JK_LOG_ERROR, =0A= "Error ajp13_process_callback - write = failed\n");=0A= return JK_INTERNAL_ERROR;=0A= }=0A= }=0A= break;=0A= =0A= case JK_AJP13_GET_BODY_CHUNK:=0A= {=0A= unsigned len =3D (unsigned)jk_b_get_int(msg);=0A= =0A= if(len > MAX_SEND_BODY_SZ) {=0A= len =3D MAX_SEND_BODY_SZ;=0A= }=0A= if(len > ep->left_bytes_to_send) {=0A= len =3D ep->left_bytes_to_send;=0A= }=0A= if(len < 0) {=0A= len =3D 0;=0A= }=0A= =0A= /* the right place to add file storage for upload */=0A= if(read_into_msg_buff(ep, r, msg, l, len)) {=0A= r->content_read +=3D len;=0A= return JK_AJP13_HAS_RESPONSE;=0A= } =0A= =0A= jk_log(l, JK_LOG_ERROR, =0A= "Error ajp13_process_callback - read_into_msg_buff = failed\n");=0A= return JK_INTERNAL_ERROR; =0A= }=0A= break;=0A= =0A= case JK_AJP13_END_RESPONSE:=0A= {=0A= ep->reuse =3D (int)jk_b_get_byte(msg);=0A= =0A= if((ep->reuse & 0X01) !=3D ep->reuse) {=0A= /*=0A= * Strange protocol error.=0A= */=0A= ep->reuse =3D JK_FALSE;=0A= }=0A= }=0A= return JK_AJP13_END_RESPONSE;=0A= break;=0A= =0A= default:=0A= jk_log(l, =0A= JK_LOG_ERROR,=0A= "Error ajp13_process_callback - Invalid code: %d\n", = code);=0A= return JK_AJP13_ERROR;=0A= }=0A= =0A= return JK_AJP13_NO_RESPONSE;=0A= }=0A= =0A= /* -------------------- Method -------------------- */=0A= static int JK_METHOD validate(jk_worker_t *pThis,=0A= jk_map_t *props, = =0A= jk_logger_t *l)=0A= {=0A= jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::validate\n");=0A= =0A= if(pThis && pThis->worker_private) { =0A= ajp13_worker_t *p =3D pThis->worker_private;=0A= int port =3D jk_get_worker_port(props, =0A= p->name,=0A= AJP_DEF_PORT);=0A= =0A= char *host =3D jk_get_worker_host(props, =0A= p->name,=0A= AJP_DEF_HOST);=0A= =0A= jk_log(l, =0A= JK_LOG_DEBUG, =0A= "In jk_worker_t::validate for worker %s contact is = %s:%d\n", =0A= p->name, host, port);=0A= =0A= if(port > 1024 && host) {=0A= if(jk_resolve(host, (short)port, &p->worker_inet_addr)) = {=0A= return JK_TRUE;=0A= }=0A= jk_log(l, JK_LOG_ERROR, "In jk_worker_t::validate, resolve = failed\n");=0A= }=0A= jk_log(l, JK_LOG_ERROR, "In jk_worker_t::validate, Error %s = %d\n", host, port);=0A= } else {=0A= jk_log(l, JK_LOG_ERROR, "In jk_worker_t::validate, NULL = parameters\n");=0A= }=0A= =0A= return JK_FALSE;=0A= }=0A= =0A= =0A= static int JK_METHOD init(jk_worker_t *pThis,=0A= jk_map_t *props, =0A= jk_logger_t *l)=0A= {=0A= /* =0A= * start the connection cache=0A= */=0A= jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::init\n");=0A= =0A= if(pThis && pThis->worker_private) { =0A= ajp13_worker_t *p =3D pThis->worker_private;=0A= int cache_sz =3D jk_get_worker_cache_size(props, =0A= p->name,=0A= DEF_CACHE_SZ);=0A= =0A= if(cache_sz > 0) {=0A= p->ep_cache =3D =0A= (ajp13_endpoint_t **)malloc(sizeof(ajp13_endpoint_t *) = * cache_sz);=0A= if(p->ep_cache) {=0A= int i;=0A= p->ep_cache_sz =3D cache_sz;=0A= for(i =3D 0 ; i < cache_sz ; i++) {=0A= p->ep_cache[i] =3D NULL;=0A= }=0A= JK_INIT_CS(&(p->cs), i);=0A= if(i) {=0A= return JK_TRUE;=0A= }=0A= }=0A= } =0A= } else {=0A= jk_log(l, =0A= JK_LOG_ERROR, =0A= "In jk_worker_t::init, NULL parameters\n");=0A= }=0A= =0A= return JK_FALSE;=0A= }=0A= =0A= =0A= static int JK_METHOD destroy(jk_worker_t **pThis,=0A= jk_logger_t *l)=0A= {=0A= jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::destroy\n");=0A= if(pThis && *pThis && (*pThis)->worker_private) {=0A= ajp13_worker_t *private_data =3D (*pThis)->worker_private;=0A= =0A= free(private_data->name);=0A= =0A= if(private_data->ep_cache_sz) {=0A= unsigned i;=0A= for(i =3D 0 ; i < private_data->ep_cache_sz ; i++) {=0A= if(private_data->ep_cache[i]) {=0A= reset_endpoint(private_data->ep_cache[i]);=0A= close_endpoint(private_data->ep_cache[i]);=0A= } =0A= }=0A= free(private_data->ep_cache);=0A= JK_DELETE_CS(&(private_data->cs), i);=0A= }=0A= =0A= free(private_data);=0A= =0A= return JK_TRUE;=0A= }=0A= =0A= jk_log(l, JK_LOG_ERROR, "In jk_worker_t::destroy, NULL = parameters\n");=0A= return JK_FALSE;=0A= }=0A= =0A= =0A= static int JK_METHOD done(jk_endpoint_t **e,=0A= jk_logger_t *l)=0A= {=0A= jk_log(l, JK_LOG_DEBUG, "Into jk_endpoint_t::done\n");=0A= if(e && *e && (*e)->endpoint_private) {=0A= ajp13_endpoint_t *p =3D (*e)->endpoint_private;=0A= int reuse_ep =3D p->reuse;=0A= =0A= reset_endpoint(p);=0A= =0A= if(reuse_ep) {=0A= ajp13_worker_t *w =3D p->worker;=0A= if(w->ep_cache_sz) {=0A= int rc;=0A= JK_ENTER_CS(&w->cs, rc);=0A= if(rc) {=0A= unsigned i;=0A= =0A= for(i =3D 0 ; i < w->ep_cache_sz ; i++) {=0A= if(!w->ep_cache[i]) {=0A= w->ep_cache[i] =3D p;=0A= break;=0A= }=0A= }=0A= JK_LEAVE_CS(&w->cs, rc);=0A= if(i < w->ep_cache_sz) {=0A= return JK_TRUE;=0A= }=0A= }=0A= }=0A= }=0A= =0A= close_endpoint(p);=0A= *e =3D NULL;=0A= =0A= return JK_TRUE;=0A= }=0A= =0A= jk_log(l, =0A= JK_LOG_ERROR, =0A= "In jk_endpoint_t::done, NULL parameters\n");=0A= return JK_FALSE;=0A= }=0A= =0A= /*=0A= * send request to Tomcat via Ajp13=0A= * - first try to find reuseable socket=0A= * - if no one available, try to connect=0A= * - send request, but send must be see as asynchronous,=0A= * since send() call will return noerror about 95% of time=0A= * Hopefully we'll get more information on next read.=0A= * =0A= * nb: reqmsg is the original request msg buffer=0A= * repmsg is the reply msg buffer which could be scratched=0A= */=0A= static int send_request(jk_endpoint_t *e,=0A= jk_ws_service_t *s,=0A= jk_logger_t *l,=0A= ajp13_endpoint_t *p,=0A= ajp13_operation_t *op)=0A= {=0A= /*=0A= * First try to reuse open connections...=0A= */=0A= while((p->sd > 0) && !connection_tcp_send_message(p, op->request, l)) = {=0A= jk_log(l, JK_LOG_ERROR, "Error sending request try another pooled = connection\n");=0A= jk_close_socket(p->sd);=0A= p->sd =3D -1;=0A= reuse_connection(p, l);=0A= }=0A= =0A= /*=0A= * If we failed to reuse a connection, try to reconnect.=0A= */=0A= if(p->sd < 0) {=0A= connect_to_tomcat(p, l);=0A= if(p->sd >=3D 0) {=0A= /*=0A= * After we are connected, each error that we are going to=0A= * have is probably unrecoverable=0A= */=0A= op->recoverable =3D JK_FALSE;=0A= if(!connection_tcp_send_message(p, op->request, l)) {=0A= jk_log(l, JK_LOG_ERROR, "Error sending request on a fresh = connection\n");=0A= return JK_FALSE;=0A= }=0A= } else {=0A= jk_log(l, JK_LOG_ERROR, "Error connecting to the Tomcat = process.\n");=0A= return JK_FALSE;=0A= }=0A= }=0A= =0A= /*=0A= * From now on an error means that we have an internal server error=0A= * or Tomcat crashed. In any case we cannot recover this.=0A= */=0A= op->recoverable =3D JK_FALSE;=0A= =0A= if(p->left_bytes_to_send > 0) {=0A= unsigned len =3D p->left_bytes_to_send;=0A= if(len > MAX_SEND_BODY_SZ) =0A= len =3D MAX_SEND_BODY_SZ;=0A= if(!read_into_msg_buff(p, s, op->reply, l, len)) =0A= return JK_FALSE;=0A= s->content_read =3D len;=0A= if(!connection_tcp_send_message(p, op->reply, l)) {=0A= jk_log(l, JK_LOG_ERROR, "Error sending request body\n");=0A= return JK_FALSE;=0A= } =0A= }=0A= =0A= return (JK_TRUE);=0A= }=0A= =0A= /*=0A= * get replies from Tomcat via Ajp13=0A= * We will know only at read time if the remote host closed=0A= * the connection (half-closed state - FIN-WAIT2). In that case=0A= * we must close our side of the socket and abort emission.=0A= * We will need another connection to send the request=0A= * There is need of refactoring here since we mix =0A= * reply reception (tomcat -> apache) and request send (apache -> = tomcat)=0A= * and everything using the same buffer (repmsg)=0A= * ajp13 is async but handling read/send this way prevent nice = recovery=0A= * In fact if tomcat link is broken during upload (browser -> apache -> = tomcat)=0A= * we'll loose data and we'll have to abort the whole request.=0A= */=0A= static int get_reply(jk_endpoint_t *e,=0A= jk_ws_service_t *s,=0A= jk_logger_t *l,=0A= ajp13_endpoint_t *p,=0A= ajp13_operation_t *op)=0A= {=0A= /* Start read all reply message */=0A= while(1) {=0A= int rc =3D 0;=0A= =0A= if(!connection_tcp_get_message(p, op->reply, l)) {=0A= jk_log(l, JK_LOG_ERROR, "Error reading reply\n");=0A= /* we just can't recover, unset recover flag */=0A= return JK_FALSE;=0A= }=0A= =0A= rc =3D ajp13_process_callback(op->reply, p, s, l);=0A= =0A= /* no more data to be sent, fine we have finish here */=0A= if(JK_AJP13_END_RESPONSE =3D=3D rc)=0A= return JK_TRUE;=0A= else if(JK_AJP13_HAS_RESPONSE =3D=3D rc) {=0A= /* =0A= * in upload-mode there is no second chance since=0A= * we may have allready send part of uploaded data =0A= * to Tomcat.=0A= * In this case if Tomcat connection is broken we must =0A= * abort request and indicate error.=0A= * A possible work-around could be to store the uploaded=0A= * data to file and replay for it=0A= */=0A= op->recoverable =3D JK_FALSE; =0A= rc =3D connection_tcp_send_message(p, op->reply, l);=0A= if (rc < 0) {=0A= jk_log(l, JK_LOG_ERROR, "Error sending request data %d\n", rc);=0A= return JK_FALSE;=0A= }=0A= } else if(rc < 0) {=0A= return (JK_FALSE); /* XXX error */=0A= }=0A= }=0A= }=0A= =0A= #define JK_RETRIES 3=0A= =0A= /*=0A= * service is now splitted in send_request and get_reply=0A= * much more easier to do errors recovery=0A= */=0A= static int JK_METHOD service(jk_endpoint_t *e, =0A= jk_ws_service_t *s,=0A= jk_logger_t *l,=0A= int *is_recoverable_error)=0A= {=0A= int i;=0A= ajp13_operation_t oper;=0A= ajp13_operation_t *op =3D &oper;=0A= =0A= jk_log(l, JK_LOG_DEBUG, "Into jk_endpoint_t::service\n");=0A= =0A= if(e && e->endpoint_private && s && is_recoverable_error) {=0A= ajp13_endpoint_t *p =3D e->endpoint_private;=0A= op->request =3D jk_b_new(&(p->pool));=0A= jk_b_set_buffer_size(op->request, DEF_BUFFER_SZ); =0A= jk_b_reset(op->request);=0A= =0A= op->reply =3D jk_b_new(&(p->pool));=0A= jk_b_set_buffer_size(op->reply, DEF_BUFFER_SZ);=0A= jk_b_reset(op->reply); =0A= =0A= op->recoverable =3D JK_TRUE;=0A= op->uploadfd =3D -1; /* not yet used, later ;) */=0A= =0A= p->left_bytes_to_send =3D s->content_length;=0A= p->reuse =3D JK_FALSE;=0A= *is_recoverable_error =3D JK_TRUE;=0A= =0A= /* =0A= * We get here initial request (in reqmsg)=0A= */=0A= if(!ajp13_marshal_into_msgb(op->request, s, l)) {=0A= *is_recoverable_error =3D JK_FALSE; =0A= return JK_FALSE;=0A= }=0A= =0A= /* =0A= * JK_RETRIES could be replaced by the number of workers in=0A= * a load-balancing configuration =0A= */=0A= for (i =3D 0; i < JK_RETRIES; i++)=0A= {=0A= /*=0A= * We're using reqmsg which hold initial request=0A= * if Tomcat is stopped or restarted, we will pass reqmsg=0A= * to next valid tomcat. =0A= */=0A= if (! send_request(e, s, l, p, op)) {=0A= jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::service, send_request = failed in send loop %d\n", i);=0A= continue;=0A= }=0A= =0A= /* Up to there we can recover */=0A= *is_recoverable_error =3D JK_TRUE;=0A= op->recoverable =3D JK_TRUE;=0A= =0A= if (get_reply(e, s, l, p, op))=0A= return (JK_TRUE);=0A= =0A= /* if we can't get reply, check if no recover flag was set =0A= * if is_recoverable_error is cleared, we have started received =0A= * upload data and we must consider that operation is no more = recoverable=0A= */=0A= if (! op->recoverable) {=0A= *is_recoverable_error =3D JK_FALSE;=0A= jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::service, get_reply = failed without recovery in send loop %d\n", i);=0A= return JK_FALSE;=0A= }=0A= =0A= jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::service, get_reply failed = in send loop %d\n", i);=0A= =0A= jk_close_socket(p->sd);=0A= p->sd =3D -1;=0A= reuse_connection(p, l);=0A= }=0A= } else {=0A= jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::service, NULL = parameters\n");=0A= }=0A= =0A= return JK_FALSE;=0A= }=0A= =0A= static int JK_METHOD get_endpoint(jk_worker_t *pThis,=0A= jk_endpoint_t **pend,=0A= jk_logger_t *l)=0A= {=0A= jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::get_endpoint\n");=0A= =0A= if(pThis && pThis->worker_private && pend) { =0A= ajp13_worker_t *p =3D pThis->worker_private;=0A= ajp13_endpoint_t *ep =3D NULL;=0A= =0A= if(p->ep_cache_sz) {=0A= int rc;=0A= JK_ENTER_CS(&p->cs, rc);=0A= if(rc) {=0A= unsigned i;=0A= =0A= for(i =3D 0 ; i < p->ep_cache_sz ; i++) {=0A= if(p->ep_cache[i]) {=0A= ep =3D p->ep_cache[i];=0A= p->ep_cache[i] =3D NULL;=0A= break;=0A= }=0A= }=0A= JK_LEAVE_CS(&p->cs, rc);=0A= if(ep) {=0A= *pend =3D &ep->endpoint;=0A= return JK_TRUE;=0A= }=0A= }=0A= } =0A= =0A= ep =3D (ajp13_endpoint_t *)malloc(sizeof(ajp13_endpoint_t));=0A= if(ep) {=0A= ep->sd =3D -1; =0A= ep->reuse =3D JK_FALSE;=0A= jk_open_pool(&ep->pool, ep->buf, sizeof(ep->buf));=0A= ep->worker =3D pThis->worker_private;=0A= ep->endpoint.endpoint_private =3D ep;=0A= ep->endpoint.service =3D service;=0A= ep->endpoint.done =3D done;=0A= *pend =3D &ep->endpoint;=0A= return JK_TRUE;=0A= }=0A= jk_log(l, JK_LOG_ERROR, "In jk_worker_t::get_endpoint, malloc = failed\n");=0A= } else {=0A= jk_log(l, JK_LOG_ERROR, "In jk_worker_t::get_endpoint, NULL = parameters\n");=0A= }=0A= =0A= return JK_FALSE;=0A= }=0A= =0A= =0A= =0A= int JK_METHOD ajp13_worker_factory(jk_worker_t **w,=0A= const char *name,=0A= jk_logger_t *l)=0A= {=0A= ajp13_worker_t *private_data =3D =0A= (ajp13_worker_t *)malloc(sizeof(ajp13_worker_t));=0A= =0A= jk_log(l, =0A= JK_LOG_DEBUG, =0A= "Into ajp13_worker_factory\n");=0A= if(NULL =3D=3D name || NULL =3D=3D w) {=0A= jk_log(l, =0A= JK_LOG_ERROR, =0A= "In ajp13_worker_factory, NULL parameters\n");=0A= return JK_FALSE;=0A= }=0A= =0A= if(!private_data) {=0A= jk_log(l, JK_LOG_ERROR, "In ajp13_worker_factory, NULL = parameters\n");=0A= return JK_FALSE;=0A= }=0A= =0A= private_data->name =3D strdup(name); =0A= =0A= if(!private_data->name) {=0A= free(private_data);=0A= jk_log(l, JK_LOG_ERROR, "In ajp13_worker_factory, malloc = failed\n");=0A= return JK_FALSE;=0A= } =0A= =0A= =0A= private_data->ep_cache_sz =3D 0;=0A= private_data->ep_cache =3D NULL;=0A= private_data->connect_retry_attempts =3D DEF_RETRY_ATTEMPTS;=0A= private_data->worker.worker_private =3D private_data;=0A= =0A= private_data->worker.validate =3D validate;=0A= private_data->worker.init =3D init;=0A= private_data->worker.get_endpoint =3D get_endpoint;=0A= private_data->worker.destroy =3D destroy;=0A= =0A= *w =3D &private_data->worker;=0A= return JK_TRUE;=0A= }=0A= ------_=_NextPart_000_01C0B646.A855F368--