131 lines
4.1 KiB
C
131 lines
4.1 KiB
C
/**************************************************************************\
|
|
* *
|
|
* 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[ 1024];
|
|
extern char **environ;
|
|
|
|
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);
|
|
exit( 1); /* belt and braces; should never be called */
|
|
}
|
|
|
|
|
|
void wrapper( int conversation, char * client_id)
|
|
/* conversation is the handle on an open socket communicating with a
|
|
client. */
|
|
{
|
|
char firstln[ 1024];
|
|
char * exec_args[1]; /* 'arguments' to pass to execve */
|
|
handler * command = null;
|
|
pid_t child_pid; /* the process number of the spawned child */
|
|
int child_status; /* the status returned by wait() */
|
|
|
|
recv( conversation, firstln, 80, MSG_PEEK);
|
|
/* get the first thing the client
|
|
says, but leave it on the input
|
|
stream for the handler. */
|
|
|
|
if ( dup2( conversation, STDIN_FILENO) == -1)
|
|
{
|
|
sprintf( errorBuff,
|
|
"failed to duplicate conversation [%d] onto stdin: %s",
|
|
conversation, strerror( errno));
|
|
error( LOG_ERR);
|
|
}
|
|
|
|
if ( dup2( conversation, STDOUT_FILENO) == -1)
|
|
{
|
|
sprintf( errorBuff,
|
|
"failed to duplicate conversation [%d] onto stdout: %s",
|
|
conversation, strerror( errno));
|
|
error( LOG_ERR);
|
|
}
|
|
|
|
command = get_handler( firstln);
|
|
/* and find the appropriate handler */
|
|
if ( command == null) /* didn't find one */
|
|
{
|
|
sprintf( errorBuff, "no handler registered for %s", firstln);
|
|
error( LOG_ERR);
|
|
}
|
|
else /* did find one */
|
|
{
|
|
setenv( "REMOTE_HOST", client_id, 1);
|
|
/* set up the handler environment */
|
|
|
|
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);
|
|
}
|
|
|
|
child_pid = fork();
|
|
|
|
switch ( child_pid)
|
|
{
|
|
case -1: /* blew it; whinge and die */
|
|
sprintf( errorBuff, "failed to fork in wrapper()");
|
|
error( LOG_ERR);
|
|
break;
|
|
case 0: /* we're the child process */
|
|
sprintf( errorBuff,
|
|
"using handler '%s' [%d] to handle %s request from %s",
|
|
command->command, ( int)getpid(), command->protocol,
|
|
client_id);
|
|
error( LOG_NOTICE);
|
|
/* log the request, and... */
|
|
|
|
exec_args[ 0] = command->command;
|
|
exec_args[ 1] = null;
|
|
/* set up the dummy arguments */
|
|
|
|
if ( execve( command->command,
|
|
exec_args, environ) == -1)
|
|
/* ...execute the command (shouldn't return) */
|
|
{ /* if it did we've got an error */
|
|
sprintf( errorBuff,
|
|
"error [errno %d] whislt execing handler '%s' [%d]\n",
|
|
errno, command->command, child_pid),
|
|
error( LOG_ERR);
|
|
}
|
|
break;
|
|
|
|
default: /* we're the parent */
|
|
wait( &child_status);
|
|
/* hang around for the child to die */
|
|
sprintf( errorBuff,
|
|
"handler '%s' [%d] completed; wrapper exiting normally",
|
|
command->command, child_pid),
|
|
error( LOG_NOTICE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
exit( 0);
|
|
}
|
|
|
|
|
|
|
|
|