📄 httpd.c
字号:
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 + -