home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1997 March
/
PCWK0397.iso
/
novell
/
webserv3
/
nws30.exe
/
DISK1
/
WEB
/
SAMPLES
/
CGIAPP
/
RCGI.C
< prev
next >
Wrap
C/C++ Source or Header
|
1996-06-14
|
13KB
|
596 lines
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ctype.h>
#include <errno.h>
#include <time.h>
#include <nwdir.h>
#include <conio.h>
#include <io.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
NETDB_DEFINE_CONTEXT
#define MAX_FNAME 1024
#define MAX_LINE_LEN 1025
#define MAX_ENV 1024
void set_local_log();
int rcgi_main(char *, int (*fptr)());
static int sockfd;
extern int server_port ;
static int server_socket;
static int reply_socket=0; /** Use this to send data to web server **/
static int server_alive;
char *cmd_line = 0;
int env_count;
static int in_port = 0;
static char *cmds[] = {
"env",
"cmd",
"input",
"port",
"end",
"vers",
0
};
char *env[MAX_ENV];
char *input;
/************************************************************************/
/************ THE RCGI INTERFACE FUNCTION *******************************/
/************************************************************************/
/****** Use this function to send data to the web server *****/
rcgi_sendreply(char *buf)
{
if (!buf)
return -1;
rcgi_send(reply_socket, buf, strlen(buf));
}
/****** Use this function to send the generic header to the web server *****/
rcgi_sendheader()
{
char tmpbuf[200];
/**** BUILD AND SEND THE HEADER ***/
memset(tmpbuf, 0, 200);
sprintf(tmpbuf, "Content-type: text/plain");
strcat(tmpbuf, "\r\n");
strcat(tmpbuf, "\r\n");
rcgi_send(reply_socket, tmpbuf, strlen(tmpbuf));
}
/********** Use this function before exiting to cleanup stuff allocated **/
/********** by RCGI *****/
rcgi_cleanup()
{
free_env();
if (input)
free(input);
input = 0;
if(cmd_line)
free(cmd_line);
cmd_line = 0;
close(sockfd);
close(server_socket);
close(reply_socket);
}
/*** The main RCGI server function. Waits for a request, does the RCGI ***/
/*** processing, calls the process_request() function and loops ***/
int
rcgi_main(char *srvr_port, int (*process_request)())
{
int client_socket, clen, one=1;
struct sockaddr_in sa_client;
struct sockaddr_in sa_server;
if (srvr_port)
set_server_port(srvr_port);
/* open tcp socket */
if ((server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
ConsolePrintf("rcgid: could not get tcp socket\n");
perror("socket");
return -1;
}
if ((setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR,
(char *)&one, sizeof(one))) == -1)
{
ConsolePrintf( "rcgid: could not set tcp socket option\n");
perror("setsockopt");
return -1;
}
/* bind it to an addres, port */
memset((char *)&sa_server, 0, sizeof(sa_server));
sa_server.sin_family = AF_INET;
sa_server.sin_addr.s_addr = htonl(INADDR_ANY);
sa_server.sin_port = htons((short)server_port);
if (bind(server_socket, (struct sockaddr *)&sa_server,
sizeof(sa_server)) == -1)
{
ConsolePrintf( "rcgid: could not bind tcp socket to port %d\n",
server_port);
perror("bind");
return -1;
}
listen(server_socket, 5);
server_alive = 1;
while (server_alive) {
retry:
clen = sizeof(sa_client);
client_socket = accept(server_socket,
(struct sockaddr *)&sa_client, &clen);
if (client_socket == -1) {
if (errno == ETIMEDOUT && server_alive) {
goto retry;
}
ConsolePrintf("accept failed, errno %d, server_alive %d\n",
errno, server_alive);
/* if we're not being shut down, schedule death */
if (server_alive)
graceful_death();
} else {
reply_socket = rcgi(client_socket, &sa_client);
correct_env();
(*process_request)();
if (input){
free(input);
input = 0;
}
free_env();
if (cmd_line) {
free(cmd_line);
cmd_line = 0;
}
close(reply_socket);
}
/* */
}
}
/************************************************************************/
/* -------------- MAIN RCGI PROCESSING ------------------------------ */
/************************************************************************/
int
rcgi(skt, sa_client)
int skt;
struct sockaddr_in *sa_client;
{
int more, i;
char buf[MAX_LINE_LEN], *p;
int rcgi_state = 0;
char scratchbuf[MAX_LINE_LEN];
int ret = skt;
rcgi_state = 0;
more = 1;
while (more) {
int len;
for (i=0;i<MAX_LINE_LEN;i++) buf[i] = 0;
if (!rcgi_recv(skt, buf, sizeof(buf)-1))
break;
len = strlen(buf);
if (len >= 2 && buf[len-2] == '\r' && buf[len-1] == '\n') {
buf[len-2] = 0;
len -= 2;
} else
if (len >=1 && buf[len-1] == '\n') {
buf[len-1] = 0;
len--;
}
switch(rcgi_state) {
case 0:
for (p = buf; *p && *p != ' '; p++)
;
if (*p)
*p++ = 0;
for (i = 0; cmds[i]; i++) {
if (strcmpi(cmds[i], buf) == 0)
break;
}
switch (i+1) {
case 1: /* env */
rcgi_state = 1;
sprintf(scratchbuf, "100 Enter env. End with single '.' on a line\r\n");
rcgi_send(skt, scratchbuf, strlen(scratchbuf));
break;
case 2: /* cmd */
if (*p)
cmd_line = strdup(p);
printf("Command is %s\n", p);
if (cmd_line) {
sprintf(scratchbuf, "101 Cmd accepted '%s'\r\n", cmd_line);
rcgi_send(skt, scratchbuf, strlen(scratchbuf));
}
break;
case 3: /* input */
rcgi_state = 2;
break;
case 4: /* port */
rcgi_state = 3;
break;
case 5: /* end */
more = 0;
break;
case 6: /* vers */
break;
default:
sprintf(scratchbuf, "500 Bad command '%s'\r\n", buf);
rcgi_send(skt, scratchbuf, strlen(scratchbuf));
more = 0;
}
break;
case 1: /* env */
if (len == 1 && buf[0] == '.') {
sprintf(scratchbuf, "100 Env accepted\r\n");
rcgi_send(skt, scratchbuf, strlen(scratchbuf));
rcgi_state = 0;
break;
}
if (buf[0] == 0)
break;
if (add_env(buf)) {
sprintf(scratchbuf, "501 Environment full '%s'\r\n", buf);
rcgi_send(skt, scratchbuf, strlen(scratchbuf));
more = 0;
}
break;
case 2: /* input */
if (len > 1 && buf[0] == '.' && buf[1] == '.')
;
else
if (len == 1 && buf[0] == '.')
rcgi_state = 0;
add_input(buf);
break;
case 3: /* port */
in_port = atoi(p);
break;
} /*switch */
} /*while */
printf("end of loop\n");
if (in_port) {
int one=1;
/* open tcp socket */
if ((skt = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
fprintf(stderr,"rcgid: could not get tcp socket\n");
perror("socket");
return(-1);
}
if ((setsockopt(skt, SOL_SOCKET, SO_REUSEADDR,
(char *)&one, sizeof(one))) == -1)
{
fprintf(stderr, "rcgid: could not set tcp socket option\n");
perror("setsockopt");
return(-1);
}
sa_client->sin_port = htons((short)in_port);
if (connect(skt, (struct sockaddr *) sa_client,
sizeof(struct sockaddr_in)) == -1) {
fprintf(stderr, "rcgid: could not connect\n");
perror("connect");
return(-1);
}
ret = skt;
}
if (cmd_line) {
sprintf(scratchbuf, "200 Cmd started '%s'\r\n", cmd_line);
rcgi_send(skt, scratchbuf, strlen(scratchbuf));
}
/* Now that we have all the info that we need, let main process execute */
return ret;
}
/************************************************************************/
/************ SUPPORT FUNCTIONS FOR RCGI()*******************************/
/************************************************************************/
/**** This function is used to extract and set the server port from ***/
/**** string passed on the command line ***/
void
set_server_port(arg)
char *arg;
{
server_port = atoi(arg);
}
/********* This function is used to get store input from the web server **/
/********* in the "input" variable ***/
int
add_input(buf)
char *buf;
{
char *newinput = NULL;
if (!input) {
input = (char *) malloc(strlen(buf)+1);
if (!input) return -1;
strcpy(input, buf);
}
else {
newinput = realloc(input, strlen(input) + strlen(buf) +1 );
if (!newinput)
return (-1);
memset(newinput + strlen(input), 0, strlen(buf) + 1);
input = newinput;
strcat(input, buf);
}
return(0);
}
/********* This function is used to store environment data from the web ***/
/********* server in the "env" variable ***/
int
add_env(buf)
char *buf;
{
if (env_count >= MAX_ENV)
return -1;
env[env_count++] = strdup(buf);
env[env_count] = 0;
return 0;
}
/********* This function is used to free the "env" array ******/
void
free_env(void)
{
int i;
for (i = 0; i < env_count; i++)
if ( env && env[i])
free(env[i]);
env_count = 0;
}
char *
get_env(name)
char *name;
{
char *tmp = NULL;
int i=0;
for (i=0;i<env_count;i++) {
tmp = strchr(env[i], '=');
if (tmp)
*tmp = '\0';
if (!strcmp(env[i], name) ) {
*tmp = '=';
tmp++;
return(strdup(tmp));
}
else
if (tmp)
*tmp = '=';
}
return NULL;
}
set_env(name, val)
char *name;
char *val;
{
char *tmp = NULL;
int i=0, namelen=0, vallen=0;
char *newenv = NULL;
for (i=0;i<env_count;i++) {
tmp = strchr(env[i], '=');
if (tmp)
*tmp = '\0';
if (!strcmp(env[i], name) ) {
namelen = strlen(env[i]);
vallen = strlen(val);
newenv = (char *) malloc(namelen+vallen+2);
if (!newenv) {
tmp--;
*tmp = '=';
return(1);
}
memset(newenv, 0, namelen+vallen+2);
strcat(newenv, env[i]);
strcat(newenv, "=");
strcat(newenv, val);
free(env[i]);
env[i] = newenv;
return 0;
}
else {
if (tmp)
*tmp = '=';
}
}
/* if it gets here then its a new env var */
newenv = (char *) malloc(strlen(name)+strlen(val)+2);
if (!newenv)
return(1);
strcat(newenv, name);
strcat(newenv, "=");
strcat(newenv, val);
add_env(newenv);
if (newenv)
free(newenv);
}
correct_env(void)
{
char *path_info_val = NULL, *script_name_val = NULL;
script_name_val = get_env("SCRIPT_NAME");
path_info_val = get_env("PATH_INFO");
munge_env(script_name_val, path_info_val);
if (script_name_val)
free(script_name_val);
if (path_info_val)
free(path_info_val);
}
munge_env(script_name_val, path_info_val)
char *script_name_val, *path_info_val;
{
char path_info[256];
char script_name[256];
char *tmp1 = NULL, *tmp2 = NULL;
int i=0;
for (i=0;i<256;i++) path_info[i] = '\0';
for (i=0;i<256;i++) script_name[i] = '\0';
if (!script_name_val || !path_info_val)
return;
tmp1 = script_name_val;
if (*tmp1 == '/') tmp1++;
tmp2 = strchr(tmp1, '/'); /* Search for first '/' */
if (tmp2)
*tmp2 = '\0';
strcat(script_name, tmp1);
if (tmp2) {
*tmp2 = '/';
strcat(path_info, tmp2);
}
tmp1 = path_info + strlen(path_info) ;
if (*(tmp1-1) != '/') *tmp1 = '/'; /* Append a slash if missing */
tmp1 = path_info_val;
if (*tmp1 == '/') tmp1++; /* skip past leading slash */
if (tmp1 && *tmp1 != '\0')
strcat(path_info, tmp1);
set_env("PATH_INFO", path_info);
set_env("SCRIPT_NAME", script_name);
}
/************************************************************************/
/*********** ROUTINES TO SEND AND GET STUFF FROM THE RCGI CLIENT ******/
/************************************************************************/
int
rcgi_send(int skt, char *buf, int len)
{
char *ptr = buf;
int num_left = len;
int num_sent = 0;
if (!buf)
return -1;
printf("\nSending %s. \nNo. of bytes = %d\n", buf, len);
while(num_left) {
num_sent = send(skt, ptr, num_left, 0);
if (num_sent == -1){
ConsolePrintf("Couldn;t send data. Errno = %d!\n", errno);
return(-1);
}
num_left -= num_sent;
ptr += num_sent;
}
}
int
rcgi_recv(int skt, char *buf, int len)
{
int num_recd = 0;
int num_left = len;
char *ptr = buf;
if (!buf)
return -1;
while (num_left) {
if ((num_recd = recv(skt, ptr, 1, 0)) == -1) {
ConsolePrintf("Error in receiving. Errno = %d\n", errno);
return -1;
}
num_left --;
if (*ptr == '\n') {
ptr++;
*ptr = '\0';
return ptr-buf;
}
ptr ++;
}
ConsolePrintf("Received %s\n", buf);
return len;
}
/* ------------------------------------------------------------------ */
/* -------------- UTIL FUNCTIONS ------------------------------------ */
void
graceful_death()
{
printf("graceful_death()\n");
}