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

📄 httpd.c

📁 《Web编程专家指南》
💻 C
📖 第 1 页 / 共 3 页
字号:
	CIDATA *pCINode;

	if (*ppCIHead == NULL)
		return NULL;

	pCINode = (*ppCIHead)->pPrev;    /* get node from end       */

	if ((*ppCIHead)->pNext == NULL)  /* if last item in list    */
		*ppCIHead = NULL;
	else {                           /* else more than one item */
		(*ppCIHead)->pPrev = pCINode->pPrev;
		pCINode->pPrev->pNext = NULL;
	}
	return pCINode;
}


/*************************************************************************
 * GetSequenceInCIList - INTERNAL remove and return the node in the
 *    specified list with the matching sequence number in it's t_call
 *    structure.
 *
 * NOTE: 'ppCIHead' MUST contain the address of a valid CIDATA pointer.
 *
 * Parameters:
 *		ppCIHead		- [I/O] address of list head pointer
 *    sequence    - [IN ] sequence number to search for
 *
 * Returns:
 *    address of removed node, or NULL if there are none to remove.
 */

CIDATA *GetSequenceInCIList(CIDATA **ppCIHead, int sequence) {
   CIDATA *pCINode = *ppCIHead;

   while (pCINode) {
		if (pCINode->pCall->sequence == sequence) {
			GetGivenNodeInCIList(ppCIHead, pCINode);
         break;
      }
      pCINode = pCINode->pNext;
   }
   return pCINode;
}


/*************************************************************************
 * GetGivenNodeInCIList - INTERNAL remove a specifiec node from the
 *    specified CI list.
 *
 * NOTE: 'pCINode' MUST be a member of the list whose head pointer is
 *    'ppCIHead'.  Since this function is only ever called from
 *    GetSequenceInCIList, this is always true for this code.
 *
 * Parameters:
 *		ppCIHead		- [I/O] address of list head pointer
 *    pCINode     - [IN ] pointer to node to retrieve
 *
 * Returns:
 *    address of removed node, or NULL if there are none to remove.
 */

void GetGivenNodeInCIList(CIDATA **ppCIHead, CIDATA *pCINode) {
   if ((*ppCIHead)->pNext == NULL)     /* only one node in list */
      *ppCIHead = NULL;
   else {                              /* more than one node in list */
      if (pCINode == *ppCIHead)
         *ppCIHead = pCINode->pNext;
      else
         pCINode->pPrev->pNext = pCINode->pNext;
      if (pCINode->pNext)
         pCINode->pNext->pPrev = pCINode->pPrev;
		else
         (*ppCIHead)->pPrev = pCINode->pPrev;
   }
	return;
}


/*************************************************************************
 * PutFirstInCIList - INTERNAL prepend a new node to the head of the
 *		specified CI list.
 *
 * NOTE: 'ppCIHead' MUST contain the address of a valid CIDATA pointer,
 *    or its equivalent (something starting with a next and prev pointer)
 *    and 'pCINode' must point to a valid CIDATA structure.
 *
 * Parameters:
 *		ppCIHead		- [I/O] address of list head pointer
 *		pCINode     - [IN ] node pointer to append to list
 *
 * Returns:
 *    Nothing.
 */

void PutFirstInCIList(CIDATA **ppCIHead, CIDATA *pCINode) {

   pCINode->pNext = *ppCIHead;   /* Null, if first -- *ppCIHead, if not */

	if (*ppCIHead == NULL)        /* empty list */
      pCINode->pPrev = pCINode;
   else {                        /* at least one node already in list */
      pCINode->pPrev = (*ppCIHead)->pPrev;
      (*ppCIHead)->pPrev = pCINode;
   }

	*ppCIHead = pCINode;          /* head moves to new node */

	return;
}


/*************************************************************************
 * DestroyCIList - INTERNAL destroy all nodes in the specified CI list,
 *		freeing the t_call structures in each node as well.
 *
 * NOTE: 'ppCIHead' MUST contain the address of a valid CIDATA pointer.
 *
 * Parameters:
 *		ppCIHead		- [I/O] address of list head pointer
 *
 * Returns:
 *    Nothing.
 */

