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
 | ||||
| # $Header$
 | ||||
| 
 | ||||
| CC= gcc | ||||
| CFLAGS= -g | ||||
|  | @ -6,7 +7,7 @@ LD= gcc | |||
| LDFLAGS= -g  | ||||
| BINDIR= /usr/local/bin | ||||
| TARGETS= gild | ||||
| COMPONENTS = gild.o wrapper.o config.o | ||||
| COMPONENTS = gild.o wrapper.o config.o log.o | ||||
| 
 | ||||
| all: $(TARGETS) | ||||
| 
 | ||||
|  | @ -21,3 +22,6 @@ clean: | |||
| 
 | ||||
| install: $(TARGETS) | ||||
| 	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 */ | ||||
| 
 | ||||
|      sprintf( errorBuff, "Loading configuration from %s", path); | ||||
|      error( NOTICE); | ||||
|      error( LOG_NOTICE); | ||||
| 
 | ||||
|      configFile = fopen( path, "r"); | ||||
| 
 | ||||
|  | @ -34,19 +34,21 @@ int parse_config( char * path) | |||
|      { | ||||
| 	  sprintf( errorBuff, "failed to open configuration file %s: %s", | ||||
| 		  path, strerror( errno)); | ||||
| 	  error( FATAL_ERROR); | ||||
| 	  error( LOG_ERR); | ||||
|      } | ||||
| 
 | ||||
|      while( ! feof( configFile)) | ||||
|      { | ||||
| 	  char buff[ 1024], protocol[ 1024], pattern[ 1024], command[ 1024]; | ||||
| 	  int timeout;		/* how long to wait for the handler to
 | ||||
| 	  			   complete */ | ||||
| 	   | ||||
| 	  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 %s %s", protocol, | ||||
| 		      pattern, command) == 3) | ||||
| 	  else if ( fscanf( configFile, "%s %s %s %d", protocol, | ||||
| 		      pattern, command, &timeout) == 4) | ||||
| 				/* otherwise look for four fields. If
 | ||||
|                                    we find them... */ | ||||
| 	  { | ||||
|  | @ -62,7 +64,7 @@ int parse_config( char * path) | |||
| 	       {		/* unlikely, but... best check */ | ||||
| 		    sprintf( errorBuff,  | ||||
| 			    "out of memory whilst allocating handler?"); | ||||
| 		    error( FATAL_ERROR); | ||||
| 		    error( LOG_ERR); | ||||
| 	       } | ||||
| 
 | ||||
| 	       regcomp( patternBuff, pattern,  | ||||
|  | @ -71,6 +73,8 @@ int parse_config( char * path) | |||
| 	       newhandler->protocol = strdup( protocol); | ||||
| 	       newhandler->pattern = patternBuff; | ||||
| 	       newhandler->command = strdup( command); | ||||
| 	       newhandler->timeout = timeout; | ||||
| 
 | ||||
| 				/* then splice it into the handler chain */ | ||||
| 	       newhandler->next = handlers; | ||||
| 	       handlers = newhandler; | ||||
|  | @ -81,28 +85,27 @@ int parse_config( char * path) | |||
| 	       sprintf( errorBuff,  | ||||
| 		       "registering handler [%s] for protocol %s",  | ||||
| 		       newhandler->command, newhandler->protocol); | ||||
| 	       error( NOTICE); | ||||
| 	       error( LOG_NOTICE); | ||||
| 	  } | ||||
|      } | ||||
|      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 */ | ||||
| { | ||||
|      handler * h; | ||||
|      char * command = null; | ||||
|      handler * h = null, * i; | ||||
|      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
 | ||||
| 				   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)); | ||||
| 				/* the address I bind the keyhole to */ | ||||
| 
 | ||||
|      sprintf( errorBuff, "GILD starting..."); | ||||
|      error( LOG_NOTICE); | ||||
|      fprintf( stderr, "%s starting...", GILD_ID); | ||||
| 
 | ||||
