From 7b8f80e2846fabd25f7d8081ecf4e6d01b88db1b Mon Sep 17 00:00:00 2001 From: Kumar Kaushik <kaushikk@vmware.com> Date: Wed, 21 Feb 2018 15:20:36 -0800 Subject: [PATCH] Preprocess timeouts and avoid any race Change-Id: Idf091f71e81256d3b9fa15268b2f7fac8b6de551 --- common/sockinterface.c | 30 +-- server/restengine/httpProtocolHead.c | 38 ++-- transport/posix/socket.c | 418 +++++++++++++++++------------------ transport/posix/structs.h | 2 +- 4 files changed, 230 insertions(+), 258 deletions(-) diff --git a/common/sockinterface.c b/common/sockinterface.c index f737f78..197dd48 100644 --- a/common/sockinterface.c +++ b/common/sockinterface.c @@ -431,17 +431,11 @@ VmRESTOnConnectionTimeout( VMREST_LOG_DEBUG(pRESTHandle,"%s","Connection Timeout..Closing conn.."); - dwError = VmRESTSendFailureResponse( - pRESTHandle, - errCodeTimeOut, - pRequest - ); - if (dwError != REST_ENGINE_SUCCESS) - { - VMREST_LOG_ERROR(pRESTHandle,"Double Failure case detected with error code %u....", dwError); - } - dwError = REST_ENGINE_SUCCESS; - + VmRESTSendFailureResponse( + pRESTHandle, + errCodeTimeOut, + pRequest + ); dwError = VmRESTDisconnectClient( pRESTHandle, @@ -481,7 +475,6 @@ VmRESTTcpReceiveNewData( char* pszBuffer = NULL; uint32_t nProcessed = 0; uint32_t nBufLen = 0; - uint32_t ret = REST_ENGINE_SUCCESS; BOOLEAN bNextIO = FALSE; if (!pSocket || !pRESTHandle || !pQueue) @@ -589,19 +582,6 @@ VmRESTTcpReceiveNewData( VMREST_LOG_ERROR(pRESTHandle,"ERROR code %u", dwError); - if ((dwError == VMREST_TRANSPORT_DEFERRED_TIMEOUT_PROCESS) && (bNextIO)) - { - ret = VmRESTOnConnectionTimeout( - pRESTHandle, - pSocket - ); - - if (ret != REST_ENGINE_SUCCESS) - { - VMREST_LOG_ERROR(pRESTHandle,"Double failure on deferred timeout processing dwError, = %u", dwError); - dwError = REST_ENGINE_ERROR_DOUBLE_FAILURE; - } - } goto cleanup; } diff --git a/server/restengine/httpProtocolHead.c b/server/restengine/httpProtocolHead.c index a7ca54a..c5b9f3c 100644 --- a/server/restengine/httpProtocolHead.c +++ b/server/restengine/httpProtocolHead.c @@ -1347,7 +1347,6 @@ VmRESTProcessBuffer( ) { uint32_t dwError = REST_ENGINE_SUCCESS; - uint32_t ret = REST_ENGINE_SUCCESS; VM_REST_PROCESSING_STATE prevState = PROCESS_INVALID; VM_REST_PROCESSING_STATE currState = PROCESS_INVALID; uint32_t nProcessed = 0; @@ -1415,10 +1414,6 @@ VmRESTProcessBuffer( &(pRequest->pResponse) ); VMREST_LOG_INFO(pRESTHandle,"C-REST-ENGINE: Application callback returns dwError %u", dwError); - if ((dwError != REST_ENGINE_SUCCESS) && pRequest && pRequest->pResponse && pRequest->pResponse->statusLine) - { - VMREST_LOG_INFO(pRESTHandle,"C-REST-ENGINE: Status code: %s, header sent %d", pRequest->pResponse->statusLine->statusCode, pRequest->pResponse->bHeaderSent); - } BAIL_ON_VMREST_ERROR(dwError); bInitiateClose = TRUE; break; @@ -1446,21 +1441,14 @@ VmRESTProcessBuffer( error: VMREST_LOG_ERROR(pRESTHandle,"Process buffer failed with error code %u, sending failure response", dwError); - ret = VmRESTSendFailureResponse( - pRESTHandle, - dwError, - pRequest - ); - if (ret != REST_ENGINE_SUCCESS) - { - VMREST_LOG_ERROR(pRESTHandle,"%s","Double Failure case detected ...."); - VMREST_LOG_ERROR(pRESTHandle,"%s","possible memory leak"); - dwError = REST_ENGINE_ERROR_DOUBLE_FAILURE; - } - else - { - dwError = REST_ENGINE_SUCCESS; - } + VmRESTSendFailureResponse( + pRESTHandle, + dwError, + pRequest + ); + + dwError = REST_ENGINE_SUCCESS; + goto cleanup; } @@ -1524,13 +1512,19 @@ VmRESTSendFailureResponse( uint32_t nBytesWritten = 0; PVM_REST_HTTP_RESPONSE_PACKET pResponse = NULL; - if (!pRequest || !pRequest->pResponse) + if (!pRESTHandle || !pRequest || !pRequest->pResponse) { VMREST_LOG_ERROR(pRESTHandle,"%s","Invalid params"); dwError = VMREST_APPLICATION_INVALID_PARAMS; } BAIL_ON_VMREST_ERROR(dwError); + if (pRESTHandle->instanceState == VMREST_INSTANCE_STOPPED) + { + VMREST_LOG_ERROR(pRESTHandle, "%s", "Library trying to stop .. Rejecting request to send negative response"); + goto cleanup; + } + pResponse = pRequest->pResponse; VMREST_LOG_ERROR(pRESTHandle,"Preparing to send negative response to client, Error %u...", errorCode); @@ -1625,7 +1619,7 @@ VmRESTSendFailureResponse( return dwError; error: - VMREST_LOG_ERROR(pRESTHandle,"%s", "Double failure observed ... No response will be sent to client and connection will be forcefully closed."); + VMREST_LOG_ERROR(pRESTHandle,"%s", "Double failure observed while sending negative response..."); goto cleanup; diff --git a/transport/posix/socket.c b/transport/posix/socket.c index b34ef15..44cfbfd 100644 --- a/transport/posix/socket.c +++ b/transport/posix/socket.c @@ -89,6 +89,12 @@ VmRESTCreateSSLObject( PVM_SOCKET pSocket ); +static +void +VmSockPosixPreProcessTimeouts( + PVMREST_HANDLE pRESTHandle, + PVM_SOCK_EVENT_QUEUE pQueue + ); DWORD @@ -501,9 +507,7 @@ VmSockPosixWaitForEvent( BOOLEAN bLocked = FALSE; VM_SOCK_EVENT_TYPE eventType = VM_SOCK_EVENT_TYPE_UNKNOWN; PVM_SOCKET pSocket = NULL; - BOOLEAN bFound = FALSE; BOOLEAN bFreeEventQueue = 0; - int i = 0; if (!pQueue || !ppSocket || !pEventType) { @@ -550,12 +554,21 @@ VmSockPosixWaitForEvent( { if (pQueue->iReady < pQueue->nReady) { + /**** Preprocess timeouts ****/ + if (pQueue->iReady == 0) + { + VmSockPosixPreProcessTimeouts( + pRESTHandle, + pQueue + ); + } + struct epoll_event* pEvent = &pQueue->pEventArray[pQueue->iReady]; PVM_SOCKET pEventSocket = (PVM_SOCKET)pEvent->data.ptr; if (!pEventSocket) { - VMREST_LOG_ERROR(pRESTHandle,"%s","Bad socket information"); + VMREST_LOG_DEBUG(pRESTHandle,"%s","Bad socket information"); dwError = ERROR_INVALID_STATE; BAIL_ON_VMREST_ERROR(dwError); } @@ -565,22 +578,16 @@ VmSockPosixWaitForEvent( if (pEvent->events & (EPOLLERR | EPOLLHUP)) { eventType = VM_SOCK_EVENT_TYPE_CONNECTION_CLOSED; - dwError = VmSockPosixDeleteEventFromQueue( - pRESTHandle, - pQueue, - pEventSocket - ); - BAIL_ON_VMREST_ERROR(dwError); pSocket = pEventSocket; + BAIL_ON_VMREST_ERROR(dwError); } else if (pEventSocket->type == VM_SOCK_TYPE_LISTENER) // New connection request { - VMREST_LOG_INFO(pRESTHandle,"%s","C-REST-ENGINE: ======================== NEW REQUEST =========================="); dwError = VmSockPosixAcceptConnection( pEventSocket, &pSocket); BAIL_ON_VMREST_ERROR(dwError); - VMREST_LOG_INFO(pRESTHandle,"C-REST-ENGINE: Accepted new connection with socket fd %d", pSocket->fd); + VMREST_LOG_INFO(pRESTHandle,"C-REST-ENGINE: ( NEW REQUEST ) Accepted new connection with socket fd %d", pSocket->fd); dwError = VmSockPosixSetNonBlocking(pRESTHandle,pSocket); BAIL_ON_VMREST_ERROR(dwError); @@ -643,120 +650,60 @@ VmSockPosixWaitForEvent( } else if (pEventSocket->type == VM_SOCK_TYPE_TIMER) // Time out event { - eventType = VM_SOCK_EVENT_TYPE_UNKNOWN; pSocket = pEventSocket; + VMREST_LOG_INFO(pRESTHandle, "Timeout event happened on IO Socket fd %d, timer fd %d", pSocket->pIoSocket->fd, pSocket->fd); - VMREST_LOG_DEBUG(pRESTHandle, "Timeout event happened on timer fd %d", pSocket->fd); - - if (pSocket->pIoSocket != NULL) + if (pSocket->pIoSocket) { - /*** Scan pQueue and look for IO event corresponding to this timer event ***/ - for ((i = (pQueue->iReady + 1)); i < pQueue->nReady ; i++) - { - struct epoll_event* pEventTemp = &pQueue->pEventArray[i]; - PVM_SOCKET pEventSocketTemp = (PVM_SOCKET)pEventTemp->data.ptr; - if (pEventSocketTemp->fd == pEventSocket->pIoSocket->fd) - { - pEventSocket->pIoSocket->pTimerSocket = NULL; - bFound = TRUE; - break; - } - } + /**** Delete IO socket from queue so that we don't get any further notification ****/ + dwError = VmSockPosixDeleteEventFromQueue( + pRESTHandle, + pQueue, + pSocket->pIoSocket + ); + BAIL_ON_VMREST_ERROR(dwError); - if (bFound) + if ((pRESTHandle->pSSLInfo->isSecure) && (!(pSocket->pIoSocket->bSSLHandShakeCompleted))) { - VMREST_LOG_DEBUG(pRESTHandle,"Action: DEFERRED, IO sock found in queue(Succeeding), Io Sock %d, timer %d", pSocket->pIoSocket->fd, pSocket->fd ); - pEventSocket->pIoSocket->pTimerSocket = NULL; + /**** SSL handshake is not completed, no response will be sent, free IoSocket ****/ + VmSockPosixCloseSocket(pRESTHandle,pSocket->pIoSocket); + VmSockPosixReleaseSocket(pRESTHandle,pSocket->pIoSocket); + pSocket = NULL; } else { - if (pSocket->pIoSocket->bInUse == TRUE) - { - VMREST_LOG_DEBUG(pRESTHandle,"Action: DEFERRED, IO Soc in use, IoSocket %d, timer %d", pSocket->pIoSocket->fd, pSocket->fd ); - pEventSocket->pIoSocket->pTimerSocket = NULL; - } - else - { - /**** We are good to close actual IO Socket here ****/ - VMREST_LOG_INFO(pRESTHandle,"Action: IO DELETION, IoSocket %d, timer %d", pSocket->pIoSocket->fd, pSocket->fd ); - - pSocket = pEventSocket->pIoSocket; - /**** Delete IO from queue ****/ - VmSockPosixDeleteEventFromQueue( - pRESTHandle, - pQueue, - pSocket - ); - - if ((pRESTHandle->pSSLInfo->isSecure) && (!(pSocket->bSSLHandShakeCompleted))) - { - /**** SSL handshake is not completed, no response will be sent, free IoSocket ****/ - pEventSocket->pIoSocket = NULL; - VmSockPosixCloseSocket(pRESTHandle,pSocket); - VmSockPosixReleaseSocket(pRESTHandle,pSocket); - eventType = VM_SOCK_EVENT_TYPE_UNKNOWN; - } - else - { - eventType = VM_SOCK_EVENT_TYPE_CONNECTION_TIMEOUT; - pEventSocket->pIoSocket->pTimerSocket = NULL; - } - } + pSocket = pSocket->pIoSocket; + eventType = VM_SOCK_EVENT_TYPE_CONNECTION_TIMEOUT; } } - - /** Close and free the timer socket ****/ - VmSockPosixCloseSocket(pRESTHandle,pEventSocket); - VmSockPosixReleaseSocket(pRESTHandle,pEventSocket); - - if (eventType == VM_SOCK_EVENT_TYPE_UNKNOWN) - { - pSocket = NULL; - } } else // Data available on IO Socket { pSocket = pEventSocket; + VMREST_LOG_DEBUG(pRESTHandle,"Data notification on socket fd %d", pSocket->fd); + + /**** stop the timer ****/ + dwError = VmSockPosixReArmTimer( + pRESTHandle, + pSocket->pTimerSocket, + 0 + ); + BAIL_ON_VMREST_ERROR(dwError); - /**** Mark IO socket in use - timer out event cannot modify IO till this is done ****/ - pSocket->bInUse = TRUE; - - if (pSocket->pTimerSocket == NULL) + /**** If SSL handshake is not yet complete, do the needful ****/ + if ((pRESTHandle->pSSLInfo->isSecure) && (!(pSocket->bSSLHandShakeCompleted))) { - /**** Time out already occurred on this socket.. request won't be processed ****/ - VmSockPosixCloseSocket(pRESTHandle,pSocket); - VmSockPosixReleaseSocket(pRESTHandle,pSocket); + dwError = VmRESTAcceptSSLContext( + pRESTHandle, + pSocket, + TRUE + ); + BAIL_ON_VMREST_ERROR(dwError); + pSocket = NULL; } else { - /**** Process data ****/ - VMREST_LOG_DEBUG(pRESTHandle,"Data notification on socket fd %d", pSocket->fd); - - /**** If SSL handshake is not yet complete, do the needful ****/ - if ((pRESTHandle->pSSLInfo->isSecure) && (!(pSocket->bSSLHandShakeCompleted))) - { - dwError = VmRESTAcceptSSLContext( - pRESTHandle, - pSocket, - TRUE - ); - BAIL_ON_VMREST_ERROR(dwError); - - /**** We do not need IO any more ..mark as available for timer ****/ - pSocket->bInUse = FALSE; - } - else - { - eventType = VM_SOCK_EVENT_TYPE_DATA_AVAILABLE; - - /*** Disarm timer associated with this IO socket .. dont delete ***/ - dwError = VmSockPosixReArmTimer( - pRESTHandle, - pSocket->pTimerSocket, - 0 - ); - BAIL_ON_VMREST_ERROR(dwError); - } + eventType = VM_SOCK_EVENT_TYPE_DATA_AVAILABLE; } } } @@ -792,6 +739,10 @@ VmSockPosixWaitForEvent( { VMREST_LOG_INFO(pRESTHandle,"C-REST-ENGINE: Shutting down...Cleaning worker thread %d", (pQueue->thrCnt + 1)); } + else if(dwError == ERROR_INVALID_STATE) + { + VMREST_LOG_DEBUG(pRESTHandle,"%s", "Skipping IO processing for timeout"); + } else { VMREST_LOG_ERROR(pRESTHandle,"Error while processing socket event, dwError = %u", dwError); @@ -1035,29 +986,11 @@ VmSockPosixRead( error: - if (pSocket && pRESTHandle && pRESTHandle->pSockContext) + if (pSocket) { - /**** Delete the socket from poller ****/ - VmSockPosixDeleteEventFromQueue( - pRESTHandle, - pRESTHandle->pSockContext->pEventQueue, - pSocket - ); - pSocket->pszBuffer = NULL; pSocket->nProcessed = 0; pSocket->nBufData = 0; - - if (pSocket->pTimerSocket) - { - pSocket->pTimerSocket->pIoSocket = NULL; - VmSockPosixReArmTimer( - pRESTHandle, - pSocket->pTimerSocket, - 1 - ); - } - } if (pszBufPrev) @@ -1197,6 +1130,11 @@ VmSockPosixReleaseSocket( { if (pSocket) { + if (pSocket->pTimerSocket) + { + VmSockPosixFreeSocket(pSocket->pTimerSocket); + pSocket->pTimerSocket = NULL; + } VmSockPosixFreeSocket(pSocket); } } @@ -1210,9 +1148,11 @@ VmSockPosixCloseSocket( DWORD dwError = REST_ENGINE_SUCCESS; int ret = 0; uint32_t errorCode = 0; - BOOLEAN bLocked = FALSE; + BOOLEAN bLockedIO = FALSE; + BOOLEAN bLockedTimer = FALSE; + PVM_SOCKET pTimerSocket = NULL; - if (!pRESTHandle || !pSocket ) + if (!pRESTHandle || !pSocket || !(pRESTHandle->pSockContext)) { VMREST_LOG_ERROR(pRESTHandle,"%s","Invalid Params.."); dwError = ERROR_INVALID_PARAMETER; @@ -1221,23 +1161,59 @@ VmSockPosixCloseSocket( VMREST_LOG_INFO(pRESTHandle,"C-REST-ENGINE: Closing socket with fd %d, Socket Type %u ( 2-Io / 5-Timer )", pSocket->fd, pSocket->type); + pTimerSocket = pSocket->pTimerSocket; + + /**** Close the timer socket ****/ + if (pTimerSocket) + { + dwError = VmRESTLockMutex(pTimerSocket->pMutex); + BAIL_ON_VMREST_ERROR(dwError); + + bLockedTimer = TRUE; + + dwError = VmSockPosixDeleteEventFromQueue( + pRESTHandle, + pRESTHandle->pSockContext->pEventQueue, + pTimerSocket + ); + BAIL_ON_VMREST_ERROR(dwError); + + if (pTimerSocket->fd > 0) + { + close(pTimerSocket->fd); + pTimerSocket->fd = INVALID; + } + VmRESTUnlockMutex(pTimerSocket->pMutex); + bLockedTimer = FALSE; + } + dwError = VmRESTLockMutex(pSocket->pMutex); BAIL_ON_VMREST_ERROR(dwError); - bLocked = TRUE; + bLockedIO = TRUE; - if (pSocket->pTimerSocket) + /**** Delete from queue if this is NOT timeout ****/ + if ((pSocket->type == VM_SOCK_TYPE_SERVER) && (!(pSocket->bTimerExpired))) { - pSocket->pTimerSocket->pIoSocket = NULL; + dwError = VmSockPosixDeleteEventFromQueue( + pRESTHandle, + pRESTHandle->pSockContext->pEventQueue, + pSocket + ); + BAIL_ON_VMREST_ERROR(dwError); } + /**** Close IO socket fd ****/ if (pRESTHandle->pSSLInfo->isSecure && pSocket->ssl && (pSocket->type != VM_SOCK_TYPE_TIMER)) { - ret = SSL_shutdown(pSocket->ssl); - if (ret < 0) + if (pSocket->bSSLHandShakeCompleted) { - errorCode = SSL_get_error(pSocket->ssl, ret); - VMREST_LOG_ERROR(pRESTHandle,"Error on SSL_shutdown on socket %d, return value %d, errorCode %u, errno %d", pSocket->fd, ret, errorCode, errno); + ret = SSL_shutdown(pSocket->ssl); + if (ret < 0) + { + errorCode = SSL_get_error(pSocket->ssl, ret); + VMREST_LOG_ERROR(pRESTHandle,"Error on SSL_shutdown on socket %d, return value %d, errorCode %u, errno %d", pSocket->fd, ret, errorCode, errno); + } } SSL_free(pSocket->ssl); pSocket->ssl = NULL; @@ -1249,17 +1225,25 @@ VmSockPosixCloseSocket( pSocket->fd = -1; } -cleanup: + VmRESTUnlockMutex(pSocket->pMutex); + bLockedIO = FALSE; - if (bLocked) - { - VmRESTUnlockMutex(pSocket->pMutex); - } +cleanup: return dwError; error: + if (bLockedTimer) + { + VmRESTUnlockMutex(pTimerSocket->pMutex); + } + + if (bLockedIO) + { + VmRESTUnlockMutex(pSocket->pMutex); + } + goto cleanup; } @@ -1419,7 +1403,7 @@ VmSockPosixAcceptConnection( pSocket->pTimerSocket = NULL; pSocket->pIoSocket = NULL; pSocket->bSSLHandShakeCompleted = FALSE; - pSocket->bInUse = FALSE; + pSocket->bTimerExpired = FALSE; *ppSocket = pSocket; @@ -1639,58 +1623,24 @@ VmSockPosixSetRequestHandle( pSocket->nProcessed = nProcessed; - if (bCompleted) + if (!bCompleted) { - /**** We are done with request - no need to add back to poller *****/ - if (pSocket->pTimerSocket != NULL) - { - pSocket->pTimerSocket->pIoSocket = NULL; - - /**** Give immediate notification to timer for cleanup ****/ - dwError = VmSockPosixReArmTimer( - pRESTHandle, - pSocket->pTimerSocket, - 1 - ); - BAIL_ON_VMREST_ERROR(dwError); - } - - /**** Delete actual IO socket from poller ****/ - dwError = VmSockPosixDeleteEventFromQueue( + /***** Add back IO socket to poller for next IO cycle and restart timer ****/ + dwError = VmSockPosixReArmTimer( pRESTHandle, - pQueue, - pSocket + pSocket->pTimerSocket, + ((pRESTHandle->pRESTConfig->connTimeoutSec) * 1000) ); BAIL_ON_VMREST_ERROR(dwError); - } - else - { - /***** Add back IO socket to poller for next IO cycle ****/ - if (pSocket->pTimerSocket == NULL) - { - /**** Timeout already happened. Notify HTTP layer to send 408 Req timeout - if possible ****/ - dwError = VMREST_TRANSPORT_DEFERRED_TIMEOUT_PROCESS; - } - else - { - /*** Rearm timer and add IO socket to poller ****/ - dwError = VmSockPosixReArmTimer( - pRESTHandle, - pSocket->pTimerSocket, - ((pRESTHandle->pRESTConfig->connTimeoutSec) * 1000) - ); - BAIL_ON_VMREST_ERROR(dwError); - event.data.ptr = pSocket; - event.events = EPOLLIN; + event.data.ptr = pSocket; + event.events = EPOLLIN; - event.events = event.events | EPOLLONESHOT; + event.events = event.events | EPOLLONESHOT; - if (epoll_ctl(pQueue->epollFd, EPOLL_CTL_MOD, pSocket->fd, &event) < 0) - { - dwError = VM_SOCK_POSIX_ERROR_SYS_CALL_FAILED; - BAIL_ON_VMREST_ERROR(dwError); - } + if (epoll_ctl(pQueue->epollFd, EPOLL_CTL_MOD, pSocket->fd, &event) < 0) + { + dwError = VM_SOCK_POSIX_ERROR_SYS_CALL_FAILED; } BAIL_ON_VMREST_ERROR(dwError); } @@ -1701,10 +1651,6 @@ VmSockPosixSetRequestHandle( { VmRESTUnlockMutex(pSocket->pMutex); } - if (!bCompleted && pSocket && (pSocket->pTimerSocket != NULL)) - { - pSocket->bInUse = FALSE; - } return dwError; @@ -1871,13 +1817,13 @@ VmSockPosixCreateTimer( pTimerSocket->type = VM_SOCK_TYPE_TIMER; pTimerSocket->fd = timerFd; - pTimerSocket->bInUse = FALSE; pTimerSocket->pIoSocket = pSocket; pTimerSocket->pRequest = NULL; pTimerSocket->pszBuffer = NULL; pTimerSocket->nBufData = 0; pTimerSocket->nProcessed = 0; pTimerSocket->pTimerSocket = NULL; + pTimerSocket->bTimerExpired = FALSE; pSocket->pTimerSocket = pTimerSocket; @@ -1902,6 +1848,11 @@ VmSockPosixCreateTimer( error: + if (timerFd > 0) + { + close(timerFd); + } + if (pTimerSocket) { VmSockPosixFreeSocket(pTimerSocket); @@ -1988,26 +1939,6 @@ VmRESTAcceptSSLContext( error: - if (pRESTHandle && pRESTHandle->pSockContext) - { - /**** Delete from poller ****/ - VmSockPosixDeleteEventFromQueue( - pRESTHandle, - pRESTHandle->pSockContext->pEventQueue, - pSocket - ); - - if (bWatched && pSocket && pSocket->pTimerSocket) - { - pSocket->pTimerSocket->pIoSocket = NULL; - VmSockPosixReArmTimer( - pRESTHandle, - pSocket->pTimerSocket, - 1 - ); - } - } - goto cleanup; } @@ -2067,3 +1998,70 @@ VmRESTCreateSSLObject( goto cleanup; } + +static +void +VmSockPosixPreProcessTimeouts( + PVMREST_HANDLE pRESTHandle, + PVM_SOCK_EVENT_QUEUE pQueue + ) +{ + struct epoll_event* pQueueEvent = NULL; + PVM_SOCKET pSocket = NULL; + PVM_SOCKET pTimerSocket = NULL; + PVM_SOCKET pIoSocket = NULL; + int index = 0; + uint32_t nTimerEvents = 0; + + /**** Mark all IO socket from corresponding timer as expired ****/ + for (index = 0; index < pQueue->nReady; index++) + { + pQueueEvent = &pQueue->pEventArray[index]; + if (pQueueEvent) + { + pSocket = (PVM_SOCKET)pQueueEvent->data.ptr; + if (pSocket && (pSocket->type == VM_SOCK_TYPE_TIMER)) + { + pTimerSocket = pSocket; + pIoSocket = pTimerSocket->pIoSocket; + if (pIoSocket) + { + pIoSocket->bTimerExpired = TRUE; + nTimerEvents++; + VMREST_LOG_DEBUG(pRESTHandle,"Timeout found for IoSocket fd %d, Timer fd %d", pIoSocket->fd, pTimerSocket->fd); + } + pTimerSocket = NULL; + pIoSocket = NULL; + } + pSocket = NULL; + } + pQueueEvent = NULL; + } + + /**** Set QueueEvent->data.ptr to NULL for all expired IO socket if present in the current queue - worker will not process those ****/ + if (nTimerEvents > 0) + { + pSocket = NULL; + pQueueEvent = NULL; + index = 0; + + for (index = 0; index < pQueue->nReady; index++) + { + pQueueEvent = &pQueue->pEventArray[index]; + if (pQueueEvent) + { + pSocket = (PVM_SOCKET)pQueueEvent->data.ptr; + if (pSocket && (pSocket->type == VM_SOCK_TYPE_SERVER) && (pSocket->bTimerExpired == TRUE)) + { + pQueueEvent->data.ptr = NULL; + VMREST_LOG_WARNING(pRESTHandle,"Near race detected for IoSocket fd %d", pSocket->fd); + } + pSocket = NULL; + } + pQueueEvent = NULL; + } + } + + return; +} + diff --git a/transport/posix/structs.h b/transport/posix/structs.h index 369cfcb..82047fe 100644 --- a/transport/posix/structs.h +++ b/transport/posix/structs.h @@ -20,7 +20,7 @@ typedef struct _VM_SOCKET int fd; SSL* ssl; BOOLEAN bSSLHandShakeCompleted; - BOOLEAN bInUse; + BOOLEAN bTimerExpired; char* pszBuffer; uint32_t nBufData; uint32_t nProcessed;