void DestroyCIList(CIDATA **ppCIHead) {
   CIDATA *pCINode = *ppCIHead;

   while (pCINode) {
		*ppCIHead = pCINode->pNext;
		t_free((char *)pCINode->pCall, T_CALL);
      free(pCINode);
      pCINode = *ppCIHead;
	}
	return;
}


/*************************************************************************
 * RejectAllCallsInCIList - INTERNAL call t_snddis on all connect
 *    indications in the list.
 *
 * Parameters:
 *		pCIHead		- [I/O] list head pointer
 *    sfd         - [IN ] server file descriptor
 *
 * Returns:
 *    Nothing.
 */

void RejectAllCallsInCIList(CIDATA *pCIHead, int sfd) {
   CIDATA *pCINode = pCIHead;

	while (pCINode) {
      t_snddis(sfd, pCINode->pCall);      /* errors don't matter */
      pCINode = pCINode->pNext;
   }
	return;
}


/*************************************************************************
 * AcceptIndications - accept first indication on the supplied indication
 *    queue.  Handle asynchronous events encountered during t_accept by
 *    passing queue on to HandleAsyncEvent.
 *
 *    NOTE: this routine presumes there is at least one node in the
 *       indication queue, or it would never have been called.
 *
 *    NOTE: 'ppCIHead' and 'ppCIFree' must contain the addresses of
 *       valid CIDATA pointers, even if these pointers are NULL.
 *
 * Parameters:
 *    sfd         - [IN ] server file descriptor
 *    ppCIHead    - [I/O] address of request queue head pointer
 *    ppCIFree    - [I/O] address of free queue head pointer
 *    pCIData     - [OUT} storage for retrieved & connected call
 *    transport   - [IN ] TLI transport stream device name
 *
 * Returns:
 *    -1 for fatal error, 0 for connected, 1 for recovered error,
 *       but no connection.
 */

int AcceptIndications(int sfd, CIDATA **ppCIHead, CIDATA **ppCIFree, CIDATA **ppCIData, char *transport) {
   int rc;

	if ((*ppCIData = GetLastInCIList(ppCIHead)) == NULL) {
      LogError("SVR: Indication queue is empty in %s (%d)", __FILE__, __LINE__);
      return -1;                                /* fatal error - this should never happen */
   }
	if (((*ppCIData)->cfd = OpenArbitraryTLIfd(transport)) < 0) {
		sprintf(syserr, "SYSERR %d - %s", errno, sys_errlist[errno]);
		LogError("SVR: t_open or t_bind failed in %s (%d) - reason: (%d) %s. %s", __FILE__, __LINE__, t_errno, t_errlist[t_errno], t_errno == TSYSERR? syserr : "");
		t_snddis(sfd, (*ppCIData)->pCall);        /* recovered by rejecting connect indication */
		PutFirstInCIList(ppCIFree, *ppCIData);
		return 1;
	}
	for ( ; ; ) {
		ThreadSwitchWithDelay();
		if (t_accept(sfd, (*ppCIData)->cfd, (*ppCIData)->pCall) < 0) {
			if (t_errno == TLOOK) {
				ThreadSwitchWithDelay();                              /* allow processing of Async event  */

            /*
             * HandleAsyncEvent() may return -1, 0, or > 0.  -1 indicates
             * a fatal error condition, log it and return a -1 to TLIListen().
             * 0 indicates the asynch event was successfully handled, and
             * > 0 indicates success, but a disconnect request was not found
             * in the head (in-use) list.  The actual value returned is
             * the sequence number (+1 to assure non-zero) of the
             * disconnecting indication.  We should compare this value (-1)
             * with number with the current block's (*ppCIData) sequence
             * number.  If they are the same, then it is the current
				 * indication that is trying to abort connection.  In this case
             * we unbind and close the client endpoint we are trying to
             * pass the indication to, and return a 1, telling TLIListen()
             * that we have recovered from a non-connect condition.
             */

            rc = HandleAsyncEvent(sfd, ppCIHead, ppCIFree);
				if (rc < 0) {                                         /* errors logged at a lower level   */
					t_snddis(sfd, (*ppCIData)->pCall);
					t_unbind((*ppCIData)->cfd);
					t_close((*ppCIData)->cfd);
					PutFirstInCIList(ppCIFree, *ppCIData);
					return -1;                                         /* fatal if error returned from HAE */
				}
            if (--rc == (*ppCIData)->pCall->sequence) {           /* discon not found in head, check current */
               t_unbind((*ppCIData)->cfd);
               t_close((*ppCIData)->cfd);
               PutFirstInCIList(ppCIFree, *ppCIData);
               return 1;
            }
				continue;                                             /* AE handled, try accepting again  */
			}
			else {
				sprintf(syserr, "SYSERR %d - %s", errno, sys_errlist[errno]);
				LogError("SVR: t_accept failed in %s (%d) - reason: (%d) %s. %s", __FILE__, __LINE__, t_errno, t_errlist[t_errno], t_errno == TSYSERR? syserr : "");
				t_snddis(sfd, (*ppCIData)->pCall);  /* recovered by rejecting connect indication */
				t_unbind((*ppCIData)->cfd);
				t_close((*ppCIData)->cfd);
				PutFirstInCIList(ppCIFree, *ppCIData);
				return 1;
			}
		}
		ThreadSwitchWithDelay();
		if (t_look((*ppCIData)->cfd) == T_DISCONNECT) {
			t_rcvdis((*ppCIData)->cfd, NULL);
			t_unbind((*ppCIData)->cfd);
			t_close((*ppCIData)->cfd);
			PutFirstInCIList(ppCIFree, *ppCIData);
         return 1;
		}
		break;
	}
	return 0;
}