|      for ( arg = 1; argc > arg; arg ++) | ||||
|      {				/* process arguments */ | ||||
|  | @ -68,29 +67,31 @@ int main( int argc, char * argv[]) | |||
| 		    port = atoi( argv[ arg]); | ||||
| 		    break; | ||||
| 	       default: | ||||
| 		    sprintf( errorBuff,  | ||||
| 		    fprintf( stderr,  | ||||
| 			    "unrecognised command line switch [-%c]", | ||||
| 			    argv[ arg][ 1]); | ||||
| 		    error( LOG_ERR); | ||||
| 		    exit( 1); | ||||
| 		    break; | ||||
| 	       } | ||||
| 	       break; | ||||
| 	  default: | ||||
| 	       sprintf( errorBuff, "unrecognised command line token [%s]", | ||||
| 	       fprintf( stderr, "unrecognised command line token [%s]", | ||||
| 		       argv[ arg]); | ||||
| 	       exit( 1); | ||||
| 	  } | ||||
|      } | ||||
| 
 | ||||
|      if ( parse_config( configPath) == 0) | ||||
|      { | ||||
| 	  sprintf( errorBuff, "failed to load any handlers"); | ||||
| 	  error( LOG_ERR); | ||||
| 	  fprintf( stderr, "failed to load any handlers"); | ||||
| 	  exit( 1); | ||||
|      } | ||||
| 
 | ||||
|      keyhole = socket( AF_INET, SOCK_STREAM, 0); | ||||
|      if ( keyhole == -1) | ||||
|      { | ||||
| 	  sprintf( errorBuff, "failed to intialise socket"); | ||||
| 	  error( LOG_ERR); | ||||
| 	  fprintf( stderr, "failed to intialise socket"); | ||||
| 	  exit( 1); | ||||
|      } | ||||
| 
 | ||||
|      memset( address, 0, sizeof( address)); | ||||
|  | @ -108,8 +109,8 @@ int main( int argc, char * argv[]) | |||
|      if ( bind( keyhole, ( struct sockaddr *)address,  | ||||
| 	       sizeof( struct sockaddr_in)) == -1) | ||||
|      {				/* attempt to bind keyhole to address */ | ||||
| 	  sprintf( errorBuff, "failed to bind socket"); | ||||
| 	  error( LOG_ERR); | ||||
| 	  fprintf( stderr, "failed to bind socket"); | ||||
| 	  exit( 1); | ||||
|      } | ||||
| 
 | ||||
| #ifndef DEBUG | ||||
|  | @ -124,7 +125,7 @@ int main( int argc, char * argv[]) | |||
| 	  sprintf( errorBuff, "failed in listen()?"); | ||||
| 	  error( LOG_ERR); | ||||
|      } | ||||
|      sprintf( errorBuff, "GILD: awaiting requests on port %d", port); | ||||
|      sprintf( errorBuff, "started; awaiting requests on port %d", port); | ||||
|      error( LOG_NOTICE); | ||||
| 
 | ||||
