Significantly improved; wrapper processes given configurable 'die' timeouts;
client identified and passed in environment to handlers; logging through syslogd sorted and working well.
This commit is contained in:
parent
715dec1ad6
commit
f54afde746
6
Makefile
6
Makefile
|
@ -1,4 +1,5 @@
|
||||||
# Makefile for itinerary engine utilities
|
# Makefile for itinerary engine utilities
|
||||||
|
# $Header$
|
||||||
|
|
||||||
CC= gcc
|
CC= gcc
|
||||||
CFLAGS= -g
|
CFLAGS= -g
|
||||||
|
@ -6,7 +7,7 @@ LD= gcc
|
||||||
LDFLAGS= -g
|
LDFLAGS= -g
|
||||||
BINDIR= /usr/local/bin
|
BINDIR= /usr/local/bin
|
||||||
TARGETS= gild
|
TARGETS= gild
|
||||||
COMPONENTS = gild.o wrapper.o config.o
|
COMPONENTS = gild.o wrapper.o config.o log.o
|
||||||
|
|
||||||
all: $(TARGETS)
|
all: $(TARGETS)
|
||||||
|
|
||||||
|
@ -21,3 +22,6 @@ clean:
|
||||||
|
|
||||||
install: $(TARGETS)
|
install: $(TARGETS)
|
||||||
install --strip $(TARGETS) $(BINDIR)
|
install --strip $(TARGETS) $(BINDIR)
|
||||||
|
|
||||||
|
version: $(TARGETS)
|
||||||
|
cvs commit gild.c wrapper.c config.c log.c Makefile gild.h gild.conf
|
29
config.c
29
config.c
|
@ -26,7 +26,7 @@ int parse_config( char * path)
|
||||||
int n = 0; /* number of handlers we find */
|
int n = 0; /* number of handlers we find */
|
||||||
|
|
||||||
sprintf( errorBuff, "Loading configuration from %s", path);
|
sprintf( errorBuff, "Loading configuration from %s", path);
|
||||||
error( NOTICE);
|
error( LOG_NOTICE);
|
||||||
|
|
||||||
configFile = fopen( path, "r");
|
configFile = fopen( path, "r");
|
||||||
|
|
||||||
|
@ -34,19 +34,21 @@ int parse_config( char * path)
|
||||||
{
|
{
|
||||||
sprintf( errorBuff, "failed to open configuration file %s: %s",
|
sprintf( errorBuff, "failed to open configuration file %s: %s",
|
||||||
path, strerror( errno));
|
path, strerror( errno));
|
||||||
error( FATAL_ERROR);
|
error( LOG_ERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
while( ! feof( configFile))
|
while( ! feof( configFile))
|
||||||
{
|
{
|
||||||
char buff[ 1024], protocol[ 1024], pattern[ 1024], command[ 1024];
|
char buff[ 1024], protocol[ 1024], pattern[ 1024], command[ 1024];
|
||||||
|
int timeout; /* how long to wait for the handler to
|
||||||
|
complete */
|
||||||
|
|
||||||
fgets( buff, 1024, configFile);
|
fgets( buff, 1024, configFile);
|
||||||
/* get a line from the config file */
|
/* get a line from the config file */
|
||||||
if ( buff[ 0] == '#');
|
if ( buff[ 0] == '#');
|
||||||
/* it's a comment, and can be ignored */
|
/* it's a comment, and can be ignored */
|
||||||
else if ( fscanf( configFile, "%s %s %s", protocol,
|
else if ( fscanf( configFile, "%s %s %s %d", protocol,
|
||||||
pattern, command) == 3)
|
pattern, command, &timeout) == 4)
|
||||||
/* otherwise look for four fields. If
|
/* otherwise look for four fields. If
|
||||||
we find them... */
|
we find them... */
|
||||||
{
|
{
|
||||||
|
@ -62,7 +64,7 @@ int parse_config( char * path)
|
||||||
{ /* unlikely, but... best check */
|
{ /* unlikely, but... best check */
|
||||||
sprintf( errorBuff,
|
sprintf( errorBuff,
|
||||||
"out of memory whilst allocating handler?");
|
"out of memory whilst allocating handler?");
|
||||||
error( FATAL_ERROR);
|
error( LOG_ERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
regcomp( patternBuff, pattern,
|
regcomp( patternBuff, pattern,
|
||||||
|
@ -71,6 +73,8 @@ int parse_config( char * path)
|
||||||
newhandler->protocol = strdup( protocol);
|
newhandler->protocol = strdup( protocol);
|
||||||
newhandler->pattern = patternBuff;
|
newhandler->pattern = patternBuff;
|
||||||
newhandler->command = strdup( command);
|
newhandler->command = strdup( command);
|
||||||
|
newhandler->timeout = timeout;
|
||||||
|
|
||||||
/* then splice it into the handler chain */
|
/* then splice it into the handler chain */
|
||||||
newhandler->next = handlers;
|
newhandler->next = handlers;
|
||||||
handlers = newhandler;
|
handlers = newhandler;
|
||||||
|
@ -81,28 +85,27 @@ int parse_config( char * path)
|
||||||
sprintf( errorBuff,
|
sprintf( errorBuff,
|
||||||
"registering handler [%s] for protocol %s",
|
"registering handler [%s] for protocol %s",
|
||||||
newhandler->command, newhandler->protocol);
|
newhandler->command, newhandler->protocol);
|
||||||
error( NOTICE);
|
error( LOG_NOTICE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ( n); /* say how many we found */
|
return ( n); /* say how many we found */
|
||||||
}
|
}
|
||||||
|
|
||||||
char * get_handler_command( char * match)
|
handler * get_handler( char * match)
|
||||||
/* find a handler whose pattern matches match, and return it's command */
|
/* find a handler whose pattern matches match, and return it's command */
|
||||||
{
|
{
|
||||||
handler * h;
|
handler * h = null, * i;
|
||||||
char * command = null;
|
|
||||||
regmatch_t pmatch[ 2];
|
regmatch_t pmatch[ 2];
|
||||||
|
|
||||||
for ( h = handlers; ( command == null) && ( h != null); h = h->next)
|
for ( i = handlers; ( h == null) && ( i != null); i = i->next)
|
||||||
/* scan down the list of handlers looking
|
/* scan down the list of handlers looking
|
||||||
for a match... */
|
for a match... */
|
||||||
{
|
{
|
||||||
if ( regexec( h->pattern, match, 2, pmatch, 0) == 0)
|
if ( regexec( i->pattern, match, 2, pmatch, 0) == 0)
|
||||||
{
|
{
|
||||||
command = h->command;
|
h = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return( command);
|
return( h);
|
||||||
}
|
}
|
||||||
|
|
38
gild.c
38
gild.c
|
@ -49,8 +49,7 @@ int main( int argc, char * argv[])
|
||||||
( struct sockaddr_in *)malloc( sizeof( struct sockaddr_in));
|
( struct sockaddr_in *)malloc( sizeof( struct sockaddr_in));
|
||||||
/* the address I bind the keyhole to */
|
/* the address I bind the keyhole to */
|
||||||
|
|
||||||
sprintf( errorBuff, "GILD starting...");
|
fprintf( stderr, "%s starting...", GILD_ID);
|
||||||
error( LOG_NOTICE);
|
|
||||||
|
|
||||||
for ( arg = 1; argc > arg; arg ++)
|
for ( arg = 1; argc > arg; arg ++)
|
||||||
{ /* process arguments */
|
{ /* process arguments */
|
||||||
|
@ -68,29 +67,31 @@ int main( int argc, char * argv[])
|
||||||
port = atoi( argv[ arg]);
|
port = atoi( argv[ arg]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sprintf( errorBuff,
|
fprintf( stderr,
|
||||||
"unrecognised command line switch [-%c]",
|
"unrecognised command line switch [-%c]",
|
||||||
argv[ arg][ 1]);
|
argv[ arg][ 1]);
|
||||||
error( LOG_ERR);
|
exit( 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
sprintf( errorBuff, "unrecognised command line token [%s]",
|
fprintf( stderr, "unrecognised command line token [%s]",
|
||||||
argv[ arg]);
|
argv[ arg]);
|
||||||
|
exit( 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( parse_config( configPath) == 0)
|
if ( parse_config( configPath) == 0)
|
||||||
{
|
{
|
||||||
sprintf( errorBuff, "failed to load any handlers");
|
fprintf( stderr, "failed to load any handlers");
|
||||||
error( LOG_ERR);
|
exit( 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
keyhole = socket( AF_INET, SOCK_STREAM, 0);
|
keyhole = socket( AF_INET, SOCK_STREAM, 0);
|
||||||
if ( keyhole == -1)
|
if ( keyhole == -1)
|
||||||
{
|
{
|
||||||
sprintf( errorBuff, "failed to intialise socket");
|
fprintf( stderr, "failed to intialise socket");
|
||||||
error( LOG_ERR);
|
exit( 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset( address, 0, sizeof( address));
|
memset( address, 0, sizeof( address));
|
||||||
|
@ -108,8 +109,8 @@ int main( int argc, char * argv[])
|
||||||
if ( bind( keyhole, ( struct sockaddr *)address,
|
if ( bind( keyhole, ( struct sockaddr *)address,
|
||||||
sizeof( struct sockaddr_in)) == -1)
|
sizeof( struct sockaddr_in)) == -1)
|
||||||
{ /* attempt to bind keyhole to address */
|
{ /* attempt to bind keyhole to address */
|
||||||
sprintf( errorBuff, "failed to bind socket");
|
fprintf( stderr, "failed to bind socket");
|
||||||
error( LOG_ERR);
|
exit( 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef DEBUG
|
#ifndef DEBUG
|
||||||
|
@ -124,7 +125,7 @@ int main( int argc, char * argv[])
|
||||||
sprintf( errorBuff, "failed in listen()?");
|
sprintf( errorBuff, "failed in listen()?");
|
||||||
error( LOG_ERR);
|
error( LOG_ERR);
|
||||||
}
|
}
|
||||||
sprintf( errorBuff, "GILD: awaiting requests on port %d", port);
|
sprintf( errorBuff, "started; awaiting requests on port %d", port);
|
||||||
error( LOG_NOTICE);
|
error( LOG_NOTICE);
|
||||||
|
|
||||||
for ever
|
for ever
|
||||||
|
@ -132,6 +133,8 @@ int main( int argc, char * argv[])
|
||||||
struct sockaddr_in * client =
|
struct sockaddr_in * client =
|
||||||
( struct sockaddr_in *) malloc( sizeof( struct sockaddr_in));
|
( struct sockaddr_in *) malloc( sizeof( struct sockaddr_in));
|
||||||
/* the address of the client calling in */
|
/* the address of the client calling in */
|
||||||
|
char * client_addr = null;
|
||||||
|
/* the network address of the client */
|
||||||
int conversation; /* a handle on the conversation we're having */
|
int conversation; /* a handle on the conversation we're having */
|
||||||
int clientsize = sizeof( struct sockaddr_in);
|
int clientsize = sizeof( struct sockaddr_in);
|
||||||
/* the size of the client object */
|
/* the size of the client object */
|
||||||
|
@ -147,6 +150,9 @@ int main( int argc, char * argv[])
|
||||||
conversation = accept( keyhole, ( struct sockaddr *)client,
|
conversation = accept( keyhole, ( struct sockaddr *)client,
|
||||||
&clientsize);
|
&clientsize);
|
||||||
|
|
||||||
|
client_addr = strdup( inet_ntoa( client->sin_addr));
|
||||||
|
|
||||||
|
|
||||||
if ( conversation == -1)
|
if ( conversation == -1)
|
||||||
{ /* again, check we set it up OK */
|
{ /* again, check we set it up OK */
|
||||||
sprintf( errorBuff, "Could not establish conversation [%d]",
|
sprintf( errorBuff, "Could not establish conversation [%d]",
|
||||||
|
@ -154,9 +160,6 @@ int main( int argc, char * argv[])
|
||||||
error( LOG_ERR);
|
error( LOG_ERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf( errorBuff, "Connection received");
|
|
||||||
error( LOG_NOTICE);
|
|
||||||
|
|
||||||
switch( fork())
|
switch( fork())
|
||||||
{
|
{
|
||||||
case -1: /* Blew it: whinge and die */
|
case -1: /* Blew it: whinge and die */
|
||||||
|
@ -166,11 +169,14 @@ int main( int argc, char * argv[])
|
||||||
case 0: /* I'm the child */
|
case 0: /* I'm the child */
|
||||||
close( keyhole);
|
close( keyhole);
|
||||||
|
|
||||||
wrapper( conversation);
|
wrapper( conversation, client_addr);
|
||||||
/* wrapper (q.v.) handles the conversation */
|
/* wrapper (q.v.) handles the conversation */
|
||||||
break;
|
break;
|
||||||
default: /* I'm the parent */
|
default: /* I'm the parent */
|
||||||
close( conversation);
|
close( conversation);
|
||||||
|
free( client); /* prevent memory bloat */
|
||||||
|
if ( client_addr != null)
|
||||||
|
free( client_addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
10
gild.conf
10
gild.conf
|
@ -1,5 +1,5 @@
|
||||||
|
# Sample GILD configuration file
|
||||||
http ^.*HTTP/[0-1] handlers/http
|
# $Header$
|
||||||
crp CRP/1 handlers/crp
|
# protocol pattern handler timeout
|
||||||
|
http ^.*HTTP/[0-1] handlers/http 5
|
||||||
|
crp CRP/1 handlers/crp 10
|
||||||
|
|
23
gild.h
23
gild.h
|
@ -16,13 +16,17 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
|
||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <linux/in.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <syslog.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include <linux/in.h>
|
|
||||||
|
|
||||||
#define GILD_NAME "gild"
|
#define GILD_NAME "gild"
|
||||||
#define GILD_VERSION "$Revision$"
|
#define GILD_VERSION "$Revision$"
|
||||||
|
@ -36,7 +40,6 @@
|
||||||
#define STDOUT_FILENO 1
|
#define STDOUT_FILENO 1
|
||||||
#define STDERR_FILENO 2
|
#define STDERR_FILENO 2
|
||||||
|
|
||||||
#define DEBUG 1
|
|
||||||
|
|
||||||
#define ever (;;)
|
#define ever (;;)
|
||||||
#define null (((void *) 0))
|
#define null (((void *) 0))
|
||||||
|
@ -49,12 +52,14 @@ typedef struct handler
|
||||||
regex_t * pattern; /* the pattern to match to select this
|
regex_t * pattern; /* the pattern to match to select this
|
||||||
handler */
|
handler */
|
||||||
char * command; /* the command to invoke this handler */
|
char * command; /* the command to invoke this handler */
|
||||||
|
int timeout; /* how long to allow for this handler to
|
||||||
|
complete, or 0 if infinite */
|
||||||
} handler;
|
} handler;
|
||||||
|
|
||||||
void error( int severity);
|
void error( int severity);
|
||||||
/* log the current contents of errorBuff and then if severity is bad die */
|
/* log the current contents of errorBuff and then if severity is bad die */
|
||||||
|
|
||||||
char * get_handler_command( char * match);
|
handler * get_handler( char * match);
|
||||||
/* find a handler whose pattern matches match, and return it's command */
|
/* find a handler whose pattern matches match, and return it's command */
|
||||||
|
|
||||||
int log( int level, char *message);
|
int log( int level, char *message);
|
||||||
|
@ -63,10 +68,6 @@ int log( int level, char *message);
|
||||||
int parse_config( char * path);
|
int parse_config( char * path);
|
||||||
/* parse the config file and identify the handlers I handle */
|
/* parse the config file and identify the handlers I handle */
|
||||||
|
|
||||||
void wrapper( int conversation);
|
void wrapper( int conversation, char * client_id);
|
||||||
/* conversation is the handle on an open socket communicating with a
|
/* conversation is the handle on an open socket communicating with a
|
||||||
client. What I want to do is quite simple, and there must be a
|
client. */
|
||||||
straightforward way of doing it: attach the conversation to both
|
|
||||||
the standard input and the standard output of a process, and then
|
|
||||||
exec the handler within that process... I can't (at present) find
|
|
||||||
an easy way of doing that, however */
|
|
||||||
|
|
4
log.c
4
log.c
|
@ -21,8 +21,8 @@
|
||||||
int log( int level, char *message)
|
int log( int level, char *message)
|
||||||
/* hand this message over to the syslog daemon for recording */
|
/* hand this message over to the syslog daemon for recording */
|
||||||
{
|
{
|
||||||
openlog( GILD_ID, 0, LOG_DAEMON);
|
openlog( GILD_NAME, 0, LOG_DAEMON);
|
||||||
syslog( level, message);
|
syslog( level, message);
|
||||||
closelog);
|
closelog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
41
wrapper.c
41
wrapper.c
|
@ -16,9 +16,17 @@
|
||||||
|
|
||||||
#include "gild.h"
|
#include "gild.h"
|
||||||
|
|
||||||
extern char * errorBuff;
|
char errorBuff[ 1024];
|
||||||
|
|
||||||
void wrapper( int conversation)
|
void die( void) /* inherited from cgi-lib; a way of
|
||||||
|
getting rid of errant programs */
|
||||||
|
{
|
||||||
|
sprintf( errorBuff, "potentially serious: handler over-ran alloted time");
|
||||||
|
error( LOG_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wrapper( int conversation, char * client_id)
|
||||||
/* conversation is the handle on an open socket communicating with a
|
/* conversation is the handle on an open socket communicating with a
|
||||||
client. What I want to do is quite simple, and there must be a
|
client. What I want to do is quite simple, and there must be a
|
||||||
straightforward way of doing it: attach the conversation to both
|
straightforward way of doing it: attach the conversation to both
|
||||||
|
@ -27,10 +35,7 @@ void wrapper( int conversation)
|
||||||
an easy way of doing that, however */
|
an easy way of doing that, however */
|
||||||
{
|
{
|
||||||
char firstln[ 1024];
|
char firstln[ 1024];
|
||||||
char * command;
|
handler * command = null;
|
||||||
|
|
||||||
printf( "wrapper started with fdes [%d]\n",
|
|
||||||
conversation);
|
|
||||||
|
|
||||||
recv( conversation, firstln, 80, MSG_PEEK);
|
recv( conversation, firstln, 80, MSG_PEEK);
|
||||||
/* get the first thing the client
|
/* get the first thing the client
|
||||||
|
@ -53,16 +58,34 @@ void wrapper( int conversation)
|
||||||
error( LOG_ERR);
|
error( LOG_ERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
command = get_handler_command( firstln);
|
command = get_handler( firstln);
|
||||||
/* and find the appropriate handler */
|
/* and find the appropriate handler */
|
||||||
if ( ! command) /* didn't find one */
|
if ( command == null) /* didn't find one */
|
||||||
{
|
{
|
||||||
sprintf( errorBuff, "no handler registered for %s", firstln);
|
sprintf( errorBuff, "no handler registered for %s", firstln);
|
||||||
error( LOG_ERR);
|
error( LOG_ERR);
|
||||||
}
|
}
|
||||||
else /* did find one */
|
else /* did find one */
|
||||||
{
|
{
|
||||||
system( command);
|
sprintf( errorBuff,
|
||||||
|
"using handler '%s' to handle %s request from %s",
|
||||||
|
command->command, command->protocol, client_id);
|
||||||
|
error( LOG_NOTICE);
|
||||||
|
/* log the request */
|
||||||
|
|
||||||
|
if ( command->timeout != 0)
|
||||||
|
/* prevent runaway processes; if a
|
||||||
|
timeout has been specified for this
|
||||||
|
handler, enforce it */
|
||||||
|
{
|
||||||
|
signal( SIGALRM,(void (*)())die);
|
||||||
|
alarm( command->timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
setenv( "REMOTE_HOST", client_id, 1);
|
||||||
|
/* set up the handler environment */
|
||||||
|
|
||||||
|
system( command->command);
|
||||||
}
|
}
|
||||||
|
|
||||||
exit( 0);
|
exit( 0);
|
||||||
|
|
Loading…
Reference in a new issue