/*************************************************************************
 * HandleAsyncEvent - call t_look to get pending async event, then
 *    process it according to the event type.  Since this function is
 *    called for TLOOK error codes returned from t_accept, it only deals
 *    with T_LISTEN and T_DISCONNECT events.  All other events are
 *    considered abnormal.
 *
 * Parameters:
 *    sfd         - [IN ] server file descriptor
 *    ppCIHead    - [I/O] pointer to head of connect indication list
 *    ppCIFree    - [I/O] pointer to head of free list
 *
 * Returns:
 *    -1 for abnormal event, 0 for normal event (T_LISTEN, or T_DISONNECT)
 *    or the sequence number of a pending disconnect request (+1 to assure
 *    a non-zero value).
 */

int HandleAsyncEvent(int sfd, CIDATA **ppCIHead, CIDATA **ppCIFree) {
   struct t_discon  *pDiscon;
   CIDATA           *pCIData;
	int               event;
	int					tcount = 0;
	int               rc = 0;

HAELookTry:

	switch (event = t_look(sfd)) {
		case T_LISTEN:

			/*
			 * Another connect indication has arrived.  Retrieve a free
			 * call structure, listen for pending connect indication,
			 * prepend it to the front of the indication queue and
			 * return to attempt the previous t_accept again.
			 */

			if ((pCIData = GetLastInCIList(ppCIFree)) == NULL) {
				LogError("SVR: Free list is empty %s (%d)", __FILE__, __LINE__);
				return -1;                             /* fatal error - CAN'T get more than TLI_QLEN concurrent cxt indications */
			}
			if (t_listen(sfd, pCIData->pCall) < 0) {
				sprintf(syserr, "SYSERR %d - %s", errno, sys_errlist[errno]);
				LogError("SVR: t_listen failed with in %s (%d) - reason: (%d) %s. %s", __FILE__, __LINE__, t_errno, t_errlist[t_errno], t_errno == TSYSERR? syserr : "");
				PutFirstInCIList(ppCIFree, pCIData);   /* recovered by returning node to free list */
				return 0;
			}
			PutFirstInCIList(ppCIHead, pCIData);
			return 0;

		case T_DISCONNECT:

			/*
			 * Someone has canceled a connect request.  Remove
			 * the disconnect indication from the stream and
          * find a pending connection that matches it.  Then
          * remove it from the head (in-use) list and add it back
          * to the free list.  We don't need to unbind and close
          * the cfd in the block because we haven't opened it yet.
          *
          * Note: it's possible to receive a discon request from
          * the client that AcceptIndications() is currently working
          * with, which means that the indication block will NOT be
          * in the head list.  We handle this situation by returning
          * the sequence number (+1 to assure non-zero) to the caller,
          * telling it that it should compare the result (-1) with
          * it's current block's sequence number. If they match,
          * it should close the client endpoint, and return 1 to
          * TLIListen() to indicate a recovered error condition.
			 * This condition should NOT be logged, as it is a valid
          * possible condition.
			 */

         if ((pDiscon = (struct t_discon *)t_alloc(sfd, T_DIS, T_ALL)) == NULL) {
				sprintf(syserr, "SYSERR %d - %s", errno, sys_errlist[errno]);
				LogError("SVR: t_alloc failed in %s (%d) - reason: (%d) %s. %s", __FILE__, __LINE__, t_errno, t_errlist[t_errno], t_errno == TSYSERR? syserr : "");
				return -1;                             /* fatal, small memory allocation failure */
			}
			if (t_rcvdis(sfd, pDiscon) != -1) {
            if ((pCIData = GetSequenceInCIList(ppCIHead, pDiscon->sequence)) != NULL)
               PutFirstInCIList(ppCIFree, pCIData);
            else
               rc = ++pDiscon->sequence;
         }
			t_free((char *)pDiscon, T_DIS);
         return rc;

		case T_ERROR:
		case -1:
			sprintf(syserr, "SYSERR %d - %s", errno, sys_errlist[errno]);
			LogError("SVR: attempt %d of t_look failed in %s (%d) - reason: (%d) %s. %s", tcount, __FILE__, __LINE__, t_errno, t_errlist[t_errno], t_errno == TSYSERR? syserr : "");
			if (tcount++ < 3)
				goto HAELookTry;
			return -1;                                /* fatal, t_look failed... */

		default:                                     /* this should NEVER happen */
			LogError("SVR: Unknown t_look event %d", event);
			return -1;                                /* fatal, don't know how to handle event (should NEVER happen) */
	}
}


