⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 httpd.c

📁 《Web编程专家指南》
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * Novell NetWare HTTP TCP server -- main, etc.
 *
 * John Calcote 5/10/95
 * internet: jcalcote@novell.com
 *
 * httpd.c - TCP/IP & SPX server for WWW file requests.
 *
 * Notes:
 *
 *    This web server daemon was written for the NetWare NON-PREEMPTIVE
 *    multitasking environment.  Thus, there is no critical section
 *    handling (we always know when we are going to switch threads).
 *
 *    The places to handle critical sections would be in the code for
 *    linked-list manipulation (addition, removal, creation, destruction).
 *    Most of the rest of the code is not re-entered by different threads.
 *
 *    This code will port fairly easily to any other non-preemptive
 *    environment which supports TLI.  It should also be a fairly trivial
 *    process to port it to any Unix system.
 *
 *    Finally, since it contains nothing specific to HTTP, it can easily
 *    be used for any server listen daemon.
 */

#include "hcommon.h"

#define LOCAL static

#include <signal.h>
#include <stropts.h>
#include <io.h>
#include <tiuser.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>


/* Transport server connection indication data block */
typedef struct cidata {
	struct cidata *pNext;
	struct cidata *pPrev;
	struct t_call *pCall;      /* indication call structure  */
	int            cfd;        /* indication client fd       */
} CIDATA;


/* Static prototypes */
LOCAL int   ParseCommandLine(int, char **);
LOCAL void  TCPMonitor(void);
LOCAL void  SPXMonitor(void);
LOCAL int   TLIListen(int, char *);
LOCAL int   CreateCIFreeList(CIDATA **, int, int);
LOCAL CIDATA *GetLastInCIList(CIDATA **);
LOCAL CIDATA *GetSequenceInCIList(CIDATA **, int);
LOCAL void  GetGivenNodeInCIList(CIDATA **, CIDATA *);
LOCAL void  PutFirstInCIList(CIDATA **, CIDATA *);
LOCAL void  DestroyCIList(CIDATA **);
LOCAL void  RejectAllCallsInCIList(CIDATA *, int);
LOCAL int   AcceptIndications(int, CIDATA **, CIDATA **, CIDATA **, char *);
LOCAL int   HandleAsyncEvent(int, CIDATA **, CIDATA **);
LOCAL int   OpenSpecificTLIfd(char *, int, void *, int, void *);
LOCAL int   OpenArbitraryTLIfd(char *);
LOCAL REQUEST *AllocThreadData(CIDATA *, char *);
LOCAL char *TCPAddr2Str(void *);
LOCAL char *SPXAddr2Str(void *);
LOCAL void  FreeRequest(REQUEST *);
LOCAL int   QueryCreateThread(void);
LOCAL int   QueryKillThread(void);
LOCAL int   InitResponsePool(void);
LOCAL void  KillResponsePool(void);
LOCAL void  ProcessRequest(void);
LOCAL void  KillServers(void);
LOCAL void  KillResponders(void);
LOCAL void  SignalHandler(int);


/* module globals */
int debugLevel;               /* debugging on or off (1 or 0)              */
int debugScreen;              /* debug screen handle                       */


/* Module static variables */
LOCAL char  syserr[256];	  	/* buffer for system error message strings	*/
LOCAL int 	listening;        /* listening flag, touched by all monitors   */
LOCAL int 	executing;        /* executing flag, touched by SEGTERM hndlr  */
LOCAL int 	responding;       /* number of threads responding              */
LOCAL int 	maxRspThreads;    /* maximum number of rsp threads allowed     */
LOCAL int 	minRspThreads;    /* minimum number of rsp threads allowed     */
LOCAL int	curRspThreads;  	/* number of response threads in pool        */
LOCAL LONG	requestWaiting;   /* request queue semaphore handle            */
LOCAL REQUEST *pRqstQueue;    /* general request queue                     */
LOCAL int	reqCount;			/* general request queue count					*/


/* -------- Transport specific static globals --------- */


/* TCP Transport */
LOCAL int tcp_server;        /* tcp server socket                         */
unsigned short usTCPPort = 80;

/* SPX Transport */
LOCAL int spx_server;        /* spx server socket                         */
unsigned int usSPXPort = 0x3280;

/*************************************************************************
 * main - System entry point.
 *
 * Parameters:
 *    <standard>
 *
 * Returns:
 *    Nothing.
 */

