You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@locus.apache.org on 2000/04/15 00:44:48 UTC
cvs commit: jakarta-tomcat/src/native/iis_netscape jk_ajp23_worker.c jk_ajp23_worker.h jk_jni_worker.c jk_worker.c
costin 00/04/14 15:44:47
Modified: src/native/iis_netscape jk_jni_worker.c jk_worker.c
Added: src/native/iis_netscape jk_ajp23_worker.c jk_ajp23_worker.h
Log:
Added the (old, experimental) ajp23 worker.
Ajp23 was used to test bi-directional communication between apache
and tomcat - the main difference from ajp12 is that the response is
sent as a sequence of blocks ( prefixed by length ) as oposed to a stream
terminated by socket close.
That allows the reuse of the connection and bi-directional communication.
Apache will start by sending a MsgBuff containing the request and wait for
a MsgBuff from tomcat. As soon as it receives one it will start processing it
and send back a response ( if needed ), and so on.
It seems jk_ framework is very easy to work with, but I still have to figure
how to keep the session open ( in a multithreaded environment ) - probably
we need a per/thread cache or something.
Revision Changes Path
1.5 +3 -1 jakarta-tomcat/src/native/iis_netscape/jk_jni_worker.c
Index: jk_jni_worker.c
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/native/iis_netscape/jk_jni_worker.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- jk_jni_worker.c 2000/03/09 11:58:36 1.4
+++ jk_jni_worker.c 2000/04/14 22:44:45 1.5
@@ -57,7 +57,7 @@
* Description: In process JNI worker *
* Author: Gal Shachor <sh...@il.ibm.com> *
* Based on: *
- * Version: $Revision: 1.4 $ *
+ * Version: $Revision: 1.5 $ *
***************************************************************************/
#ifndef WIN32
@@ -193,12 +193,14 @@
*/
*is_recoverable_error = JK_FALSE;
+/* printf( "Prepare to call \n"); */
rc = (*(p->env))->CallIntMethod(p->env,
p->worker->jk_java_bridge_object,
p->worker->jk_service_method,
(jlong)s,
(jlong)l);
+/* printf( "RC %d\n", rc); */
return rc == 0 ? JK_FALSE : JK_TRUE;
}
*is_recoverable_error = JK_TRUE;
1.4 +4 -2 jakarta-tomcat/src/native/iis_netscape/jk_worker.c
Index: jk_worker.c
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/native/iis_netscape/jk_worker.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- jk_worker.c 2000/02/28 11:52:49 1.3
+++ jk_worker.c 2000/04/14 22:44:45 1.4
@@ -56,10 +56,11 @@
/***************************************************************************
* Description: Workers controller *
* Author: Gal Shachor <sh...@il.ibm.com> *
- * Version: $Revision: 1.3 $ *
+ * Version: $Revision: 1.4 $ *
***************************************************************************/
#include "jk_ajp12_worker.h"
+#include "jk_ajp23_worker.h"
#include "jk_jni_worker.h"
#include "jk_lb_worker.h"
#include "jk_worker.h"
@@ -75,6 +76,7 @@
static worker_factory_record_t worker_factories[] = {
{ JK_AJP12_WORKER_NAME, ajp12_worker_factory},
+ { JK_AJP23_WORKER_NAME, ajp23_worker_factory},
{ JK_JNI_WORKER_NAME, jni_worker_factory},
{ JK_LB_WORKER_NAME, lb_worker_factory},
{ NULL, NULL}
@@ -258,4 +260,4 @@
}
return NULL;
-}
\ No newline at end of file
+}
1.1 jakarta-tomcat/src/native/iis_netscape/jk_ajp23_worker.c
Index: jk_ajp23_worker.c
===================================================================
/*
* Copyright (c) 1997-1999 The Java Apache Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the Java Apache
* Project for use in the Apache JServ servlet engine project
* <http://java.apache.org/>."
*
* 4. The names "Apache JServ", "Apache JServ Servlet Engine" and
* "Java Apache Project" must not be used to endorse or promote products
* derived from this software without prior written permission.
*
* 5. Products derived from this software may not be called "Apache JServ"
* nor may "Apache" nor "Apache JServ" appear in their names without
* prior written permission of the Java Apache Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the Java Apache
* Project for use in the Apache JServ servlet engine project
* <http://java.apache.org/>."
*
* THIS SOFTWARE IS PROVIDED BY THE JAVA APACHE PROJECT "AS IS" AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JAVA APACHE PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Java Apache Group. For more information
* on the Java Apache Project and the Apache JServ Servlet Engine project,
* please see <http://java.apache.org/>.
*
*/
/**
Experimental bi-directionl protocol.
( updated from src/native/apache/connector )
@author costin@costin.dnt.ro
*/
#include "jk_ajp23_worker.h"
#include "jk_pool.h"
#include "jk_connect.h"
#include "jk_util.h"
#include "jk_sockbuf.h"
#define AJP_DEF_HOST ("localhost")
#define AJP_DEF_PORT (8008)
#define READ_BUF_SIZE (8*1024)
#define DEF_RETRY_ATTEMPTS (1)
/** "PseudoObjects" in JK:
struct Base {
void (*method)();
SubClass *subClass;
}
Base *SubClassFactory();
struct SubClass {
char *propertiesSubcl;
}
We pass around pointers to the Base object.
XXX We could check the type of the worker too to validate.
All methods are returning int==error code ( 0==success )
The first parameter is a pointer to this.
XXX have second param a pointer to ctx ( include log in ctx)
Conventions: _t == type
*/
/** Objects:
class Worker {
int validate(Properties props);
int init(Properties props );
int get_endpoint( Endpoint *endp );
int destroy();
}
class Endpoint {
int service( WsService s, int *isRecoverable);
int done();
}
class WsService {
Pool *pool;
... all fields in request_rec ...
int startResponse( int status, String reason, String headers[], String values[], int hCount );
int read( char buff[], int len, int *read);
int write( char buff[], int len );
}
*/
/**
Utilities:
*/
/** ajp23Worker extends Worker -> worker will point to the extended object.
*/
struct ajp23_worker {
struct sockaddr_in worker_inet_addr; /* Contains host and port */
unsigned connect_retry_attempts;
char *name;
jk_worker_t worker;
// no cache endpoint - it's up to caller to cache it if
// he wants!
};
typedef struct ajp23_worker ajp23_worker_t;
struct ajp23_endpoint {
ajp23_worker_t *worker;
int sd;
jk_sockbuf_t sb;
jk_endpoint_t endpoint;
};
typedef struct ajp23_endpoint ajp23_endpoint_t;
/* -------------------- Local objects */
/* // XXX replace all return values with error codes */
#define ERR_BAD_PACKET -5
/* Data marshaling.
Uses a Buffer ( iovect later ), with 1 copy.
Simple marshaling, based on Ajp21.
*/
/* strbuf ? */
struct MsgBuffer_Simple {
jk_pool_t *pool;
unsigned char *buf;
int pos; /* XXX MT */
int len;
int maxlen;
};
typedef struct MsgBuffer_Simple MsgBuffer;
MsgBuffer *new_MsgBuffer();
/* -------------------- Method -------------------- */
static int JK_METHOD validate(jk_worker_t *pThis,
jk_map_t *props,
jk_logger_t *l)
{
jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::validate\n");
if(pThis && pThis->worker_private) {
ajp23_worker_t *p = pThis->worker_private;
int port = jk_get_worker_port(props,
p->name,
AJP_DEF_PORT);
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\n",
p->name, host, port);
if(port > 1024 && host) {
if(jk_resolve(host, (short)port, &p->worker_inet_addr)) {
return JK_TRUE;
}
jk_log(l, JK_LOG_ERROR, "In jk_worker_t::validate, resolve failed\n");
}
jk_log(l, JK_LOG_ERROR, "In jk_worker_t::validate, Error %s %d\n", host, port);
} else {
jk_log(l, JK_LOG_ERROR, "In jk_worker_t::validate, NULL parameters\n");
}
return JK_FALSE;
}
static int JK_METHOD init(jk_worker_t *pThis,
jk_map_t *props,
jk_logger_t *log)
{
/* Nothing to do for now */
return JK_TRUE;
}
static int JK_METHOD destroy(jk_worker_t **pThis,
jk_logger_t *l)
{
jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::destroy\n");
if(pThis && *pThis && (*pThis)->worker_private) {
ajp23_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\n");
return JK_FALSE;
}
static int JK_METHOD done(jk_endpoint_t **e,
jk_logger_t *l)
{
jk_log(l, JK_LOG_DEBUG, "Into jk_endpoint_t::done\n");
if(e && *e && (*e)->endpoint_private) {
ajp23_endpoint_t *p = (*e)->endpoint_private;
if(p->sd > 0) {
jk_close_socket(p->sd);
}
free(p);
*e = NULL;
return JK_TRUE;
}
jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::done, NULL parameters\n");
return JK_FALSE;
}
// ---------------------------------------- START MARSHALL ----------------------------------------
/* XXX what's above this line can go to .h XXX */
static void b_dump( MsgBuffer *msg, char *err ) {
int i=0;
printf("%s %d/%d/%d %x %x %x %x - %x %x %x %x - %x %x %x %x - %x %x %x %x\n", err, msg->pos, msg->len, msg->maxlen,
msg->buf[i++],msg->buf[i++],msg->buf[i++],msg->buf[i++],
msg->buf[i++],msg->buf[i++],msg->buf[i++],msg->buf[i++],
msg->buf[i++],msg->buf[i++],msg->buf[i++],msg->buf[i++],
msg->buf[i++],msg->buf[i++],msg->buf[i++],msg->buf[i++]);
i=msg->pos - 4;
if( i<0 ) i=0;
printf(" %x %x %x %x - %x %x %x %x --- %x %x %x %x - %x %x %x %x\n",
msg->buf[i++],msg->buf[i++],msg->buf[i++],msg->buf[i++],
msg->buf[i++],msg->buf[i++],msg->buf[i++],msg->buf[i++],
msg->buf[i++],msg->buf[i++],msg->buf[i++],msg->buf[i++],
msg->buf[i++],msg->buf[i++],msg->buf[i++],msg->buf[i++]);
}
static void b_reset( MsgBuffer *msg ) {
msg->len =4;
msg->pos =4;
}
static void b_set_int( MsgBuffer *msg, int pos, unsigned int val ) {
/* XXX optimize - swap if needed or just copyb */
/* #if SWAP */
/* swap_16( (unsigned char *)&val, msg->buf ) */
/* #else */
/* ??? */
/* #endif */
msg->buf[pos++]=(unsigned char) ( (val >> 8) & 0xff );
msg->buf[pos]= (unsigned char) ( val & 0xff );
}
static int b_append_int( MsgBuffer *msg, unsigned int val ) {
if( msg->len + 2 > msg->maxlen )
return -1;
b_set_int( msg, msg->len, val );
msg->len +=2;
return 0;
}
static void b_end(MsgBuffer *msg) {
/* Ugly way to set the size in the right position */
b_set_int( msg, 2, msg->len - 4 ); /* see protocol */
b_set_int( msg, 0, 0x1234 );
}
/* XXX optimize it ( less function calls, macros )
Ugly pointer arithmetic code
*/
/* XXX io_vec ? XXX just send/map the pool !!! */
static MsgBuffer *b_new(jk_pool_t *p) {
MsgBuffer *msg=(MsgBuffer *)jk_pool_alloc( p, sizeof ( MsgBuffer ));
msg->pool=p;
if(msg==NULL) return NULL;
}
static int b_set_buffer( MsgBuffer *msg, char *data, int buffSize ) {
if(msg==NULL) return -1;
msg->len=0;
msg->buf=data;
msg->maxlen=buffSize;
/* XXX error checking !!! */
return 0;
}
static int b_set_buffer_size( MsgBuffer *msg, int buffSize ) {
unsigned char *data=(unsigned char *)jk_pool_alloc( msg->pool, buffSize );
if( data==NULL ) {
/* Free - sub-pools */
return -1;
}
b_set_buffer( msg, data, buffSize );
}
static unsigned char *b_get_buff( MsgBuffer *msg ) {
return msg->buf;
}
static unsigned int b_get_pos( MsgBuffer *msg ) {
return msg->pos;
}
static unsigned int b_get_len( MsgBuffer *msg ) {
return msg->len;
}
static void b_set_len( MsgBuffer *msg, int len ) {
msg->len=len;
}
static int b_get_size( MsgBuffer *msg ) {
return msg->maxlen;
}
/** Shame-less copy from somewhere.
assert (src != dst)
*/
static void swap_16( unsigned char *src, unsigned char *dst) {
*dst++ = *(src + 1 );
*dst= *src;
}
static int b_append_string( MsgBuffer *msg, char *param ) {
int len;
if( param==NULL ) {
b_append_int( msg, 0xFFFF );
return 0;
}
len=strlen(param);
if( msg->len + len + 2 > msg->maxlen )
return -1;
// ignore error - we checked once
b_append_int( msg, len );
// We checked for space !!
strncpy( msg->buf + msg->len , param, len+1 ); // including \0
msg->len += len + 1;
return 0;
}
static int b_get_int( MsgBuffer *msg) {
int i;
if( msg->pos + 1 > msg->len ) {
printf( "Read after end \n");
return 0;
}
i= ((msg->buf[msg->pos++]&0xff)<<8);
i+= (msg->buf[(msg->pos++)] & 0xFF);
return i;
}
static int b_pget_int( MsgBuffer *msg, int pos) {
int i= ((msg->buf[pos++]&0xff)<<8);
i+= (msg->buf[pos] & 0xFF);
return i;
}
static int b_getCode( MsgBuffer *msg ) {
return b_pget_int( msg, 0 );
}
static unsigned char *b_get_string( MsgBuffer *msg) {
int size, start;
char *str;
/* b_dump(msg, "Before GS: "); */
size=b_get_int(msg);
start=msg->pos;
if(( size < 0 ) || ( size + start > msg->maxlen ) ) {
b_dump(msg, "After get int");
printf("ERROR\n" );
return "ERROR"; /* XXX */
}
msg->pos += size;
msg->pos++; // end 0
str= msg->buf + start;
/* printf( "Get_string %lx %lx %x\n", msg->buf, str, size ); */
/* printf( "Get_string %s \n", str ); */
return (unsigned char *)(msg->buf + start);
}
static int b_append_headers( MsgBuffer *msg, jk_ws_service_t *s, jk_logger_t *l) {
/* Send the request headers */
int err=b_append_int( msg, s->num_headers);
if(err<0) return err;
if(s->num_headers) {
unsigned i;
for(i = 0 ; i < s->num_headers ; ++i) {
err=b_append_string( msg, s->headers_names[i] );
if (err<0) return err;
err=b_append_string( msg, s->headers_values[i] );
if (err<0) return err;
}
}
if(!err) {
jk_log(l, JK_LOG_ERROR, "In ajpv12_handle_request, failed to send headers\n");
return JK_FALSE;
}
return JK_TRUE;
}
// ---------------------------------------- START RMETHODS ----------------------------------------
/* Protocol independent remote methods.
Uses buffer.c to do (de)marshaling.
Contain both remote methods impl + skel
Separate later, now hard-coding may be faster to code and maybe more efficient
*/
#define NO_RESPONSE 0
#define HAS_RESPONSE 1
#define SET_HEADERS 2
#define SEND_BODY_CHUNK 3
#define SEND_HEADERS 4
#define REQUEST_FORWARD 1
#define END_RESPONSE 5
#define GET_BODY_CHUNK 6
/** Callback demux
Small methods inlined
XXX add support for user-defined methods
*/
static void encode_request( MsgBuffer *msg, jk_ws_service_t *r, jk_logger_t *l );
static int process_callback( MsgBuffer *msg, jk_ws_service_t *r, jk_logger_t *l);
/* XXX what's above this line should go to .h XXX */
/** Method codes */
/* XXX all method codes should start with 0xFF,
For methods not starting with 0xFF type is a length, and
the method _name_ follows
*/
static void encode_env( MsgBuffer *msg, jk_ws_service_t *r ) {
// b_append_table( msg, r->subprocess_env );
/* XXX use r instead of env */
b_append_int( msg, 6 );
b_append_string( msg, "REQUEST_METHOD" );
b_append_string( msg, r->method );
b_append_string( msg, "SERVER_PROTOCOL");
b_append_string( msg, r->protocol );
b_append_string( msg, "REQUEST_URI" );
b_append_string( msg, r->req_uri );
b_append_string( msg, "QUERY_STRING" );
b_append_string( msg, r->query_string );
b_append_string( msg, "SERVER_PORT" );
b_append_string( msg, "8080" );
b_append_string( msg, "REMOTE_ADDR");
b_append_string( msg, r->remote_addr );
}
/** Forward request info to the remote engine.
XXX do not forward everything, only what's used
XXX configure what is sent per request, fine tune
XXX integrate with mod_session (notes)
XXX integrate with special module to find the context (notes)
*/
static void encode_request( MsgBuffer *msg, jk_ws_service_t *r, jk_logger_t *l ) {
b_append_int( msg, REQUEST_FORWARD );
encode_env( msg, r );
b_append_headers( msg, r, l );
/* // Append first chunk of request body ( up to the buffer size ) */
/* printf("Encode request \n"); */
/* if ( ! ap_should_client_block(r)) { */
/* // no body, send 0 */
/* printf("No body\n"); */
b_append_int( msg, 0 );
/* } else { */
/* int maxsize=b_get_size( msg ); */
/* char *buffer=b_get_buff(msg); */
/* int posLen= b_get_len( msg ); */
/* int pos=posLen +2 ; */
/* long rd; */
/* /* Read in buff, at pos + 2 ( let space for size ), up to */
/* maxsize - pos. */
/* while ( (pos < maxsize ) && (rd=ap_get_client_block(r,buffer+pos, maxsize - pos ))>0) { */
/* printf( "Reading %d %d %d \n", posLen, pos, maxsize ); */
/* pos=pos + rd; */
/* } */
/* printf( "End reading %d %d %d \n", posLen, pos, maxsize ); */
/* b_set_int( msg, posLen, pos - posLen -2 ); */
/* b_set_len( msg, pos ); */
/* b_dump(msg, "Post "); */
/* b_dump(msg, "Encode req"); */
}
/**
SetHeaders callback - all headers are added to headers->out, no
more parsing
*/
static int setHeaders( MsgBuffer *msg, jk_ws_service_t *r, jk_logger_t *l) {
int i;
int count;
char **names=NULL;
char **values=NULL;
int status=200;
count= b_get_int( msg );
names=(char **) jk_pool_alloc( r->pool, ( count + 1 ) * sizeof( char * ));
values=(char **) jk_pool_alloc( r->pool, ( count + 1 ) * sizeof( char * ));
// printf( "Header count: %x %x %x %x\n", count, pos, (int)msg[2], (int)msg[3] );
for( i=0; i< count; i++ ) {
char *n=b_get_string( msg );
char *v=b_get_string( msg );
names[i]=n;
values[i]=v;
if( 0==strcmp(n, "Status")) {
// printf("Setting status %s\n", v);
status=atoi(v);
}
}
if( ! r->start_response( r, status, "Reason",
(const char * const *)names, /* ??? */
(const char * const *)values,
count )) {
jk_log( l, JK_LOG_ERROR, "Error starting response " );
return NO_RESPONSE;
}
return NO_RESPONSE;
}
/**
Get Body Chunk
*/
static int getBodyChunk( MsgBuffer *msg, jk_ws_service_t *r) {
int i;
int count;
/* No parameters, send body */
b_reset( msg );
b_append_int( msg, SEND_BODY_CHUNK );
/* if ( ! ap_should_client_block(r)) { */
/* // no body, send 0 */
/* printf("No body\n"); */
/* b_append_int( msg, 0 ); */
/* } else { */
/* int maxsize=b_get_size( msg ); */
/* char *buffer=b_get_buff(msg); */
/* int posLen= b_get_len( msg ); */
/* int pos=posLen +2 ; */
/* long rd; */
/* /* Read in buff, at pos + 2 ( let space for size ), up to */
/* maxsize - pos. */
/* while ( (pos < maxsize ) && (rd=ap_get_client_block(r,buffer+pos, maxsize - pos ))>0) { */
/* printf( "Reading %d %d %d \n", posLen, pos, maxsize ); */
/* pos=pos + rd; */
/* } */
/* printf( "End reading %d %d %d \n", posLen, pos, maxsize ); */
/* b_set_int( msg, posLen, pos - posLen -2 ); */
/* b_set_len( msg, pos ); */
/* b_dump(msg, "Post additional data"); */
/* } */
return HAS_RESPONSE;
}
/*
Small methods inlined
XXX add support for user-defined methods
*/
int process_callback( MsgBuffer *msg, jk_ws_service_t *r, jk_logger_t *l) {
int len;
/* printf("Callback %x\n", b_getCode(msg)); */
switch( b_getCode(msg) ) {
case SET_HEADERS:
setHeaders( msg , r, l);
break;
case SEND_BODY_CHUNK:
len=b_get_int( msg );
r->write( r, msg->buf + msg->pos, len);
break;
case GET_BODY_CHUNK:
getBodyChunk( msg, r );
return HAS_RESPONSE;
break;
case END_RESPONSE:
break;
default:
b_dump( msg , "Invalid code");
jk_log( l, JK_LOG_ERROR,
"Invalid code: %d\n", b_getCode(msg));
return -1;
}
return NO_RESPONSE;
}
// ---------------------------------------- START TCP ----------------------------------------
static int connection_tcp_send_message( ajp23_endpoint_t *con, MsgBuffer *msg, jk_logger_t *l ) {
int sent=0;
int i;
b_end( msg );
/* printf("Sending %x %x %x %x\n", msg->buf[0],msg->buf[1],msg->buf[2],msg->buf[3]) ; */
while( sent < msg->len ) {
i=write( con->sd, msg->buf + sent , msg->len - sent );
/* printf("i=%d\n", i); */
if( i == 0 ) {
return -2;
}
if( i < 0 ) {
return -3;
}
sent += i;
}
/* ... */
/* flush( con->socket ); */
return 0;
}
/** Read a full buffer, deal with partial reads
XXX rewrite it - we should read as much as possible
and then interpret it and read more if needed, right now there
are at least 2 reads per request
*/
static int read_full( ajp23_endpoint_t *con, unsigned char *buff, int msglen, jk_logger_t *l ) {
int rdlen=0;
int i;
while( rdlen < msglen ) {
i=read( con->sd, buff + rdlen, msglen - rdlen );
/* printf( "Read: %d %d %x %x %x\n", i, rdlen, i, rdlen, msglen ); */
if(i==-1) {
if(errno==EAGAIN) {
jk_log( l, JK_LOG_ERROR,
"EAGAIN, continue reading");
}
else {
jk_log( l, JK_LOG_ERROR,
"ERRNO=%s", strerror(errno));
/* // closeConnection( ses ); */
return -6;
}
}
/* printf("."); */
if(i==0) return -7;
rdlen += i;
}
return 0;
}
/**
Read a callback
*/
static int connection_tcp_get_message( ajp23_endpoint_t *con, MsgBuffer *msg, jk_logger_t *l ) {
char head[6];
int rdlen;
int i;
int pos;
int msglen;
int off;
char *message;
int *imessage;
/* // mark[2] + len[2] */
i=read_full( con, head, 4, l );
/* printf( "XXX %d \n" , i ) ; */
if(i<0) return i;
if( (head[0] != 'A') || (head[1] != 'B' )) {
return ERR_BAD_PACKET ;
}
/* sreq->msglen=get_I( head, &pos ); */
msglen=((head[2]&0xff)<<8);
msglen+= (head[3] & 0xFF);
/* printf( "Packet len %d %x\n", msglen, msglen ); */
if(msglen > b_get_size(msg) ) {
printf("Message too long ");
return -5; /* XXX */
/* sreq->message=(char *)ap_palloc( p, sreq->msglen ); */
/* "Re-alocating msg buffer, %d %d\n", sreq->buffSize, sreq->msglen);
/* sreq->buffSize = sreq->msglen; */
}
msg->len=msglen;
msg->pos=2; /* After code */
i=read_full(con, msg->buf, msglen, l );
if( i<0) return i;
/* b_dump( msg, " RCV: " ); */
return 0;
}
// ---------------------------------------- ----------------------------------------
static int JK_METHOD service(jk_endpoint_t *e,
jk_ws_service_t *s,
jk_logger_t *l,
int *is_recoverable_error)
{
jk_log(l, JK_LOG_DEBUG, "Into jk_endpoint_t::service\n");
if(e && e->endpoint_private && s && is_recoverable_error) {
ajp23_endpoint_t *p = e->endpoint_private;
unsigned attempt;
*is_recoverable_error = JK_TRUE;
for(attempt = 0 ; attempt < p->worker->connect_retry_attempts ; attempt++) {
p->sd = jk_open_socket(&p->worker->worker_inet_addr,
JK_TRUE,
l);
jk_log(l, JK_LOG_DEBUG, "In jk_endpoint_t::service, sd = %d\n", p->sd);
if(p->sd >= 0) {
break;
}
}
if(p->sd >= 0) {
MsgBuffer *msg;
int err;
/*
* After we are connected, each error that we are going to
* have is probably unrecoverable
*/
*is_recoverable_error = JK_FALSE;
jk_sb_open(&p->sb, p->sd);
msg = b_new( s->pool );
b_set_buffer_size( msg, 2048);
b_reset( msg );
encode_request( msg , s, l );
err= connection_tcp_send_message( p, msg, l );
if(err<0) {
jk_log( l, JK_LOG_ERROR,
"Error sending request %d\n", err);
return JK_FALSE;
}
while( 1 ) {
int err=connection_tcp_get_message( p, msg, l );
/* b_dump(msg, "Get Message: " ); */
if( err < 0 ) {
jk_log( l, JK_LOG_ERROR,
"Error reading request %d\n", err);
// XXX cleanup, close connection if packet error
return JK_FALSE;
}
if( b_getCode( msg ) == END_RESPONSE )
break;
err=process_callback( msg, s, l );
if( err == HAS_RESPONSE ) {
err=connection_tcp_send_message( p, msg, l );
if( err < 0 ) {
jk_log( l, JK_LOG_DEBUG,
"Error reading response1 %d\n", err);
return JK_FALSE;
}
}
if( err < 0 ) break; /* XXX error */
}
return JK_TRUE;
}
jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::service, Error sd = %d\n", p->sd);
} else {
jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::service, NULL parameters\n");
}
return JK_FALSE;
}
static int JK_METHOD get_endpoint(jk_worker_t *pThis,
jk_endpoint_t **pend,
jk_logger_t *l)
{
jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::get_endpoint\n");
if(pThis && pThis->worker_private && pend) {
ajp23_endpoint_t *p = (ajp23_endpoint_t *)malloc(sizeof(ajp23_endpoint_t));
if(p) {
p->sd = -1;
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\n");
} else {
jk_log(l, JK_LOG_ERROR, "In jk_worker_t::get_endpoint, NULL parameters\n");
}
return JK_FALSE;
}
/** Constructor for ajp23_worker_t
*/
int JK_METHOD ajp23_worker_factory(jk_worker_t **w,
const char *name,
jk_logger_t *l)
{
ajp23_worker_t *private_data = (ajp23_worker_t *)malloc(sizeof(ajp23_worker_t));
printf( "Into ajp23_worker_factory\n"); fflush(stdout);
jk_log(l, JK_LOG_DEBUG, "Into ajp23_worker_factory\n");
if(NULL == name || NULL == w) {
jk_log(l, JK_LOG_ERROR, "In ajp23_worker_factory, NULL parameters\n");
return JK_FALSE;
}
if(! private_data) {
jk_log(l, JK_LOG_ERROR, "In ajp23_worker_factory, NULL parameters\n");
return JK_FALSE;
}
private_data->name = strdup(name);
if( ! private_data->name) {
free(private_data);
jk_log(l, JK_LOG_ERROR, "In ajp23_worker_factory, malloc failed\n");
return JK_FALSE;
}
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;
*w = &private_data->worker;
return JK_TRUE;
}
1.1 jakarta-tomcat/src/native/iis_netscape/jk_ajp23_worker.h
Index: jk_ajp23_worker.h
===================================================================
/*
* Copyright (c) 1997-1999 The Java Apache Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the Java Apache
* Project for use in the Apache JServ servlet engine project
* <http://java.apache.org/>."
*
* 4. The names "Apache JServ", "Apache JServ Servlet Engine" and
* "Java Apache Project" must not be used to endorse or promote products
* derived from this software without prior written permission.
*
* 5. Products derived from this software may not be called "Apache JServ"
* nor may "Apache" nor "Apache JServ" appear in their names without
* prior written permission of the Java Apache Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the Java Apache
* Project for use in the Apache JServ servlet engine project
* <http://java.apache.org/>."
*
* THIS SOFTWARE IS PROVIDED BY THE JAVA APACHE PROJECT "AS IS" AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JAVA APACHE PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Java Apache Group. For more information
* on the Java Apache Project and the Apache JServ Servlet Engine project,
* please see <http://java.apache.org/>.
*
*/
/***************************************************************************
* Description: ajpv1.2 worker header file *
* Author: Gal Shachor <sh...@il.ibm.com> *
* Version: $Revision: 1.1 $ *
***************************************************************************/
#ifndef JK_AJP23_WORKER_H
#define JK_AJP23_WORKER_H
#include "jk_logger.h"
#include "jk_service.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define JK_AJP23_WORKER_NAME ("ajp23")
int JK_METHOD ajp23_worker_factory(jk_worker_t **w,
const char *name,
jk_logger_t *l);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* JK_AJP23_WORKER_H */