/*************************************************************************
 * OpenSpecificTLIfd - opens a TLI end point in BLOCKING mode using the
 *    specified transport provider.  Then binds the end point to the
 *    socket using the specified address buffer.
 *
 * Parameters:
 *    transport   - [IN ] transport provider device path.
 *    qlen        - [IN ] TLI indication queue length (max simultaneous ind).
 *    addr        - [IN ] provider specific address buffer - port assigned.
 *    addrsize    - [IN ] size of provider specific address buffer.
 *		aout		   - [OUT] buffer for output address, (at least addrsize)
 *
 * Returns:
 *    a bound TLI end point file descriptor.
 *    -1 on error, no endpoint is opened.
 */

int OpenSpecificTLIfd(char *transport, int qlen,
   void *addr, int addrsize, void *aout) {
	struct t_bind bin;
	struct t_bind bout;
	int           fd;

	if ((fd = t_open(transport, O_RDWR, NULL)) == -1) {
      LogError("TLI(%s) Error: t_open failed in %s (%d) - (%d) %s",
			transport, __FILE__, __LINE__, t_error, t_errlist[t_errno]);
		return -1;
	}
	bin.addr.len 	  = addrsize;
	bin.addr.buf 	  = addr;
	bin.qlen     	  = qlen;
	bout.addr.maxlen = addrsize;
	bout.addr.buf	  = aout;

	if (t_bind(fd, &bin, &bout) == -1) {
		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;
}


/*************************************************************************
 * OpenArbitraryTLIfd - opens a TLI end point in BLOCKING mode using the
 *    specified transport provider.  Then binds the end point to the
 *    socket using an arbitrary address.
 *
 * Parameters:
 *    transport   - [IN ] transport provider device path.
 *
 * Returns:
 *    a bound TLI end point file descriptor.
 *    -1 on error, no endpoint is opened.
 */

int OpenArbitraryTLIfd(char *transport) {
	int fd;

⌨️ 快捷键说明

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