void main (int argc, char *argv[]) {

   printf("HTTPD - Web Document Server.  (Version 0.90)\n");
	printf("Compiled on " __DATE__ " at " __TIME__".\n\n");

	executing 		= 1;		/* are we executing? 						*/
	listening 		= 0;		/* how many daemons are listening? 		*/
	responding 		= 0;		/* how many requests are we servicing?	*/
	curRspThreads	= 0;		/* number of responder threads			*/
	uniqueThreadID	= 0;  	/* unique thread ID number (for name)	*/

	maxRspThreads 	= MAX_RSP_THREADS;
	minRspThreads	= MIN_RSP_THREADS;

	tcp_server = -1;
	spx_server = -1;

	if (InitResponsePool() != 0) {
      printf("HTTPD: Failed to build response thread pool. Terminating.\n");
		return;
	}

   OpenLogs();             /* open error and access logs          */

	signal(SIGTERM, SignalHandler);

	BeginThread((void(*)(void*))TCPMonitor, NULL, 0, NULL);
	BeginThread((void(*)(void*))SPXMonitor, NULL, 0, NULL);

	return;
}


/*************************************************************************
 * ParseCommandLine - parse command line parameters into globals.
 *		Fills in globals, ndsUserName, ndsPassword, ndsTreeName, and
 *    debugLevel.
 *
 *		Command Line Syntax:
 *			LOAD HTTPD [/L=<NDS Login> [/P=<NDS Password>] [/T=<NDS Tree>]] [/D(ebug)]
 *
 * Parameters:
 *    argc		- [IN ] argument count (not used in this implementation)
 *		argv		- [IN ] argument array
 *
 * Returns:
 *    0 for success, or non-zero error code indicating bad parameter, etc.
 */

#pragma argsused
int ParseCommandLine(int argc, char *argv[]) {
	char *argp, opt;

	debugLevel = 0;

	while (*++argv) {
		argp = *argv;
		if (*argp == '/' || *argp == '-')
			argp++;

		opt = (char)toupper(*argp++);
		if (*argp == '=')
			argp++;

		switch(opt) {
			case 'D':
            debugLevel = *argp? atoi(argp) : 1;
				break;
			default:
				return -1;
		}
	}
	return 0;
}


/*************************************************************************
 * TCPMonitor - entry point for TCP connection indication monitor.
 *
 * Parameters:
 *    None.
 *
 * Returns:
 *    Nothing.
 */

void TCPMonitor(void) {
	char              *transport = "/dev/tcp";   /* TCP streams device name */
	struct sockaddr_in saddr, saout;             /* TCP address buffers     */

	RenameThread(GetThreadID(), "HTTP TCP Monitor");

	memset(&saddr, 0, sizeof(saddr));
   saddr.sin_port = htons(usTCPPort);       /* specify only the port #    */

	if ((tcp_server = OpenSpecificTLIfd(transport, TLI_QLEN,
		&saddr, sizeof(saddr), &saout)) < 0) {
      printf("HTTPD: Unable to open TLI(%s) monitor end point."
			"\n       Terminating this monitor.\n", transport);
		return;
	}

	if (saddr.sin_port != saout.sin_port)
      printf("HTTPD: WARNING! Requested TCP port (%d) not available."
			"\n       TCP listen end point bound to port %d.\n",
         usTCPPort, ntohs(saout.sin_port));
	else
      printf("HTTPD: TCP monitor listening on port %d.\n", usTCPPort);

	listening++;
	if (TLIListen(tcp_server, transport) < 0) {
		t_close(tcp_server);
		tcp_server = -1;
	}
	listening--;

	return;
}


/*************************************************************************
 * SPXMonitor - entry point for SPX connection indication monitor.
 *
 * Parameters:
 *    None.
 *
 * Returns:
 *    Nothing.
 */

void SPXMonitor(void) {
	char     *transport = "/dev/nspx";     /* SPX streams device name       */
	IPX_ADDR  saddr, saout;                /* SPX address buffers           */

	RenameThread(GetThreadID(), "HTTP SPX Monitor");

	memset(&saddr, 0, sizeof(saddr));
   *(unsigned short *)saddr.ipxa_socket = htons(usSPXPort);

	if ((spx_server = OpenSpecificTLIfd(transport, TLI_QLEN,
		&saddr, sizeof(saddr), &saout)) == -1) {
      printf("HTTPD: Unable to open TLI(%s) monitor end point."
			"\n       Terminating this monitor.\n", transport);
		return;
	}
	if (*(unsigned short *)saddr.ipxa_socket != *(unsigned short *)saout.ipxa_socket)
      printf("HTTPD: WARNING! Requested SPX socket (0x%x) not available."
			"\n       SPX listen end point bound to socket 0x%x.\n",
         usSPXPort, ntohs(*(unsigned short *)saout.ipxa_socket));
	else
      printf("HTTPD: SPX monitor listening on socket 0x%x.\n", usSPXPort);

	listening++;
	if (TLIListen(spx_server, transport) < 0) {
		t_close(spx_server);
		spx_server = -1;
	}
	listening--;

	return;
}


