commit f8cb76e84928203751649ca97c233baf40a2c1f1 Author: simon <> Date: Wed Oct 8 20:11:27 1997 +0000 Generalised Internet Listener Daemon diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..979ddc8 --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +# Makefile for itinerary engine utilities + +CC= gcc +CFLAGS= -g +LD= gcc +LDFLAGS= -g +BINDIR= /usr/local/bin +TARGETS= gild +COMPONENTS = gild.o wrapper.o config.o + +all: $(TARGETS) + +.c.o: + $(CC) $(CFLAGS) -c $< + +gild: $(COMPONENTS) gild.h Makefile + $(LD) $(LDFLAGS) -o gild $(COMPONENTS) + +clean: + rm core *.o $(TARGETS) + +install: $(TARGETS) + install --strip $(TARGETS) $(BINDIR) diff --git a/config.c b/config.c new file mode 100644 index 0000000..62c7650 --- /dev/null +++ b/config.c @@ -0,0 +1,115 @@ +/**************************************************************************\ +* * +* Project: Gild * +* config.c * +* * +* Purpose: Handle configuration file * +* * +* Author : Simon Brooke * +* Copyright: (c) Simon Brooke 1997 * +* Version : 0.1 * +* Created : 8th October 1997 * +* * +\**************************************************************************/ + +#include "gild.h" + +extern char errorBuff[]; /* where I assemble logging messages */ +handler * handlers = ( handler *) null; + /* the list of handlers I handle */ + +void parse_config( char * path) +/* parse the config file and identify the handlers I handle */ +{ + FILE * configFile; /* the file handle from which to load config */ + char * line[ 1024]; /* a buffer to read lines into */ + + + sprintf( errorBuff, "Loading configuration from %s", path); + error( NOTICE); + + configFile = fopen( path, "r"); + + if ( configFile == ( FILE *)null) + { + sprintf( errorBuff, "failed to open configuration file %s: %s", + path, strerror( errno)); + error( FATAL_ERROR); + } + + while( ! feof( configFile)) + { + char buff[ 1024], protocol[ 1024], pattern[ 1024], command[ 1024]; + int port; + + fgets( buff, 1024, configFile); + /* get a line from the config file */ + if ( buff[ 0] == '#'); + /* it's a comment, and can be ignored */ + else if ( fscanf( configFile, "%s %d %s %s", protocol, &port, + pattern, command) == 4) + /* otherwise look for four fields. If + we find them... */ + { + handler * newhandler = + ( struct handler *) malloc( sizeof( struct handler)); + /* create a handler */ + + if ( newhandler == ( handler *) null) + { /* unlikely, but... best check */ + sprintf( errorBuff, + "out of memory whilst allocating handler?"); + error( FATAL_ERROR); + } + + /* and load it with the values we found */ + newhandler->port = port; + newhandler->protocol = strdup( protocol); + newhandler->pattern = regcomp( pattern); + newhandler->command = strdup( command); + /* then splice it into the handler chain */ + newhandler->next = handlers; + handlers = newhandler; + + /* and log it. */ + sprintf( errorBuff, + "registering handler [%s] for protocol %s", + newhandler->command, newhandler->protocol); + error( NOTICE); + + /* ultimately we will deal with + listening on multiple ports, but + not yet! */ + if ( newhandler->next != null) + { + if ( newhandler->next->port != port) + { + sprintf( errorBuff, + "port for %s [%d] differs from %s [%d] - this version of GILD only handles one port!", + protocol, port, newhandler->next->protocol, + newhandler->next->port); + error( FATAL_ERROR); + } + } + } + } +} + +char * get_handler_command( char * match) +/* find a handler whose pattern matches match, and return it's command */ +{ + handler * h; + char * command = null; + + for ( h = handlers; ( command == null) && ( h != null); h = h->next) + /* scan down the list of handlers looking + for a match... */ + { + if ( 0) /* ( regexec( h->pattern, match)) */ + { + command = h->command; + } + } + + return( command); +} diff --git a/gild b/gild new file mode 100755 index 0000000..9f0583e Binary files /dev/null and b/gild differ diff --git a/gild.c b/gild.c new file mode 100644 index 0000000..b3c5a5b --- /dev/null +++ b/gild.c @@ -0,0 +1,166 @@ +/***********************************************************************\ +* * +* Project: Gild * +* gild.c * +* * +* Purpose: Generalised Internet Listener Daemon * +* -- a daemon which listens for requests on a specified * +* IP port, and despatches them to specified handlers * +* depending on the content of the first line. * +* * +* Author : Simon Brooke * +* Copyright: (c) Simon Brooke 1997 * +* Version : 0.1 * +* Created : 5th October 1997 * +* * +\***********************************************************************/ + +#include "gild.h" + +int port = DEFAULT_PORT_NO; /* the port I shall listen on */ +char errorBuff[ 1024]; /* somewhere to assemble error messages */ +extern handler * handlers; + /* the list of handlers I support */ +FILE * logstream = stderr; /* where I stick log messages */ + + +void error( int severity) +/* log the current contents of errorBuff and then if severity is bad die */ +{ + fprintf( logstream, "%s\n", errorBuff); + + switch ( severity) + { + case FATAL_ERROR: + exit( 1); + break; + } +} + + +int main( int argc, char * argv[]) +{ + char * configPath = CONFIG_PATH; /* the path to my default config file */ + int arg; /* the argument being handled */ + int keyhole; /* where I listen, of course */ + struct sockaddr_in * address = + ( struct sockaddr_in *)malloc( sizeof( struct sockaddr_in)); + /* the address I bind the keyhole to */ + + sprintf( errorBuff, "GILD starting..."); + error( NOTICE); + + for ( arg = 1; argc > arg; arg ++) + { /* process arguments */ + switch ( argv[ arg][ 0]) + { + case '-': + switch( argv[ arg][ 1]) + { + case 'f': /* specify a config file to load */ + arg ++; + configPath = argv[ arg]; + break; + default: + sprintf( errorBuff, + "unrecognised command line switch [-%c]", + argv[ arg][ 1]); + error( FATAL_ERROR); + break; + } + default: + sprintf( errorBuff, "unrecognised command line token [%s]", + argv[ arg]); + } + } + + parse_config( configPath); + + keyhole = socket( AF_INET, SOCK_STREAM, 0); + if ( keyhole == -1) + { + sprintf( errorBuff, "failed to intialise socket"); + error( FATAL_ERROR); + } + + memset( address, 0, sizeof( address)); + /* sanitation */ + + /* now set up the address preparatory + to binding it */ + address->sin_family = AF_INET; + /* it's an internet address */ + address->sin_addr.s_addr = htonl( INADDR_ANY); + /* and we don't mind where it comes from */ + address->sin_port = htons( port); + /* that's the port we listen on, remember? */ + + if ( bind( keyhole, ( struct sockaddr *)address, + sizeof( struct sockaddr_in)) == -1) + { /* attempt to bind keyhole to address */ + sprintf( errorBuff, "failed to bind socket"); + error( FATAL_ERROR); + } + +#ifndef DEBUG + /* we become a real class one daemon */ + if ( fork() != 0) exit(0); + /* the parent exits */ + setsid(); /* release the controlling tty */ +#endif + + if ( listen( keyhole, MAX_PENDING_REQUESTS) == -1) + { + sprintf( errorBuff, "failed in listen()?"); + error( FATAL_ERROR); + } + sprintf( errorBuff, "GILD: awaiting requests"); + error( NOTICE); + + for ever + { + struct sockaddr_in * client = + ( struct sockaddr_in *) malloc( sizeof( struct sockaddr_in)); + /* the address of the client calling in */ + int conversation; /* a handle on the conversation we're having */ + int clientsize = sizeof( struct sockaddr_in); + /* the size of the client object */ + + if ( client == 0) + { /* unlikely, but might as well check... */ + sprintf( errorBuff, "Out of memory?"); + error( FATAL_ERROR); + } + memset( client, 0, sizeof( client)); + /* sanitation */ + + conversation = accept( keyhole, ( struct sockaddr *)client, + &clientsize); + + if ( conversation == -1) + { /* again, check we set it up OK */ + sprintf( errorBuff, "Could not establish conversation [%d]", + errno); + error( FATAL_ERROR); + } + + sprintf( errorBuff, "Connection received"); + error( NOTICE); + + switch( fork()) + { + case -1: /* Blew it: whinge and die */ + sprintf( errorBuff, "failed to fork?"); + error( FATAL_ERROR); + break; + case 0: /* I'm the child */ + close( keyhole); + + wrapper( conversation); + /* wrapper (q.v.) handles the conversation */ + break; + default: /* I'm the parent */ + close( conversation); + } + } +} diff --git a/gild.conf b/gild.conf new file mode 100644 index 0000000..ac6e8dc --- /dev/null +++ b/gild.conf @@ -0,0 +1,4 @@ +http 8080 HTTP/0\.9 handlers/http +crp 8080 CRP/1.* handlers/crp + + diff --git a/gild.h b/gild.h new file mode 100644 index 0000000..9327b3b --- /dev/null +++ b/gild.h @@ -0,0 +1,67 @@ +/**************************************************************************\ +* * +* Project: Gild * +* gild.h * +* * +* Purpose: public header file for gild server. * +* * +* Author : Simon Brooke * +* Copyright: (c) Simon Brooke 1997 * +* Version : 0.1 * +* Created : 6th October 1997 * +* * +\**************************************************************************/ + +#define _POSIX_SOURCE +/* this is a fudge. The whole thing depends on fdopen, and I'm having + great difficulty making it work */ + +#include +#include +#include +#include +#include +#include + +#include + + +#define CONFIG_PATH "/usr/local/etc/gild/gild.conf" +#define DEFAULT_PORT_NO 1984 +#define MAX_PENDING_REQUESTS 5 + +#define null (((void *) 0)) + +#define FATAL_ERROR 1 +#define NOTICE 0 + +#define DEBUG 1 + +#define ever (;;) + +typedef struct handler +{ + struct handler * next; /* next one down the chain */ + int port; /* the port on which I listen */ + char * protocol; /* a name for the protocol handled */ + regexp * pattern; /* the pattern to match to select this + handler */ + char * command; /* the command to invoke this handler */ +} handler; + +void error( int severity); +/* log the current contents of errorBuff and then if severity is bad die */ + +char * get_handler_command( char * match); +/* find a handler whose pattern matches match, and return it's command */ + +void parse_config( char * path); +/* parse the config file and identify the handlers I handle */ + +void wrapper( int conversation); +/* 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 + 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 */ diff --git a/gild.sed b/gild.sed new file mode 100644 index 0000000..b1c0258 --- /dev/null +++ b/gild.sed @@ -0,0 +1,3 @@ +s/guild/gild/g +s/Guild/Gild/g +s/GUILD/GILD/g diff --git a/wrapper.c b/wrapper.c new file mode 100644 index 0000000..fbc863f --- /dev/null +++ b/wrapper.c @@ -0,0 +1,102 @@ +/**************************************************************************\ +* * +* Project: Gild * +* wrapper.c * +* * +* Purpose: Given a open socket connected to a client, handle * +* the conversation with the client by detecting the protocol * +* in use and invoking the appropriate handler * +* * +* Author : Simon Brooke * +* Copyright: (c) Simon Brooke 1997 * +* Version : 0.1 * +* Created : 7th October 1997 * +* * +\**************************************************************************/ + +#include "gild.h" + +extern char * errorBuff; + +void wrapper( int conversation) +/* 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 + 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 */ +{ + char firstln[ 1024]; + char * command; + int i, hear, say = conversation; + FILE * c_rx, * c_tx; + + printf( "wrapper started with fdes [%d]\n", + conversation); + + hear = dup( conversation); /* creat two handles on conversation */ + say = dup( conversation); /* one for reading and one for writing */ + +#ifdef globba + for( i = 0; ( i < 1024 ) && ( ( i == 0) || ( firstln[ i - 1] > ' ')); i++) + { + read( hear, ( char *)firstln + i, 1); + /* read a control-terminated line from the + conversation, one byte at a time + (prolly a better way of doing this) */ + puts( firstln); + } + firstln[ i] = '\0'; /* terminate the string */ +#endif + + recv( hear, firstln, 80, MSG_PEEK); + + puts( "looking for command"); + + command = get_handler_command( firstln); + /* and find the appropriate handler */ + + printf( "got command [%s]\n", command); + + if ( ! command) /* didn't find one */ + { + sprintf( errorBuff, "no handler registered for %s", firstln); + error( FATAL_ERROR); + } + else /* did find one */ + { + sprintf( errorBuff, "using handler %s for protocol %s", + command, firstln); + error( FATAL_ERROR); + } + + recv( hear, firstln, 1024, 0); + exit( 0); + + if ( dup2( hear, 0) == -1) + { + sprintf( errorBuff, + "failed to duplicate conversation [%d] onto stdin: %s", + hear, strerror( errno)); + error( FATAL_ERROR); + } + dup2( say, 1); + { + sprintf( errorBuff, + "failed to duplicate conversation [%d] onto stdout: %s", + say, strerror( errno)); + error( FATAL_ERROR); + } + +/* gets( firstln); */ + puts( "hello!\n"); +/* puts( firstln); */ + + puts("\tClosing..."); + exit( 0); +} + + + + +