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...@hyperreal.org on 1999/11/10 19:56:26 UTC
cvs commit: jakarta-tomcat/src/native/apache/modules mod_ajp23.c
costin 99/11/10 10:56:22
Added: src/native/apache/modules mod_ajp23.c
Log:
Added mod_ajp23.c for easy-building.
( based on files in native/apache/connector ).
Apache/connector will be "deprecated" until we get a stable
build and a better way to reuse the C code.
Revision Changes Path
1.1 jakarta-tomcat/src/native/apache/modules/mod_ajp23.c
Index: mod_ajp23.c
===================================================================
/*
* XXX copyright
*/
#include "httpd.h"
#include "http_config.h"
#include "http_log.h"
#include "http_main.h"
#include "http_protocol.h"
#include "http_request.h"
#include "util_script.h"
#include "util_md5.h"
/**
XXX Add high level description
XXX Add configuration documentation
*/
module ajp23_module;
#define MAX_HOSTS 20
/* 16 k */
#define MAX_BUFF_SIZE 0x4000
#define DEFAULT_ARG1 "localhost"
#define DEFAULT_ARG2 "8008"
#define CONNECTOR "Ajp23"
#define CONNECTOR_MODULE ajp23_module
#define CONNECTOR_HANDLE_NAME "ajp23_handler"
/* -------------------- #include "msg_buffer_simple.c" -------------------- */
/* Data marshaling.
Uses a Buffer ( iovect later ), with 1 copy.
Simple marshaling, based on Ajp21.
*/
typedef struct MsgBuffer_Simple MsgBuffer;
MsgBuffer *new_MsgBuffer();
/* strbuf ? */
struct MsgBuffer_Simple {
pool *pool;
unsigned char *buf;
int pos; /* XXX MT */
int len;
int maxlen;
};
/* XXX what's above this line should 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(pool *p) {
MsgBuffer *msg=(MsgBuffer *)ap_palloc( 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 *)ap_palloc( 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_table( MsgBuffer *msg, table *tbl) {
array_header *env_arr = ap_table_elts(tbl);
table_entry *elts = (table_entry *) env_arr->elts;
int i, err;
err=b_append_int( msg, env_arr->nelts);
if(err<0) return err;
for (i = 0; i < env_arr->nelts; ++i) {
//if (!elts[i].key) continue;
// XXX do not send headers as environment variables
//if ( type== ENV && !strncmp(elts[i].key, "HTTP_", 5)) continue;
err=b_append_string( msg, elts[i].key );
if (err<0) return err;
err=b_append_string( msg, elts[i].val );
if (err<0) return err;
}
return 0;
}
static int table_size( MsgBuffer *msg, table *tbl ) {
int size=0;
int i;
array_header *env_arr = ap_table_elts(tbl);
table_entry *elts = (table_entry *) env_arr->elts;
size+=2; // NV count
for (i = 0; i < env_arr->nelts; ++i) {
if (!elts[i].key) continue;
size += strlen( elts[i].key );
size += strlen( elts[i].val );
}
size+=6*env_arr->nelts; // 2 byte for each string length + 1 ending 0
return size;
}
/* -------------------- #include "rmethods.c" -------------------- */
/* 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, request_rec *r );
static int process_callback( MsgBuffer *msg, request_rec *r);
/* 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, request_rec *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, (char *)ap_table_get( r->subprocess_env , "REQUEST_METHOD") );
b_append_string( msg, "SERVER_PROTOCOL");
b_append_string( msg, (char *)ap_table_get( r->subprocess_env , "SERVER_PROTOCOL" ) );
b_append_string( msg, "REQUEST_URI" );
b_append_string( msg, (char *)ap_table_get( r->subprocess_env , "REQUEST_URI" ) );
b_append_string( msg, "QUERY_STRING" );
b_append_string( msg, (char *)ap_table_get( r->subprocess_env , "QUERY_STRING") );
b_append_string( msg, "SERVER_PORT" );
b_append_string( msg, (char *)ap_table_get( r->subprocess_env , "SERVER_PORT") );
b_append_string( msg, "REMOTE_ADDR");
b_append_string( msg, (char *)ap_table_get( r->subprocess_env , "REMOTE_ADDR") );
}
static char *headers[]={ "content-length", "content-type", "cookie" };
static void encode_headers( MsgBuffer *msg, request_rec *r ) {
int i;
b_append_table( msg, r->headers_in );
if( 0 ) {
b_append_int( msg, 3 );
for( i=0; i<3 ; i++ ) {
b_append_string( msg, headers[i] );
b_append_string( msg, (char *)ap_table_get( r->headers_in , headers[i]) );
}
}
}
/** 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, request_rec *r ) {
ap_setup_client_block(r, REQUEST_CHUNKED_ERROR);
b_append_int( msg, REQUEST_FORWARD );
encode_env( msg, r );
encode_headers( msg, r );
// 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, request_rec *r) {
int i;
int count;
count= b_get_int( msg );
// 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 );
ap_table_add( r->headers_out, n, v);
/* printf( "Setting header: %s=%s\n", n , v ); */
if( 0==strcmp(n,"Content-Type") ) {
// XXX Todo Content-encoding!!!
// XXX special function to send "special" headers
// printf("Setting content-type %s\n", v);
r->content_type=v;
}
if( 0==strcmp(n, "Status")) {
// printf("Setting status %s\n", v);
r->status=atoi(v);
}
}
return NO_RESPONSE;
}
/**
Get Body Chunk
*/
static int getBodyChunk( MsgBuffer *msg, request_rec *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, request_rec *r) {
int len;
//printf("Callback %x\n", (int)sreq->type);
switch( b_getCode(msg) ) {
case SET_HEADERS:
setHeaders( msg , r);
ap_send_http_header(r);
break;
case SEND_HEADERS:
ap_send_http_header(r);
break;
case SEND_BODY_CHUNK:
len=b_get_int( msg );
ap_rwrite( msg->buf + msg->pos, len, r);
break;
case GET_BODY_CHUNK:
getBodyChunk( msg, r );
return HAS_RESPONSE;
break;
case END_RESPONSE:
break;
default:
b_dump( msg , "Invalid code");
ap_log_error( APLOG_MARK, APLOG_EMERG, NULL,
"Invalid code: %d\n", b_getCode(msg));
return -1;
}
return NO_RESPONSE;
}
/* -------------------- #include "connection_tcp.c" -------------------- */
/** Connection using TCP sockets
*/
/* The default size of a buffer
XXX make it configurable
*/
#define DEFAULT_SIZE 0x1000
#define connection_get( rhost ) connection_tcp_get( rhost )
#define connection_release( c ) connection_tcp_release( c )
#define connection_destroy( c ) connection_tcp_destroy( c )
#define connection_get_message( c, msg ) connection_tcp_get_message( c, msg )
#define connection_send_message( c, msg ) connection_tcp_send_message( c, msg )
#define rhost_new( p, name, arg1, arg2 ) rhost_tcp_new( p, name, arg1, arg2)
typedef struct TcpConnection Connection;
typedef struct TcpRemoteHost RemoteHost;
typedef struct TcpConnection {
pool *pool;
RemoteHost *host;
int socket; /* XXX sock_t */
BUFF *bsocket;
} TcpConnection;
/* Informations about a remote TCP host
*/
typedef struct TcpRemoteHost{
pool *pool;
char *name;
TcpConnection *connection; /* cache */
char *host;
int port;
struct hostent *hinfo; /* in pool */
struct sockaddr_in addr;
} TcpRemoteHost;
/* // XXX replace all return values with error codes */
#define ERR_BAD_PACKET -5
/* ---------------------------------------- */
static RemoteHost *rhost_tcp_new(pool *p, char *name, char *arg1, char *arg2) {
TcpRemoteHost *rh=ap_palloc( p, sizeof(TcpRemoteHost));
rh->pool=p;
rh->connection=NULL;
rh->name=name;
if(arg2!=NULL)
rh->port=atoi(arg2);
else
rh->port=DEFAULT_ARG2;/* XXX */
rh->host=arg1;
rh->hinfo=ap_pgethostbyname( rh->pool, rh->host );
/* // palloc a new hostent, unlike gethostbyname */
rh->addr.sin_family = AF_INET;
rh->addr.sin_addr.s_addr = ((struct in_addr *)rh->hinfo->h_addr_list[0])->s_addr;
rh->addr.sin_port = htons(rh->port);
return (RemoteHost *)rh;
}
/* ---------------------------------------- */
static Connection *connection_tcp_create( RemoteHost *rhost ) {
TcpConnection *con;
int err;
int fd_flags;
con=(TcpConnection *)ap_palloc( rhost->pool, sizeof ( TcpConnection ));
ap_log_error( APLOG_MARK, APLOG_EMERG, NULL, "Open connection to %s", rhost->host);
con->pool=rhost->pool;
con->host=rhost;
con->bsocket= ap_bcreate( rhost->pool, B_SOCKET | B_RDWR );
if( con->bsocket == NULL ) {
/* XXX clean the subpool */
return NULL;
}
con->socket= ap_psocket(con->pool, AF_INET, SOCK_STREAM, IPPROTO_TCP);
err=connect(con->socket, &rhost->addr ,sizeof(struct sockaddr_in));
if( err==-1 ) {
ap_log_error( APLOG_MARK, APLOG_EMERG, NULL,
"Error connecting %d\n", err);
return NULL;
/* XXX clean subpool
// XXX add WIN stuff
*/
}
/* XXX add TCP_NODELAY sfuff */
ap_bpushfd( con->bsocket, con->socket, con->socket );
fd_flags = fcntl(con->socket, F_GETFL, 0);
fd_flags &= ~O_NONBLOCK;
fcntl(con->socket, F_SETFL, fd_flags);
rhost->connection=con;
return con;
}
/* Remote Host connection handling
If one connection/request - optimize it
If connection reuse - everything is ok.
*/
static Connection *connection_tcp_get( TcpRemoteHost *rhost ) {
Connection *con;
if( rhost->connection != NULL )
return (Connection *)rhost->connection;
con=connection_tcp_create( rhost );
return con;
}
static int connection_tcp_release( struct TcpConnection *con ) {
}
static int connection_tcp_destroy( struct TcpConnection *con ) {
ap_log_error( APLOG_MARK, APLOG_EMERG, NULL,
"Closing connection");
if(con==NULL) return 0;
if( con->bsocket!=NULL ) {
ap_bclose( con->bsocket );
ap_pclosesocket( con->pool, con->socket );
}
con->bsocket=NULL;
con->socket=0;
con->host->connection=NULL;
/* XXX free ? */
/* XXX leak - either create subpool, or reuse the connection */
return 0;
}
static int connection_tcp_send_message( TcpConnection *con, MsgBuffer *msg ) {
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->socket, 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( TcpConnection *con, unsigned char *buff, int msglen ) {
int rdlen=0;
int i;
while( rdlen < msglen ) {
i=read( con->socket, buff + rdlen, msglen - rdlen );
/* printf( "Read: %d %d %x %x %x\n", i, rdlen, i, rdlen, msglen ); */
if(i==-1) {
if(errno==EAGAIN) {
ap_log_error( APLOG_MARK, APLOG_EMERG, NULL,
"EAGAIN, continue reading");
}
else {
ap_log_error( APLOG_MARK, APLOG_EMERG, NULL,
"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( struct TcpConnection *con, MsgBuffer *msg ) {
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 );
/* 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 ); */
/* ap_log_error( APLOG_MARK, APLOG_EMERG, NULL,
/* "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 );
if( i<0) return i;
/* b_dump( msg, " RCV: " ); */
return 0;
}
/* -------------------- #include "module_c.c" -------------------- */
/* Apache-specific code, to be included in modules
A better aproach to OO in C is needed ( instead of include and define )...
*/
/*
module doors_connector_module;
*/
typedef struct {
/** Methods */
/* "public" fields, in all protocol modules */
int debug;
pool *config_pool;
server_rec *server_rec;
int hostc;
RemoteHost **hosts;
} Connector;
/* ---------------------------------------- */
static int connector_fixups(request_rec *r) {
if( (r->content_type != NULL ) ||
(r->handler != NULL ) )
return DECLINED;
/* File not found - it may be a servlet */
/* XXX Doing that means File not found will be handled by tomcat */
printf("FIXUP: %s %s \n", r->filename , r->unparsed_uri );
r->handler = CONNECTOR_HANDLE_NAME ;
return DECLINED;
}
static int connector_handler(request_rec *r) {
void *sess;
MsgBuffer *msg;
Connector *rpm;
RemoteHost *rhost;
Connection *cn;
int err;
rpm=(Connector *)ap_get_module_config(r->server->module_config,
& CONNECTOR_MODULE );
/* A load-balancing module will set a note with the rhost to use,
we'll search it in hosts */
rhost=rpm->hosts[0];
/* XXX Send only the relevant information */
ap_add_cgi_vars(r);
ap_add_common_vars(r);
msg = b_new( r->pool );
b_set_buffer_size( msg, MAX_BUFF_SIZE);
b_reset( msg );
encode_request( msg , r );
cn=connection_get( rhost );
if(cn==NULL) {
return NOT_FOUND;
}
err= connection_send_message( cn, msg );
if(err<0) {
/* Disconect */
connection_destroy( cn );
ap_log_error( APLOG_MARK, APLOG_EMERG, NULL,
"Error sending request %d\n", err);
/* XXX retry once !!! */
return NOT_FOUND;
}
while( 1 ) {
int err=connection_get_message( cn, msg );
/* b_dump(msg, "Get Message: " ); */
if( err < 0 ) {
ap_log_error( APLOG_MARK, APLOG_EMERG, NULL,
"Error reading request %d\n", err);
// XXX cleanup, close connection if packet error
connection_destroy( cn );
return NOT_FOUND;
}
if( b_getCode( msg ) == END_RESPONSE )
break;
err=process_callback( msg, r );
if( err == HAS_RESPONSE ) {
err=connection_send_message( cn, msg );
if( err < 0 ) {
ap_log_error( APLOG_MARK, APLOG_EMERG, NULL,
"Error reading response1 %d\n", err);
connection_destroy( cn );
return NOT_FOUND;
}
}
if( err < 0 ) break; /* XXX error */
}
connection_release( cn );
return OK;
}
/* ---------------------------------------- */
/**
Standard Apache configuration handling - create and maintain config struct
Configuration directives
*/
static const char *add_host(cmd_parms *cmd, void *module_c, char *name, char *arg1, char *arg2);
static void *create_connector_config(pool *p, server_rec *server)
{
Connector *rpm = (Connector *) ap_palloc(p, sizeof(Connector));
rpm->config_pool=p;
rpm->debug=1;
rpm->server_rec=server;
rpm->hosts = (RemoteHost **)ap_palloc( rpm->config_pool, MAX_HOSTS * sizeof( void *) );
add_host( NULL, rpm, "default", DEFAULT_ARG1, DEFAULT_ARG2 );
/* XXX check alloc error, return NULL if any */
return rpm;
}
/* XXX Not fully implemented */
static const char *add_host(cmd_parms *cmd, void *module_c, char *name, char *arg1, char *arg2)
{
/* XXX !!! Error checking - return real message since it's a config problem*/
Connector *rpm=(Connector *)module_c;
rpm->hosts[0]= rhost_new( rpm->config_pool, name , arg1, arg2);
if( rpm->debug ) ap_log_error( APLOG_MARK, APLOG_EMERG, rpm->server_rec,
"Add host %s %s", name, arg1);
return NULL;
}
static const char *set_debug(cmd_parms *cmd, void *module_c, char *arg1)
{
Connector *rpm=(Connector *)module_c;
rpm->debug=atoi(arg1);
return NULL;
}
/* -------------------- #include "connection_tcp.c -------------------- */
/**
Module registration data ( sort of Module Interface )
*/
/* List of handlers */
static handler_rec connector_handlers[] = {
{CONNECTOR_HANDLE_NAME , connector_handler}, // XXX remove, separate module
{NULL}
};
/* List of configuration directives */
static command_rec connector_cmds[] = {
{CONNECTOR "Connector", add_host , NULL, RSRC_CONF, TAKE23,
"Set a connector, default is apconnector "},
{CONNECTOR "ConnectorDebug", set_debug, NULL, RSRC_CONF, TAKE1,
"Debug level for Connector"},
{NULL}
};
/* Apache module descriptor */
/* Assume at least Apache 1.3 - no check for >19970622 ( it was removed from
most Apache modules I saw) */
module MODULE_VAR_EXPORT ajp23_module = {
STANDARD_MODULE_STUFF,
NULL, /* module initializer */
NULL, /* per-directory config creator */
NULL, /* dir config merger */
create_connector_config, /* server config creator */
NULL, /* server config merger */
connector_cmds, /* command table */
connector_handlers, /* [7] list of handlers */
NULL, /* [2] filename-to-URI translation */
NULL, /* [5] check/validate user_id */
NULL, /* [6] check user_id is valid *here* */
NULL, /* [4] check access by host address */
NULL, /* [7] MIME type checker/setter */
connector_fixups, /* [8] fixups */
NULL, /* [10] logger */
NULL, /* [3] header parser */
NULL, /* apache child process initializer */
NULL, /* apache child process exit/cleanup */
NULL /* [1] post read_request handling */
};