From 96a49b724295422ceb6465553fdf0da20e5a3b6d Mon Sep 17 00:00:00 2001 From: Kumar Kaushik Date: Mon, 29 Jan 2018 19:30:18 -0800 Subject: [PATCH] Handling timeout events for faulty application callback Change-Id: I9a412f6d7cf2c3345c73f0581906829bd183e445 --- common/sockinterface.c | 26 ++- include/public/vmrest.h | 1 + include/vmrestdefines.h | 9 + server/restengine/httpAllocStruct.c | 4 +- server/restengine/httpProtocolHead.c | 7 +- transport/posix/socket.c | 425 ++++++++++++++++++----------------- transport/posix/structs.h | 1 + 7 files changed, 257 insertions(+), 216 deletions(-) diff --git a/common/sockinterface.c b/common/sockinterface.c index 403189c..9e7d404 100644 --- a/common/sockinterface.c +++ b/common/sockinterface.c @@ -327,14 +327,13 @@ VmRESTHandleSocketEvent( break; case VM_SOCK_EVENT_TYPE_CONNECTION_TIMEOUT: - /**** Free Associated memory ****/ - VMREST_LOG_DEBUG(pRESTHandle,"%s","EVENT-HANDLER: Connection timeout happened..Disconnecting client ..."); - dwError = VmRESTOnConnectionTimeout( + VMREST_LOG_DEBUG(pRESTHandle,"%s","EVENT-HANDLER: Connection timeout happened..Disconnecting client"); + dwError = VmRESTOnConnectionTimeout( pRESTHandle, pSocket ); - BAIL_ON_VMREST_ERROR(dwError); - break; + BAIL_ON_VMREST_ERROR(dwError); + break; case VM_SOCK_EVENT_TYPE_UNKNOWN: VMREST_LOG_DEBUG(pRESTHandle,"%s","EVENT-HANDLER: Unknown Socket Event, do nothing"); @@ -436,6 +435,7 @@ 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) @@ -517,7 +517,7 @@ VmRESTTcpReceiveNewData( cleanup: - if (!bNextIO) + if (!bNextIO && dwError != REST_ENGINE_ERROR_DOUBLE_FAILURE) { VMREST_LOG_DEBUG(pRESTHandle,"%s","Calling closed connection...."); /**** Close connection ****/ @@ -542,6 +542,20 @@ VmRESTTcpReceiveNewData( error: 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/include/public/vmrest.h b/include/public/vmrest.h index 3988266..5219952 100644 --- a/include/public/vmrest.h +++ b/include/public/vmrest.h @@ -32,6 +32,7 @@ /**** REST ENGINE ERROR CODES ****/ #define REST_ENGINE_SUCCESS 0 #define REST_ENGINE_FAILURE 1 +#define REST_ENGINE_ERROR_DOUBLE_FAILURE 99 #define REST_ERROR_MISSING_CONFIG 100 #define REST_ERROR_INVALID_CONFIG 101 #define REST_ERROR_NO_MEMORY 102 diff --git a/include/vmrestdefines.h b/include/vmrestdefines.h index 914422a..8a37628 100644 --- a/include/vmrestdefines.h +++ b/include/vmrestdefines.h @@ -63,6 +63,15 @@ #define VMREST_TRANSPORT_COND_INIT_FAILED 61125 #define VMREST_TRANSPORT_SERVER_THREAD_START_FAILED 61126 + +#define VMREST_TRANSPORT_DEFERRED_TIMEOUT_PROCESS 61127 +#define VMREST_TRANSPORT_SOCK_READ_FAILED 61128 +#define VMREST_TRANSPORT_SOCK_WRITE_FAILED 61129 +#define VMREST_TRANSPORT_SOCK_GET_HANDLE_FAILED 61130 +#define VMREST_TRANSPORT_SOCK_SET_HANDLE_FAILED 61131 +#define VMREST_TRANSPORT_SOCK_DATA_OVER_LIMIT 61132 +#define VMREST_TRANSPORT_REMOTE_CONN_CLOSED 61133 + #define ERROR_TRANSPORT_INVALID_PARAMS 61040 #define ERROR_TRANSPORT_VALIDATION_FAILED 61041 diff --git a/server/restengine/httpAllocStruct.c b/server/restengine/httpAllocStruct.c index 64cb846..27aa9ed 100644 --- a/server/restengine/httpAllocStruct.c +++ b/server/restengine/httpAllocStruct.c @@ -519,11 +519,13 @@ VmRESTAllocateMiscQueue( PMISC_HEADER_QUEUE pMiscQueue = NULL; dwError = VmRESTAllocateMemory( - sizeof(VM_REST_HTTP_MESSAGE_BODY), + sizeof(MISC_HEADER_QUEUE), (void**)&pMiscQueue ); BAIL_ON_VMREST_ERROR(dwError); + pMiscQueue->head = NULL; + *ppMiscHeaderQueue = pMiscQueue; cleanup: diff --git a/server/restengine/httpProtocolHead.c b/server/restengine/httpProtocolHead.c index 18cff08..95089a3 100644 --- a/server/restengine/httpProtocolHead.c +++ b/server/restengine/httpProtocolHead.c @@ -1448,8 +1448,13 @@ VmRESTProcessBuffer( 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; } - dwError = REST_ENGINE_SUCCESS; goto cleanup; } diff --git a/transport/posix/socket.c b/transport/posix/socket.c index 6c0e14e..207075b 100644 --- a/transport/posix/socket.c +++ b/transport/posix/socket.c @@ -81,13 +81,6 @@ VmSockPosixReArmTimer( int milliSec ); -static -BOOLEAN -VmSockPosixIsSafeToCloseConnOnTimeOut( - PVMREST_HANDLE pRESTHandle, - PVM_SOCKET pTimerSocket - ); - static uint32_t VmRESTAcceptSSLContext( @@ -482,7 +475,9 @@ 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) { @@ -551,7 +546,7 @@ VmSockPosixWaitForEvent( BAIL_ON_VMREST_ERROR(dwError); pSocket = pEventSocket; } - else if (pEventSocket->type == VM_SOCK_TYPE_LISTENER) + else if (pEventSocket->type == VM_SOCK_TYPE_LISTENER) // New connection request { VMREST_LOG_INFO(pRESTHandle,"%s","C-REST-ENGINE: ======================== NEW REQUEST =========================="); dwError = VmSockPosixAcceptConnection( @@ -572,6 +567,7 @@ VmSockPosixWaitForEvent( ); BAIL_ON_VMREST_ERROR(dwError); + /**** Try SSL Handshake ****/ dwError = VmRESTAcceptSSLContext( pRESTHandle, pSocket, @@ -580,6 +576,7 @@ VmSockPosixWaitForEvent( BAIL_ON_VMREST_ERROR(dwError); } + /**** Start watching new connection ****/ dwError = VmSockPosixEventQueueAdd_inlock( pQueue, TRUE, @@ -593,9 +590,12 @@ VmSockPosixWaitForEvent( pSocket ); BAIL_ON_VMREST_ERROR(dwError); + eventType = VM_SOCK_EVENT_TYPE_TCP_NEW_CONNECTION; + + VMREST_LOG_DEBUG(pRESTHandle,"Timer fd %d associated with socket fd %d", pSocket->pTimerSocket->fd ,pSocket->fd); } - else if (pEventSocket->type == VM_SOCK_TYPE_SIGNAL) + else if (pEventSocket->type == VM_SOCK_TYPE_SIGNAL) // Shutdown library { if (pQueue->bShutdown) { @@ -614,58 +614,108 @@ VmSockPosixWaitForEvent( eventType = VM_SOCK_EVENT_TYPE_DATA_AVAILABLE; } } - else if (pEventSocket->type == VM_SOCK_TYPE_TIMER) + else if (pEventSocket->type == VM_SOCK_TYPE_TIMER) // Time out event { - /**** No activity on the socket watched by poller till timeout ****/ - if (VmSockPosixIsSafeToCloseConnOnTimeOut(pRESTHandle, pEventSocket)) + eventType = VM_SOCK_EVENT_TYPE_UNKNOWN; + pSocket = pEventSocket; + + VMREST_LOG_DEBUG(pRESTHandle, "Timeout event happened on timer fd %d", pSocket->fd); + + if (pSocket->pIoSocket != NULL) { - pSocket = pEventSocket; + /*** 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 timer socket from poller ****/ - dwError = VmSockPosixEventQueueDelete_inlock( - pQueue, - pSocket - ); - BAIL_ON_VMREST_ERROR(dwError); + if (bFound) + { + VMREST_LOG_DEBUG(pRESTHandle,"Action: DEFERRED, IO sock found in queue(Succeeding), Io Sock %d, timer %d", pSocket->pIoSocket->fd, pSocket->fd ); + } + 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 ); + eventType = VM_SOCK_EVENT_TYPE_CONNECTION_TIMEOUT; + pSocket = pSocket->pIoSocket; + + /**** Delete IO from queue ****/ + VmSockPosixEventQueueDelete_inlock( + pQueue, + pSocket + ); + } + } + } - /**** Delete actual IO socket from poller ****/ - dwError = VmSockPosixEventQueueDelete_inlock( - pQueue, - pSocket->pIoSocket - ); - BAIL_ON_VMREST_ERROR(dwError); + /** Close and free the timer socket ****/ + VmSockPosixCloseSocket(pRESTHandle,pEventSocket); + VmSockPosixReleaseSocket(pRESTHandle,pEventSocket); - pSocket = pEventSocket->pIoSocket; - eventType = VM_SOCK_EVENT_TYPE_CONNECTION_TIMEOUT; + if (eventType == VM_SOCK_EVENT_TYPE_UNKNOWN) + { + pSocket = NULL; } } - else + else // Data available on IO Socket { - /**** Data is available over the socket ****/ - pSocket = pEventSocket; + pSocket = pEventSocket; - /**** 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); - } - else - { - eventType = VM_SOCK_EVENT_TYPE_DATA_AVAILABLE; + /**** Mark IO socket in use - timer out event cannot modify IO till this is done ****/ + pSocket->bInUse = TRUE; - /**** Stop timer on the socket ****/ - dwError = VmSockPosixReArmTimer( - pRESTHandle, - pSocket->pTimerSocket, - 0 - ); - BAIL_ON_VMREST_ERROR(dwError); - } + if (pSocket->pTimerSocket == NULL) + { + /**** Time out already occurred on this socket.. request won't be processed ****/ + VmSockPosixCloseSocket(pRESTHandle,pSocket); + VmSockPosixReleaseSocket(pRESTHandle,pSocket); + } + 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); + } + } } } pQueue->iReady++; @@ -696,7 +746,7 @@ VmSockPosixWaitForEvent( error: - VMREST_LOG_ERROR(pRESTHandle,"%s","Socket layer - wait for event error"); + VMREST_LOG_ERROR(pRESTHandle,"Error while processing socket event, dwError = %u", dwError); if (ppSocket) { *ppSocket = NULL; @@ -884,8 +934,8 @@ VmSockPosixRead( if (nPrevBuf >= pRESTHandle->pRESTConfig->maxDataPerConnMB) { /**** Discard the request here itself. This might be the first read IO cycle ****/ - VMREST_LOG_ERROR(pRESTHandle,"Total Data in request %u bytes is over allowed limit of %u bytes, closing connection...", nPrevBuf, pRESTHandle->pRESTConfig->maxDataPerConnMB); - dwError = REST_ENGINE_FAILURE; + VMREST_LOG_ERROR(pRESTHandle,"Total Data in request %u bytes is over allowed limit of %u bytes, closing connection with fd %d", nPrevBuf, pRESTHandle->pRESTConfig->maxDataPerConnMB, pSocket->fd); + dwError = VMREST_TRANSPORT_SOCK_DATA_OVER_LIMIT; } BAIL_ON_VMREST_ERROR(dwError); @@ -897,8 +947,8 @@ VmSockPosixRead( } else { - VMREST_LOG_ERROR(pRESTHandle,"Unknown socket read error: errno %u, errorCode %u, nRead %d", errno, errorCode, nRead); - dwError = REST_ENGINE_FAILURE; + VMREST_LOG_ERROR(pRESTHandle,"Socket read error: errno %u, errorCode %u, nRead %d", errno, errorCode, nRead); + dwError = VMREST_TRANSPORT_SOCK_READ_FAILED; } } else @@ -906,12 +956,12 @@ VmSockPosixRead( if (nRead == 0) { VMREST_LOG_ERROR(pRESTHandle,"%s","Socket Read Failed: Remote has closed the connection"); - dwError = VM_SOCK_POSIX_ERROR_BROKEN_PIPE; + dwError = VMREST_TRANSPORT_SOCK_READ_FAILED; } else { VMREST_LOG_ERROR(pRESTHandle, "Socket read failed with error code %u", errorCode); - dwError = errorCode; + dwError = VMREST_TRANSPORT_SOCK_READ_FAILED; } } BAIL_ON_VMREST_ERROR(dwError); @@ -936,29 +986,37 @@ VmSockPosixRead( error: - if (pSocket) - { - VMREST_LOG_ERROR(pRESTHandle,"Socket read failed with Socket fd %d, dwError = %u, nRead = %d, errno = %u, errorCode = %u", pSocket->fd, dwError, nRead, errno, errorCode); - } - else - { - VMREST_LOG_ERROR(pRESTHandle,"Socket read failed with dwError = %u, nRead = %d, errno = %u, errorCode = %u", dwError, nRead, errno, errorCode); - } - - if (pszBufPrev && pSocket && pRESTHandle->pSockContext) + if (pSocket && pRESTHandle->pSockContext) { /**** Delete the socket from poller ****/ - - VmSockPosixEventQueueDelete_inlock( + VmSockPosixEventQueueDelete_inlock( pRESTHandle->pSockContext->pEventQueue, pSocket ); - - VmRESTFreeMemory(pszBufPrev); - pszBufPrev = NULL; + pSocket->pszBuffer = NULL; pSocket->nProcessed = 0; pSocket->nBufData = 0; + + if (pSocket->pTimerSocket) + { + VmSockPosixReArmTimer( + pRESTHandle, + pSocket->pTimerSocket, + ((pRESTHandle->pRESTConfig->connTimeoutSec) * 1000) + ); + + write(pSocket->pTimerSocket->fd, "NotifyPQ", 8); + pSocket->pTimerSocket->pIoSocket = NULL; + + } + + } + + if (pszBufPrev) + { + VmRESTFreeMemory(pszBufPrev); + pszBufPrev = NULL; } if (nBufLen) @@ -1080,8 +1138,8 @@ VmSockPosixWrite( error: - VMREST_LOG_ERROR(pRESTHandle,"%s", "Socket write failed"); goto cleanup; + } VOID @@ -1092,10 +1150,6 @@ VmSockPosixReleaseSocket( { if (pSocket) { - if (pSocket->pTimerSocket) - { - VmSockPosixFreeSocket(pSocket->pTimerSocket); - } VmSockPosixFreeSocket(pSocket); } } @@ -1118,22 +1172,21 @@ VmSockPosixCloseSocket( } BAIL_ON_VMREST_ERROR(dwError); - VMREST_LOG_INFO(pRESTHandle,"C-REST-ENGINE: Closing socket with fd %d", pSocket->fd); + VMREST_LOG_INFO(pRESTHandle,"C-REST-ENGINE: Closing socket with fd %d, Socket Type %u ( 2-Io / 5-Timer )", pSocket->fd, pSocket->type); dwError = VmRESTLockMutex(pSocket->pMutex); BAIL_ON_VMREST_ERROR(dwError); bLocked = TRUE; - if (pSocket->pTimerSocket && (pSocket->pTimerSocket->fd > 0)) + if (pSocket->pTimerSocket) { - close(pSocket->pTimerSocket->fd); - pSocket->pTimerSocket->fd = -1; + pSocket->pTimerSocket->pIoSocket = NULL; } - if (pRESTHandle->pSSLInfo->isSecure && pSocket->ssl) + if (pRESTHandle->pSSLInfo->isSecure && pSocket->ssl && (pSocket->type != VM_SOCK_TYPE_TIMER)) { - ret = SSL_shutdown(pSocket->ssl); + ret = SSL_shutdown(pSocket->ssl); if (ret < 0) { errorCode = SSL_get_error(pSocket->ssl, ret); @@ -1149,7 +1202,6 @@ VmSockPosixCloseSocket( pSocket->fd = -1; } - cleanup: if (bLocked) @@ -1294,6 +1346,12 @@ VmSockPosixEventQueueDelete_inlock( DWORD dwError = REST_ENGINE_SUCCESS; struct epoll_event event = {0}; + if (!pSocket || !pQueue) + { + dwError = REST_ERROR_INVALID_HANDLER; + } + BAIL_ON_VMREST_ERROR(dwError); + if (epoll_ctl(pQueue->epollFd, EPOLL_CTL_DEL, pSocket->fd, &event) < 0) { dwError = VM_SOCK_POSIX_ERROR_SYS_CALL_FAILED; @@ -1341,6 +1399,7 @@ VmSockPosixAcceptConnection( pSocket->pTimerSocket = NULL; pSocket->pIoSocket = NULL; pSocket->bSSLHandShakeCompleted = FALSE; + pSocket->bInUse = FALSE; *ppSocket = pSocket; @@ -1560,35 +1619,21 @@ VmSockPosixSetRequestHandle( pSocket->nProcessed = nProcessed; - /**** Rearm timer and add sockfd back to poller ****/ - if (!bCompleted) + if (bCompleted) { - dwError = VmSockPosixReArmTimer( - pRESTHandle, - pSocket->pTimerSocket, - ((pRESTHandle->pRESTConfig->connTimeoutSec) * 1000) - ); - BAIL_ON_VMREST_ERROR(dwError); - - event.data.ptr = pSocket; - event.events = EPOLLIN; - - event.events = event.events | EPOLLONESHOT; - - if (epoll_ctl(pQueue->epollFd, EPOLL_CTL_MOD, pSocket->fd, &event) < 0) + /**** We are done with request - no need to add back to poller *****/ + if (pSocket->pTimerSocket != NULL) { - dwError = VM_SOCK_POSIX_ERROR_SYS_CALL_FAILED; + pSocket->pTimerSocket->pIoSocket = NULL; + + /**** Give immediate notification to timer for cleanup ****/ + dwError = VmSockPosixReArmTimer( + pRESTHandle, + pSocket->pTimerSocket, + 1 + ); BAIL_ON_VMREST_ERROR(dwError); } - } - else - { - /**** Delete timerfd from poller ****/ - dwError = VmSockPosixEventQueueDelete_inlock( - pQueue, - pSocket->pTimerSocket - ); - BAIL_ON_VMREST_ERROR(dwError); /**** Delete actual IO socket from poller ****/ dwError = VmSockPosixEventQueueDelete_inlock( @@ -1596,13 +1641,37 @@ VmSockPosixSetRequestHandle( pSocket ); BAIL_ON_VMREST_ERROR(dwError); - - - if (pSocket->pTimerSocket->fd > 0) + } + else + { + /***** Add back IO socket to poller for next IO cycle ****/ + if (pSocket->pTimerSocket == NULL) { - close(pSocket->pTimerSocket->fd); - pSocket->pTimerSocket->fd = -1; - } + /**** 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.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); + } + } + BAIL_ON_VMREST_ERROR(dwError); } cleanup: @@ -1611,6 +1680,10 @@ VmSockPosixSetRequestHandle( { VmRESTUnlockMutex(pSocket->pMutex); } + if (!bCompleted && pSocket && (pSocket->pTimerSocket != NULL)) + { + pSocket->bInUse = FALSE; + } return dwError; @@ -1702,6 +1775,13 @@ VmSockPosixReArmTimer( int nSec = 0; int nNanoSec = 0; + if (!pRESTHandle || !pTimerSocket ) + { + VMREST_LOG_ERROR(pRESTHandle,"%s","Invalid params"); + dwError = ERROR_INVALID_PARAMETER; + } + BAIL_ON_VMREST_ERROR(dwError); + if (milliSec > 0) { nSec = milliSec / 1000; @@ -1733,96 +1813,6 @@ VmSockPosixReArmTimer( } -static -BOOLEAN -VmSockPosixIsSafeToCloseConnOnTimeOut( - PVMREST_HANDLE pRESTHandle, - PVM_SOCKET pTimerSocket - ) -{ - uint32_t dwError = REST_ENGINE_SUCCESS; - struct epoll_event event = {0}; - BOOLEAN bCloseConn = FALSE; - ssize_t nRead = 0; - uint32_t errorCode = 0; - uint64_t res = 0; - char pBuf = '\0'; - struct itimerspec ts = {0}; - PVM_SOCKET pSocket = NULL; - - if (!pRESTHandle || !pTimerSocket) - { - VMREST_LOG_ERROR(pRESTHandle,"%s","Invalid params"); - dwError = ERROR_INVALID_PARAMETER; - } - BAIL_ON_VMREST_ERROR(dwError); - - pSocket = pTimerSocket->pIoSocket; - errno = 0; - - if ((pRESTHandle->pSSLInfo->isSecure) && (pSocket->ssl)) - { - nRead = SSL_read(pSocket->ssl, &pBuf, 0); - errorCode = SSL_get_error(pSocket->ssl, nRead); - } - else if (pSocket->fd > 0) - { - nRead = read(pSocket->fd, &pBuf, 0); - errorCode = errno; - } - VMREST_LOG_DEBUG(pRESTHandle, "IO socket read bytes %d, errorCode %u, at timer expiration", nRead, errorCode); - - if (errorCode == EAGAIN || errorCode == EWOULDBLOCK || errorCode == SSL_ERROR_WANT_READ) - { - /**** Check for preceeding reset of timer due to valid IO ****/ - if (timerfd_gettime(pTimerSocket->fd, &ts) == 0) - { - if ((ts.it_value.tv_sec == 0) && (ts.it_value.tv_nsec == 0)) - { - /**** timer is still disarmed ****/ - /**** It's safe to close connection ****/ - bCloseConn = TRUE; - } - - /**** Do a read on timer socket - dummy read ****/ - do - { - errorCode = 0; - errno = 0; - nRead = 0; - nRead = read(pTimerSocket->fd, &res, sizeof(res)); - errorCode = errno; - res = 0; - }while(nRead > 0); - - if (!bCloseConn) - { - /**** Add timer socket back to poller ****/ - event.data.ptr = pTimerSocket; - event.events = EPOLLIN; - event.events = event.events | EPOLLONESHOT; - - if (epoll_ctl(pRESTHandle->pSockContext->pEventQueue->epollFd, EPOLL_CTL_MOD, pTimerSocket->fd, &event) < 0) - { - dwError = VM_SOCK_POSIX_ERROR_SYS_CALL_FAILED; - BAIL_ON_VMREST_ERROR(dwError); - } - } - } - } - -cleanup: - - return bCloseConn; - -error: - - bCloseConn = FALSE; - - goto cleanup; - -} - static uint32_t VmSockPosixCreateTimer( @@ -1860,6 +1850,7 @@ VmSockPosixCreateTimer( pTimerSocket->type = VM_SOCK_TYPE_TIMER; pTimerSocket->fd = timerFd; + pTimerSocket->bInUse = FALSE; pTimerSocket->pIoSocket = pSocket; pTimerSocket->pRequest = NULL; pTimerSocket->pszBuffer = NULL; @@ -1931,6 +1922,7 @@ VmRESTAcceptSSLContext( if (ret == 1) { + VMREST_LOG_DEBUG(pRESTHandle," SSL accept successful on socket %d, ret %d, errorCode %u", pSocket->fd, ret, errorCode); pSocket->bSSLHandShakeCompleted = TRUE; bReArm = TRUE; } @@ -1940,15 +1932,22 @@ VmRESTAcceptSSLContext( pSocket->bSSLHandShakeCompleted = FALSE; bReArm = TRUE; } + else if ((ret == 0) && (errorCode == SSL_ERROR_SYSCALL)) + { + VMREST_LOG_ERROR(pRESTHandle," Client closed the connection during SSL handshake, socket fd %d, ret %d, errorCode %u, errno %d", pSocket->fd, ret, errorCode, errno); + dwError = VMREST_TRANSPORT_SSL_ACCEPT_FAILED; + BAIL_ON_VMREST_ERROR(dwError); + } else { - VMREST_LOG_ERROR(pRESTHandle, "SSL handshake failed...connection will be closed for socket with fd %d, ret %d, errorCode %u", pSocket->fd, ret, errorCode); + VMREST_LOG_ERROR(pRESTHandle, "SSL handshake failed...connection will be closed for socket with fd %d, ret %d, errorCode %u, errno %d", pSocket->fd, ret, errorCode, errno); dwError = VMREST_TRANSPORT_SSL_ACCEPT_FAILED; BAIL_ON_VMREST_ERROR(dwError); } if (bReArm && bWatched) { + /**** Rearm and add the socket ****/ dwError = VmSockPosixReArmTimer( pRESTHandle, pSocket->pTimerSocket, @@ -1974,13 +1973,23 @@ VmRESTAcceptSSLContext( error: - if (bWatched && pRESTHandle && pRESTHandle->pSockContext) + if (pRESTHandle && pRESTHandle->pSockContext) { /**** Delete from poller ****/ VmSockPosixEventQueueDelete_inlock( pRESTHandle->pSockContext->pEventQueue, pSocket ); + + if (bWatched && pSocket && pSocket->pTimerSocket) + { + pSocket->pTimerSocket->pIoSocket = NULL; + VmSockPosixReArmTimer( + pRESTHandle, + pSocket->pTimerSocket, + 1 + ); + } } goto cleanup; diff --git a/transport/posix/structs.h b/transport/posix/structs.h index ad5563e..369cfcb 100644 --- a/transport/posix/structs.h +++ b/transport/posix/structs.h @@ -20,6 +20,7 @@ typedef struct _VM_SOCKET int fd; SSL* ssl; BOOLEAN bSSLHandShakeCompleted; + BOOLEAN bInUse; char* pszBuffer; uint32_t nBufData; uint32_t nProcessed;