SOURCE FILE: webserver.c


/* webserver.c */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <cnaiapi.h>

#if defined(LINUX) || defined(SOLARIS)
#include <sys/time.h>
#endif

#define BUFFSIZE	256
#define SERVER_NAME	"CNAI Demo Web Server"

#define ERROR_400	"<head></head><body><html><h1>Error 400</h1><p>Th\
e server couldn't understand your request.</html></body>\n"

#define ERROR_404	"<head></head><body><html><h1>Error 404</h1><p>Do\
cument not found.</html></body>\n"

#define HOME_PAGE	"<head></head><body><html><h1>Welcome to the CNAI\
 Demo Server</h1><p>Why not visit: <ul><li><a href=\"http://netbook.cs.pu\
rdue.edu\">Netbook Home Page</a><li><a href=\"http://www.comerbooks.com\"\
>Comer Books Home Page<a></ul></html></body>\n"

#define TIME_PAGE	"<head></head><body><html><h1>The current date is\
: %s</h1></html></body>\n"

int	recvln(connection, char *, int);
void	send_head(connection, int, int);

/*-----------------------------------------------------------------------
 *
 * Program: webserver
 * Purpose: serve hard-coded webpages to web clients
 * Usage:   webserver <appnum>
 *
 *-----------------------------------------------------------------------
 */
int
main(int argc, char *argv[])
{

	connection	conn;
	int		n;
	char		buff[BUFFSIZE], cmd[16], path[64], vers[16];
	char		*timestr;
        /* DECLARE A VARIABLE FOR STORING DATE AND TIME. */
#if defined(LINUX) || defined(SOLARIS)
	struct timeval	tv;
#elif defined(WIN32)
	time_t          tv;
#endif

	if (argc != 2) { /* 'ERROR OUT' IF #ARGS WRONG. */
		(void) fprintf(stderr, "usage: %s <appnum>\n", argv[0]);
		exit(1);
	}

	while(1) 
        { /* START OF MAIN LOOP (INFINITE LOOP) */

		/* wait for contact from a client on specified appnum */

		conn = await_contact((appnum) atoi(argv[1]));
		if (conn < 0)
			exit(1);

		/* read and parse the request line */

		n = recvln(conn, buff, BUFFSIZE);
                 /* THIS MAKES SEPARATE STRINGS: cmd, path, AND vers
                    FROM THE PARTS OF THE COMMAND
                    SEPARATED BY BLANKS. */
		sscanf(buff, "%s %s %s", cmd, path, vers);

		/* skip all headers - read until we get \r\n alone 
                   -- THIS IS JUST CODE THAT SKIPS OVER ANY ADDITIONAL
                      INFORMATION THAT THE CLIENT MAY HAVE SENT. */

		while((n = recvln(conn, buff, BUFFSIZE)) > 0) {
			if (n == 2 && buff[0] == '\r' && buff[1] == '\n')
				break;
		}

		/* check for unexpected end of file */

		if (n < 1) {
			(void) send_eof(conn); /* 'HANG UP' ON THE CLIENT */
			continue; /* GO BACK TO THE TOP OF THE (MAIN) LOOP. */
		}
		
		/* check for a request that we cannot understand 
                   -- IF THE COMMAND IS NOT GET OR THE VERSION
                      IS NOT EITHER OF THE TWO SHOWN, THEN SEND
                      THE 400 ERROR MESSAGE (WITH HEADER). 
                      THEN 'HANG UP' AND GO BACK TO THE TOP OF THE (MAIN)
		      LOOP. */

		if (strcmp(cmd, "GET") || (strcmp(vers, "HTTP/1.0") &&
					   strcmp(vers, "HTTP/1.1"))) {
			send_head(conn, 400, strlen(ERROR_400));
			(void) send(conn, ERROR_400, strlen(ERROR_400),0);
			(void) send_eof(conn);
			continue;
		}

		/* send the requested web page or a "not found" error */
                        
		if (strcmp(path, "/") == 0) /* IF THE PATH IS '/'*/
                { /* SEND THE HOME PAGE (WITH HEADER). */
			send_head(conn, 200, strlen(HOME_PAGE));
			(void) send(conn, HOME_PAGE, strlen(HOME_PAGE),0);
		} else if (strcmp(path, "/time") == 0) 
                          /* IF /time IS THE PATH */
                       {  /* CALCULATE THE TIME & DATE AS APPROPRIATE */
#if defined(LINUX) || defined(SOLARIS)
			gettimeofday(&tv, NULL);
			timestr = ctime(&tv.tv_sec);
#elif defined(WIN32)
			time(&tv);
			timestr = ctime(&tv);
#endif
                            /* FORMAT AND SEND THE TIME & DATE 
                               INFO (WITH HEADER). */
			(void) sprintf(buff, TIME_PAGE, timestr);
			send_head(conn, 200, strlen(buff));
			(void) send(conn, buff, strlen(buff), 0);
		} else { /* OTHERWISE SEND THE 'NOT FOUND' 
                            HEADER AND MESSAGE. */
			send_head(conn, 404, strlen(ERROR_404));
			(void) send(conn, ERROR_404, strlen(ERROR_404),0);
		}
		(void) send_eof(conn); /* 'HANG UP' AND GO BACK TO THE TOP
                                          OF THE MAIN LOOP. */
	} /* END OF MAIN LOOP (INFINITE LOOP) */
}/* END OF FUNCTION main() */

/*-----------------------------------------------------------------------
 * send_head - send an HTTP 1.0 header with given status and content-len
 *-----------------------------------------------------------------------
 */
void
send_head(connection conn, int stat, int len)
{
	char	*statstr, buff[BUFFSIZE];

	/* convert the status code to a string */

	switch(stat) {
	case 200:
		statstr = "OK";
		break;
	case 400:
		statstr = "Bad Request";
		break;
	case 404:
		statstr = "Not Found";
		break;
	default:
		statstr = "Unknown";
		break;
	}
	
	/*
	 * send an HTTP/1.0 response with Server, Content-Length,
	 * and Content-Type headers.
	 */
                 /* ASSEMBLE MESSAGE LINE AND COPY INTO BUFFER --
                    STATUS NUMBER AND STATUS STRING. */ 
	(void) sprintf(buff, "HTTP/1.0 %d %s\r\n", stat, statstr);
                 /* SEND LINE OVER CONNECTION */
	(void) send(conn, buff, strlen(buff), 0);
                 /* THE REST ARE SIMILAR. */
	(void) sprintf(buff, "Server: %s\r\n", SERVER_NAME);
	(void) send(conn, buff, strlen(buff), 0);

	(void) sprintf(buff, "Content-Length: %d\r\n", len);
	(void) send(conn, buff, strlen(buff), 0);

	(void) sprintf(buff, "Content-Type: text/html\r\n");
	(void) send(conn, buff, strlen(buff), 0);

	(void) sprintf(buff, "\r\n");
	(void) send(conn, buff, strlen(buff), 0);
}