📄 httpd.c
字号:
if ((fd = t_open(transport, O_RDWR, NULL)) < 0) {
LogError("TLI(%s) Error: t_open failed in %s (%d) - (%d) %s",
transport, __FILE__, __LINE__, t_error, t_errlist[t_errno]);
return -1;
}
if (t_bind(fd, NULL, NULL) < 0) {
LogError("TLI(%s) Error: t_bind failed in %s (%d) - (%d) %s",
transport, __FILE__, __LINE__, t_error, t_errlist[t_errno]);
t_close(fd);
return -1;
}
return fd;
}
/*************************************************************************
* AllocThreadData -- INTERNAL allocates a thread data block and
* fills in the address fields according to the transport provider's
* addressing mechanism. Currently only TCP and SPX are supported.
*
* Parameters:
* pCIData - [IN ] client information
* transport - [IN ] tsp streams device name
*
* Return Value:
* pointer to request data block, or NULL on mem alloc failure.
*/
REQUEST *AllocThreadData(CIDATA *pCIData, char *transport) {
REQUEST *request;
struct hostent *he;
if ((request = malloc(sizeof(REQUEST))) == NULL) {
LogError("MEM: Memory allocation failure in %s (%d)", __FILE__, __LINE__);
return NULL;
}
memset(request, 0, sizeof(REQUEST));
if ((request->strm = fdopen(pCIData->cfd, "rb+")) == NULL) {
LogError("FIO: unable to open I/O stream for client connection");
free(request);
return NULL;
}
request->fd = pCIData->cfd;
request->nStatus = -1;
request->fSent = -1;
/*
* NOTE: add more cases to the following switch statement in order to
* support more transport service providers. Then make sure the
* appropriate transport stream device name is passed.
*
* I realize this system is not perfect, but it's easy enough to
* change in the future and works well for the two currently
* supported transport service providers.
*/
switch (transport[5]) {
case 't': /* "/dev/tcp" */
request->connType = TCP_CONN;
request->szAddr = strdup(TCPAddr2Str(pCIData->pCall->addr.buf));
if ((he = gethostbyaddr(pCIData->pCall->addr.buf,
sizeof(struct sockaddr_in), AF_INET)) != NULL) {
request->szHost = strdup(he->h_name);
}
break;
case 'n': /* "/dev/nspx" */
request->connType = SPX_CONN;
request->szAddr = strdup(SPXAddr2Str(pCIData->pCall->addr.buf));
break;
}
return request;
}
/*************************************************************************
* TCPAddr2Str -- INTERNAL converts a struct sockaddr_in buffer into a
* displayable dotted-quad/port text string and returns a pointer to
* a static buffer containing the string.
*
* Parameters:
* buf - binary data buffer to convert to displayable hex text.
*
* Return Value:
* pointer to static buffer containing text address.
*/
char *TCPAddr2Str(void *buf) {
struct sockaddr_in *addrp = buf;
static char astr[30];
sprintf(astr, "%u.%u.%u.%u/%u",
addrp->sin_addr.S_un.S_un_b.s_b1, addrp->sin_addr.S_un.S_un_b.s_b2,
addrp->sin_addr.S_un.S_un_b.s_b3, addrp->sin_addr.S_un.S_un_b.s_b4,
ntohs(addrp->sin_port));
return astr;
}
/*************************************************************************
* SPXAddr2Str - INTERNAL converts a 12 byte binary hex buffer into a
* displayable hex text string and returns a pointer to a static
* buffer containing the string.
*
* Parameters:
* buf - IN binary data buffer to convert to displayable hex text.
*
* Returns:
* a pointer to a static buffer containing text address.
*/
char *SPXAddr2Str(void *buf) {
static char astr[30];
unsigned char *aubin = buf;
char *cp;
int i;
for (cp = astr, i = 0; i < 4; i++, cp+=2)
sprintf(cp, "%02X", aubin[i]);
*cp++ = ':';
for (; i < 10; i++, cp+=2)
sprintf(cp, "%02X", aubin[i]);
*cp++ = ':';
for (; i < 12; i++, cp+=2)
sprintf(cp, "%02X", aubin[i]);
return astr;
}
/*************************************************************************
* FreeRequest - INTERNAL flush and close client connection and free
* context block.
*
* Parameters:
* request - [IN ] client request context block to be freed.
*
* Returns:
* Nothing.
*/
void FreeRequest(REQUEST *request) {
fclose(request->strm);
free(request->szHost);
free(request->szAddr);
free(request->szRequest);
free(request->szURL);
free(request->szPath);
free(request->szExtra);
free(request->szQuery);
free(request);
return;
}
/*************************************************************************
* QueryCreateThread - INTERNAL returns TRUE if less than 'maxRspThreads'
* threads are running and 'pRqstQueue' is above its high
* water mark.
*
* Parameters:
* None.
*
* Returns:
* TRUE if thread should be created, FALSE if it should not.
*/
int QueryCreateThread(void) {
return (curRspThreads < maxRspThreads) && (reqCount > REQ_HIGH_WATER);
}
/*************************************************************************
* QueryKillThread - INTERNAL returns TRUE if more than 'minRspThreads'
* threads are running and 'pRqstQueue' is below its low water mark
* OR
* we are not executing and there are no requests in the request queue
*
* Parameters:
* None.
*
* Returns:
* TRUE if thread should terminate, FALSE if it should not.
*/
int QueryKillThread(void) {
return ((curRspThreads > minRspThreads) &&
(reqCount < REQ_LOW_WATER)) || (!executing && !reqCount);
}
/*************************************************************************
* InitResponsePool - INTERNAL creates the response queue, opens a
* local queue semaphore for it, then creates the minimum responding
* threads which wait on the semaphore for a client request.
*
* Parameters:
* None.
*
* Returns:
* 0 for success, -1 for resource failure (ie, memory or threads).
*/
int InitResponsePool(void) {
int i;
pRqstQueue = 0; /* make sure queue head pointer is NULL */
reqCount = 0; /* and count is zero */
requestWaiting = OpenLocalSemaphore(0);
for (i = 0; i < minRspThreads; i++) {
if (BeginThreadGroup((void(*)(void*))ProcessRequest, NULL, 0, NULL) == -1) {
CloseLocalSemaphore(requestWaiting);
return -1;
}
}
return 0;
}
/*************************************************************************
* KillResponsePool - INTERNAL destroys 'pRqstQueue' and closes local
* queue semaphore.
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*/
void KillResponsePool(void) {
/* pRqstQueue should be 0 at this point, otherwise there was an error */
CloseLocalSemaphore(requestWaiting);
return;
}
/*************************************************************************
* ProcessRequest - INTERNAL main thread group starting point for new
* response threads. Threads that begin with this function sleep
* on the 'requestWaiting' semaphore. They increase the response
* thread pool by one if necessary before servicing the current
* request, then at the end they die if they are not needed, or
* otherwise go to sleep.
*
* Only one 'compound' condition is necessary to start a new thread:
*
* 1. number of responding threads is less than 'maxRspThreads' AND
* number of outstanding requests is greater than hiWater mark
*
* One of two compound conditions are necessary to kill the current thread:
*
* 1. number of responding threads is greater than 'avgResponding'
* AND number of outstanding requests is less than loWater mark.
*
* OR
*
* 2. we are in "Shut Down" mode (ie., 'executing' is FALSE) AND
* number of outstanding requests is zero.
*
* Note that these last two statements represent the inverse of
* the implemented code because the while loop continues based
* on the inverse of these conditions.
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*/
void ProcessRequest(void) {
REQUEST *request;
char threadName[25];
int ccode;
curRspThreads++;
sprintf(threadName, "HTTP Responder %02d", (++uniqueThreadID % 100));
RenameThread(GetThreadID(), threadName);
do {
WaitOnLocalSemaphore(requestWaiting);
if (QueryCreateThread())
BeginThreadGroup((void(*)(void*))ProcessRequest, NULL, 0, NULL);
if ((request = (REQUEST *)GetLastInCIList((CIDATA **)&pRqstQueue)) != NULL) {
reqCount--;
responding++;
/*
* This is the call to the request handler. It takes a single
* pointer to the request data block containing all information
* necessary to handle the request. It may fork a process for
* the Unix environment, but THIS function will have to be
* re-written because it is designed as a thread-pool entry
* point for multi-threaded environments (like NetWare).
*/
HTTPRequest(request);
/*
* Since the above call doesn't return until the request is
* complete, the request block may now be destroyed.
*/
FreeRequest(request);
responding--;
}
} while (!QueryKillThread());
curRspThreads--;
return;
}
/*************************************************************************
* KillServers - INTERNAL shuts down monitor threads (TCP and SPX).
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*/
void KillServers(void) {
time_t t1;
if (tcp_server != -1)
t_close(tcp_server); /* abortive closes, cancels t_listen blocks */
if (spx_server != -1)
t_close(spx_server);
t1 = clock();
while (listening && (clock() - t1) < MONITOR_TIMEOUT)
ThreadSwitchWithDelay();
printf("HTTPD: Connection monitors have been shutdown.\n");
return;
}
/*************************************************************************
* KillResponders - INTERNAL signals responders to terminate and waits
* for them, or times out.
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*/
void KillResponders(void) {
time_t t1;
int i;
for (i = 0; i < curRspThreads; i++) /* wake up all threads */
SignalLocalSemaphore(requestWaiting); /* and let them shut down */
if (responding) {
printf("HTTPD: Waiting for HTTP requests to complete.\n");
t1 = clock();
while (responding && (clock() - t1) < RESPONDER_TIMEOUT)
ThreadSwitchWithDelay();
}
if (!responding)
while (curRspThreads) /* wait for response threads terminate */
ThreadSwitchWithDelay();
if (responding)
printf("HTTPD: Aborting requests due to timeout.\n");
else
printf("HTTPD: All requests have completed.\n");
return;
}
/*************************************************************************
* SignalHandler - INTERNAL handles all signals we set.
*
* Parameters:
* sig - IN the signal that was sent.
*
* Returns:
* Nothing.
*/
void SignalHandler(int sig) {
switch (sig) {
case SIGTERM:
executing = 0; /* tell everyone to close up and go home */
KillServers();
KillResponders();
KillResponsePool(); /* destroy response queue */
LogError("HTTPD: Unloaded at server console");
CloseLogs();
break;
default:
LogError("HTTPD: Unexpected signal caught.");
return;
}
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -