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

📄 httpd.c

📁 《Web编程专家指南》
💻 C
📖 第 1 页 / 共 3 页
字号:
	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 + -