|      for ever | ||||
|  | @ -132,6 +133,8 @@ int main( int argc, char * argv[]) | |||
| 	  struct sockaddr_in * client =  | ||||
| 	       ( struct sockaddr_in *) malloc( sizeof( struct sockaddr_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 clientsize = sizeof( struct sockaddr_in); | ||||
| 				/* the size of the client object */ | ||||
|  | @ -147,6 +150,9 @@ int main( int argc, char * argv[]) | |||
| 	  conversation = accept( keyhole, ( struct sockaddr *)client,  | ||||
| 				&clientsize); | ||||
| 
 | ||||
| 	  client_addr = strdup( inet_ntoa( client->sin_addr)); | ||||
| 
 | ||||
| 
 | ||||
| 	  if ( conversation == -1) | ||||
| 	  {			/* again, check we set it up OK */ | ||||
| 	       sprintf( errorBuff, "Could not establish conversation [%d]", | ||||
|  | @ -154,9 +160,6 @@ int main( int argc, char * argv[]) | |||
| 	       error( LOG_ERR); | ||||
| 	  } | ||||
| 
 | ||||
| 	  sprintf( errorBuff, "Connection received"); | ||||
| 	  error( LOG_NOTICE); | ||||
| 
 | ||||
| 	  switch( fork()) | ||||
| 	  { | ||||
| 	  case -1:		/* Blew it: whinge and die */ | ||||
|  | @ -166,11 +169,14 @@ int main( int argc, char * argv[]) | |||
| 	  case 0:		/* I'm the child */ | ||||
| 	       close( keyhole); | ||||
| 
 | ||||
| 	       wrapper( conversation); | ||||
| 	       wrapper( conversation, client_addr); | ||||
| 				/* wrapper (q.v.) handles the conversation */ | ||||
| 	       break; | ||||
| 	  default:		/* I'm the parent */ | ||||
| 	       close( conversation);  | ||||
| 	       free( client);	/* prevent memory bloat */ | ||||
| 	       if ( client_addr != null) | ||||
| 		    free( client_addr); | ||||
| 	  } | ||||
|      } | ||||
| } | ||||
|  |  | |||
							
								
								
									
										10
									
								
								gild.conf
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								gild.conf
									
									
									
									
									
								
							|  | @ -1,5 +1,5 @@ | |||
| 
 | ||||
| http	^.*HTTP/[0-1]   handlers/http | ||||
| crp	CRP/1		handlers/crp | ||||
| 
 | ||||
| 
 | ||||
| # Sample GILD configuration file | ||||
| # $Header$ | ||||
| # 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 <errno.h> | ||||
| #include <string.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/socket.h> | ||||
| #include <syslog.h> | ||||
| #include <sys/socket.h> | ||||
| 
 | ||||
| #include <linux/in.h> | ||||
| 
 | ||||
| #define GILD_NAME 	"gild" | ||||
| #define GILD_VERSION 	"$Revision$" | ||||
|  | @ -36,7 +40,6 @@ | |||
| #define STDOUT_FILENO 1 | ||||
| #define STDERR_FILENO 2 | ||||
| 
 | ||||
| #define DEBUG 1 | ||||
| 
 | ||||
| #define ever (;;) | ||||
| #define null (((void *) 0)) | ||||
|  | @ -49,12 +52,14 @@ typedef struct handler | |||
|      regex_t * pattern;		/* the pattern to match to select 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; | ||||
| 
 | ||||
| void error( int severity); | ||||
| /* 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 */ | ||||
| 
 | ||||
| int log( int level, char *message); | ||||
|  | @ -63,10 +68,6 @@ int log( int level, char *message); | |||
| int parse_config( char * path); | ||||
| /* 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
 | ||||
|    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 */ | ||||
|    client. */ | ||||
|  |  | |||
							
								
								
									
										4
									
								
								log.c
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								log.c
									
									
									
									
									
								
							|  | @ -21,8 +21,8 @@ | |||
| int log( int level, char *message) | ||||
| /* 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); | ||||
|      closelog); | ||||
|      closelog(); | ||||
| } | ||||
|       | ||||
|  |  | |||
							
								
								
									
										41
									
								
								wrapper.c
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								wrapper.c
									
									
									
									
									
								
							|  | @ -16,9 +16,17 @@ | |||
| 
 | ||||
| #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
 | ||||
|    client. What I want to do is quite simple, and there must be a | ||||
|    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 */ | ||||
| { | ||||
|      char firstln[ 1024]; | ||||
|      char * command; | ||||
| 
 | ||||
|      printf( "wrapper started with fdes [%d]\n", | ||||
| 		  conversation);  | ||||
|      handler * command = null; | ||||
| 
 | ||||
|      recv( conversation, firstln, 80, MSG_PEEK); | ||||
| 				/* get the first thing the client
 | ||||
|  | @ -53,16 +58,34 @@ void wrapper( int conversation) | |||
| 	  error( LOG_ERR); | ||||
|      } | ||||
| 
 | ||||
|      command = get_handler_command( firstln); | ||||
|      command = get_handler( firstln); | ||||
| 				/* 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); | ||||
| 	  error( LOG_ERR); | ||||
|      } | ||||
|      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); | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 simon
						simon