/*************************************************************************
 * TLIListen - listen on an an open TLI endpoint (sfd) using 'transport'.
 *
 * Parameters:
 *    sfd         - [IN ] server file descriptor
 *    transport   - [IN ] transport device name
 *
 * Returns:
 *    the value of 'executing' == non-zero for abnormal termination,
 *       or 0 for normal (SIGTERM) termination.
 */

int TLIListen(int sfd, char *transport) {
	REQUEST  *pRequest;        /* connected request             */
	CIDATA 	*pCIFree = NULL;  /* head of free block list			*/
	CIDATA	*pCIHead = NULL;  /* head of pending cxtn list		*/
	CIDATA   *pCIData;         /* current indication            */
	int       rc;

	/* allocate free block list */

	if (CreateCIFreeList(&pCIFree, sfd, TLI_QLEN) < 0) {
      printf("HTTPD: Unable to allocate free cxtn block list."
			"\n       Terminating device (%s) monitor.\n", transport);
		return -1;
	}

	/* start listening for connect requests */

	while (executing) {
		ThreadSwitchWithDelay();
		pCIData = GetLastInCIList(&pCIFree);
		if (t_listen(sfd, pCIData->pCall) < 0) {
			if (!executing) {
				PutFirstInCIList(&pCIFree, pCIData);
				goto ListenExit;
			}

         /* This should never happen, but if it does for SOME reason ... */

         sprintf(syserr, "SYSERR %d - %s", errno, sys_errlist[errno]);
			LogError("SVR: t_listen failed in %s (%d) - reason: (%d) %s. %s",
				__FILE__, __LINE__, t_errno, t_errlist[t_errno],
				t_errno == TSYSERR? syserr : "");

			PutFirstInCIList(&pCIFree, pCIData);
			goto ListenExit;
		}
		PutFirstInCIList(&pCIHead, pCIData);
		while (pCIHead) {
			ThreadSwitchWithDelay();

			/* AcceptIndications may fail for many reasons, but only
			 * unrecoverable (memory) errors should return an error code
			 * so that the system may keep running.
			 */

			rc = AcceptIndications(sfd, &pCIHead, &pCIFree, &pCIData, transport);
			if (rc < 0)
				goto ListenExit;                    /* fatal, if AI returns -1 */
			if (rc > 0)
				continue;
			if ((pRequest = AllocThreadData(pCIData, transport)) == NULL) {	/* memory error */
				t_snddis(pCIData->cfd, pCIData->pCall);
				t_unbind(pCIData->cfd);
				t_close(pCIData->cfd);
				PutFirstInCIList(&pCIFree, pCIData);
				goto ListenExit;
			}
			PutFirstInCIList((CIDATA **)&pRqstQueue, (CIDATA *)pRequest);
         reqCount++;
         SignalLocalSemaphore(requestWaiting);
			PutFirstInCIList(&pCIFree, pCIData);
		}
	}

ListenExit:

	DestroyCIList(&pCIFree);
	RejectAllCallsInCIList(pCIHead, sfd);
	DestroyCIList(&pCIHead);
	return executing;
}


/*************************************************************************
 * CreateCIFreeList - INTERNAL create a list of 'count' CIDATA nodes
 *		whose head pointer is stored in 'ppCIHead'.  Use 'sfd' to
 *		initialize the t_call structure via t_alloc.
 *
 *	NOTE: This routine assumes that *ppCIHead has been initialized to
 *		NULL before it was passed in.
 *
 * Parameters:
 *		ppCIHead		- [I/O] address of list head pointer
 *    sfd         - [IN ] server file descriptor (used by t_alloc)
 *    count			- [IN ] number of nodes to create
 *
 * Returns:
 *    -1 for memory allocation error, 0 for successful allocation.
 */

int CreateCIFreeList(CIDATA **ppCIHead, int sfd, int count) {
	CIDATA  *pCIData;
	int 		i;

	for (i = 0; i < count; i++) {
		if ((pCIData = (CIDATA *)malloc(sizeof(CIDATA))) == NULL) {
			DestroyCIList(ppCIHead);
			return -1;
		}
		if ((pCIData->pCall = (struct t_call *)t_alloc(sfd, T_CALL, T_ALL)) == NULL) {
			free(pCIData);
			DestroyCIList(ppCIHead);
			return -1;
		}
		PutFirstInCIList(ppCIHead, pCIData);
	}
   return 0;
}


/*************************************************************************
 * GetLastInCIList - INTERNAL remove a node from the end of the
 *		specified CI list.  Return the node's address or NULL if there
 *		aren't any nodes in the list.
 *
 * NOTE: this list is a ring on the previous chain and a list on the
 *    next chain.
 *
 * NOTE: this function always removes from the tail of the list by
 *    backing up one from head.
 *
 * Parameters:
 *		ppCIHead		- [I/O] address of list head pointer
 *
 * Returns:
 *    address of removed node, or NULL if there are none to remove.
 */

CIDATA *GetLastInCIList(CIDATA **ppCIHead) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -