diff -ru c-rest-engine-1.0.3/build/package/rpm/c-rest-engine.spec c-rest-engine-1.0.4/build/package/rpm/c-rest-engine.spec --- c-rest-engine-1.0.3/build/package/rpm/c-rest-engine.spec 2017-07-20 19:57:03.000000000 -0700 +++ c-rest-engine-1.0.4/build/package/rpm/c-rest-engine.spec 2017-08-21 16:40:55.000000000 -0700 @@ -1,7 +1,7 @@ Name: c-rest-engine Summary: Minimal http(s) server library -Version: 1.0.2 -Release: 2%{?dist} +Version: 1.0.3 +Release: 5%{?dist} Group: Applications/System Vendor: VMware, Inc. License: Apache 2.0 @@ -65,11 +65,19 @@ %{_lib64dir}/*.so %changelog +* Thu Aug 17 2017 Kumar Kaushik <kaushikk@vmware.com> 1.0.3-5 +- Adding new and cleaner parsing for all packets. +* Mon Aug 14 2017 Kumar Kaushik <kaushikk@vmware.com> 1.0.3-4 +- Fixing bug # 1938177 +* Fri Aug 11 2017 Kumar Kaushik <kaushikk@vmware.com> 1.0.3-3 +- Fixing all known coverity bugs. +* Fri Aug 04 2017 Kumar Kaushik <kaushikk@vmware.com> 1.0.3-2 +- Applying security fixes for set SSL info. * Thu Jul 20 2017 Kumar Kaushik <kaushikk@vmware.com> 1.0.2-2 - Providing API for set SSL info, Bug#1864924 * Mon Jun 19 2017 Kumar Kaushik <kaushikk@vmware.com> 1.0.2-1 - Updating to version 1.0.2 -* Thu Jun 16 2017 Kumar Kaushik <kaushikk@vmware.com> 1.0.1-4 +* Fri Jun 16 2017 Kumar Kaushik <kaushikk@vmware.com> 1.0.1-4 - Relaxing maximum URI length. * Thu Jun 08 2017 Kumar Kaushik <kaushikk@vmware.com> 1.0.1-3 - Fixing file upload. diff -ru c-rest-engine-1.0.3/common/logging.c c-rest-engine-1.0.4/common/logging.c --- c-rest-engine-1.0.3/common/logging.c 2017-07-20 19:57:03.000000000 -0700 +++ c-rest-engine-1.0.4/common/logging.c 2017-08-21 16:40:55.000000000 -0700 @@ -56,8 +56,8 @@ if (pRESTHandle && pRESTHandle->logFile != NULL) { fclose(pRESTHandle->logFile); + pRESTHandle->logFile = NULL; } - pRESTHandle->logFile = NULL; } void diff -ru c-rest-engine-1.0.3/common/sockinterface.c c-rest-engine-1.0.4/common/sockinterface.c --- c-rest-engine-1.0.3/common/sockinterface.c 2017-07-20 19:57:03.000000000 -0700 +++ c-rest-engine-1.0.4/common/sockinterface.c 2017-08-21 16:40:55.000000000 -0700 @@ -1,908 +1,919 @@ -/* C-REST-Engine -* -* Copyright (c) 2017 VMware, Inc. All Rights Reserved. -* -* This product is licensed to you under the Apache 2.0 license (the "License"). -* You may not use this product except in compliance with the Apache 2.0 License. -* -* This product may include a number of subcomponents with separate copyright -* notices and license terms. Your use of these subcomponents is subject to the -* terms and conditions of the subcomponent's license, as noted in the LICENSE file. -* -*/ - -#include "includes.h" - -static -VOID -VmRESTSockContextFree( - PVMREST_HANDLE pRESTHandle, - PVMREST_SOCK_CONTEXT pSockInterface - ); - -static -DWORD -VmRESTHandleSocketEvent( - PVMREST_HANDLE pRESTHandle, - PVM_SOCKET pSocket, - VM_SOCK_EVENT_TYPE sockEvent, - PVM_SOCK_IO_BUFFER pIoBuffer, - DWORD dwError - ); - -static -DWORD -VmRESTOnNewConnection( - PVMREST_HANDLE pRESTHandle, - PVM_SOCKET pSocket, - PVM_SOCK_IO_BUFFER pIoBuffer - ); - -static -VOID -VmRESTOnDisconnect( - PVMREST_HANDLE pRESTHandle, - PVM_SOCKET pSocket, - PVM_SOCK_IO_BUFFER pIoBuffer - ); - -static -DWORD -VmRESTOnDataAvailable( - PVMREST_HANDLE pRESTHandle, - PVM_SOCKET pSocket, - PVM_SOCK_IO_BUFFER pIoBuffer - ); - -static -PVOID -VmRESTSockWorkerThreadProc( - PVOID pData - ); - -static -DWORD -VmRESTTcpReceiveNewData( - PVMREST_HANDLE pRESTHandle, - PVM_SOCKET pSocket - ); - -static -DWORD -VmRESTReceiveData( - PVMREST_HANDLE pRESTHandle, - PVM_SOCKET pSocket, - PVM_SOCK_IO_BUFFER pIoBuffer - ); - -static -DWORD -VmRESTTcpReceiveData( - PVMREST_HANDLE pRESTHandle, - PVM_SOCKET pSocket, - PVM_SOCK_IO_BUFFER pIoBuffer - ); - -static -DWORD -VmRESTDisconnectClient( - PVMREST_HANDLE pRESTHandle, - PVM_SOCKET pSocket - ); - -static -PVOID -VmRESTSockWorkerThreadProc( - PVOID pData - ); - -DWORD -VmRESTInitProtocolServer( - PVMREST_HANDLE pRESTHandle - ) -{ - DWORD dwError = REST_ENGINE_SUCCESS; - PVMREST_SOCK_CONTEXT pSockContext = NULL; - DWORD dwFlags = VM_SOCK_CREATE_FLAGS_REUSE_ADDR | - VM_SOCK_CREATE_FLAGS_NON_BLOCK; - DWORD iThr = 0; - char lastPortChar = '\0'; - char* sslCert = NULL; - char* sslKey = NULL; - char* temp = NULL; - PVM_WORKER_THREAD_DATA pThreadData = NULL; - - if (! pRESTHandle || !( pRESTHandle->pRESTConfig)) - { - VMREST_LOG_ERROR(pRESTHandle,"%s","Invalid REST config"); - dwError = REST_ERROR_INVALID_HANDLER; - } - BAIL_ON_VMREST_ERROR(dwError); - - pSockContext = pRESTHandle->pSockContext; - - dwError = VmRESTAllocateMutex(&pSockContext->pMutex); - BAIL_ON_VMREST_ERROR(dwError); - - /**** Init SSL if configured ****/ - if (( pRESTHandle->pRESTConfig->server_port != NULL) && (strlen( pRESTHandle->pRESTConfig->server_port) == 0)) - { - VMREST_LOG_ERROR(pRESTHandle,"%s","REST Engine config server port missing"); - dwError = 111; /** Fix this **/ - } - BAIL_ON_VMREST_ERROR(dwError); - - lastPortChar = VmRESTUtilsGetLastChar( - pRESTHandle->pRESTConfig->server_port - ); - - if (lastPortChar == 'p' || lastPortChar == 'P') - { - VMREST_LOG_DEBUG(pRESTHandle,"%s","Server initing in plain text wire connection mode"); - temp = pRESTHandle->pRESTConfig->server_port; - while(temp != NULL) - { - if (*temp == 'p' || *temp == 'P') - { - *temp = '\0'; - break; - } - temp++; - } - } - else - { - VMREST_LOG_DEBUG(pRESTHandle,"%s","Server initing in encrypted wire connection mode"); - if (strlen( pRESTHandle->pRESTConfig->ssl_certificate) == 0 || strlen( pRESTHandle->pRESTConfig->ssl_key) == 0) - { - VMREST_LOG_ERROR(pRESTHandle,"%s", "Invalid SSL params"); - dwError = 112; /** Fix this **/ - } - BAIL_ON_VMREST_ERROR(dwError); - dwFlags = dwFlags | VM_SOCK_IS_SSL; - sslCert = pRESTHandle->pRESTConfig->ssl_certificate; - sslKey = pRESTHandle->pRESTConfig->ssl_key; - } - - /**** Handle IPv4 case ****/ - - dwError = VmwSockOpenServer( - pRESTHandle, - ((unsigned short)atoi( pRESTHandle->pRESTConfig->server_port)), - ((int)atoi( pRESTHandle->pRESTConfig->worker_thread_count)), - dwFlags | VM_SOCK_CREATE_FLAGS_TCP | - VM_SOCK_CREATE_FLAGS_IPV4, - &pSockContext->pListenerTCP, - sslCert, - sslKey - ); - BAIL_ON_VMREST_ERROR(dwError); - -#ifdef AF_INET6 - /**** Handle IPv6 case ****/ - - dwError = VmwSockOpenServer( - pRESTHandle, - ((unsigned short)atoi( pRESTHandle->pRESTConfig->server_port)), - ((int)atoi( pRESTHandle->pRESTConfig->worker_thread_count)), - dwFlags | VM_SOCK_CREATE_FLAGS_TCP | - VM_SOCK_CREATE_FLAGS_IPV6, - &pSockContext->pListenerTCP6, - sslCert, - sslKey - ); - BAIL_ON_VMREST_ERROR(dwError); -#endif - - dwError = VmwSockCreateEventQueue( - pRESTHandle, - -1, - &pSockContext->pEventQueue - ); - BAIL_ON_VMREST_ERROR(dwError); - - dwError = VmwSockEventQueueAdd( - pRESTHandle, - pSockContext->pEventQueue, - pSockContext->pListenerTCP - ); - BAIL_ON_VMREST_ERROR(dwError); - -#ifdef AF_INET6 - dwError = VmwSockEventQueueAdd( - pRESTHandle, - pSockContext->pEventQueue, - pSockContext->pListenerTCP6 - ); - BAIL_ON_VMREST_ERROR(dwError); -#endif - - dwError = VmRESTAllocateMemory( - sizeof(PVMREST_THREAD) * (((int)atoi( pRESTHandle->pRESTConfig->worker_thread_count))) , - (PVOID*)&pSockContext->pWorkerThreads - ); - BAIL_ON_VMREST_ERROR(dwError); - - pSockContext->dwNumThreads = ((int)atoi( pRESTHandle->pRESTConfig->worker_thread_count)); - - for (; iThr < pSockContext->dwNumThreads; iThr++) - { - dwError = VmRESTAllocateMemory( - sizeof(VM_WORKER_THREAD_DATA) , - (PVOID*)&pThreadData - ); - BAIL_ON_VMREST_ERROR(dwError); - pThreadData->pSockContext = pSockContext; - pThreadData-> pRESTHandle = pRESTHandle; - - dwError = VmRESTAllocateMemory( - sizeof(VMREST_THREAD), - (void **)&pSockContext->pWorkerThreads[iThr] - ); - BAIL_ON_VMREST_ERROR(dwError); - - dwError = VmRESTCreateThread( - pSockContext->pWorkerThreads[iThr], - TRUE, - (PVMREST_START_ROUTINE)&VmRESTSockWorkerThreadProc, - pThreadData - ); - BAIL_ON_VMREST_ERROR(dwError); - - pThreadData = NULL; - } - - pRESTHandle->pSockContext = pSockContext; - -cleanup: - - return dwError; - -error: - - goto cleanup; -} - -VOID -VmRESTShutdownProtocolServer( - PVMREST_HANDLE pRESTHandle - ) -{ - if (pRESTHandle && pRESTHandle->pSockContext) - { - VmRESTSockContextFree( pRESTHandle, pRESTHandle->pSockContext); - } -} - -static -PVOID -VmRESTSockWorkerThreadProc( - PVOID pData - ) -{ - DWORD dwError = 0; - PVM_WORKER_THREAD_DATA pWorkerData = (PVM_WORKER_THREAD_DATA)pData; - PVMREST_HANDLE pRESTHandle = pWorkerData-> pRESTHandle; - PVMREST_SOCK_CONTEXT pSockContext = pWorkerData->pSockContext; - PVM_SOCKET pSocket = NULL; - PVM_SOCK_IO_BUFFER pIoBuffer = NULL; - - if (pWorkerData != NULL) - { - VmRESTFreeMemory(pWorkerData); - pWorkerData = NULL; - } - - for(;;) - { - VM_SOCK_EVENT_TYPE eventType = VM_SOCK_EVENT_TYPE_UNKNOWN; - - dwError = VmwSockWaitForEvent( - pRESTHandle, - pSockContext->pEventQueue, - -1, - &pSocket, - &eventType, - &pIoBuffer); - - if (dwError == ERROR_SHUTDOWN_IN_PROGRESS) - { - break; - } - dwError = VmRESTHandleSocketEvent( - pRESTHandle, - pSocket, - eventType, - pIoBuffer, - dwError); - - if (dwError == ERROR_SUCCESS || - dwError == ERROR_IO_PENDING) - { - dwError = ERROR_SUCCESS; - } - else - { - pSocket = NULL; - pIoBuffer = NULL; - dwError = 0; - } - BAIL_ON_VMREST_ERROR(dwError); - - } -error: -#ifndef WIN32 - if (pSocket) - { - VmwSockRelease( pRESTHandle, pSocket); - } -#endif - - return NULL; -} - - - -static -DWORD -VmRESTHandleSocketEvent( - PVMREST_HANDLE pRESTHandle, - PVM_SOCKET pSocket, - VM_SOCK_EVENT_TYPE sockEvent, - PVM_SOCK_IO_BUFFER pIoBuffer, - DWORD dwError - ) -{ - if (dwError == ERROR_SUCCESS) - { - switch (sockEvent) - { - case VM_SOCK_EVENT_TYPE_TCP_NEW_CONNECTION: - - dwError = VmRESTOnNewConnection( pRESTHandle, pSocket, pIoBuffer); - BAIL_ON_VMREST_ERROR(dwError); - break; -#ifndef WIN32 - case VM_SOCK_EVENT_TYPE_DATA_AVAILABLE: - dwError = VmRESTOnDataAvailable( pRESTHandle,pSocket, pIoBuffer); - BAIL_ON_VMREST_ERROR(dwError); - break; - - case VM_SOCK_EVENT_TYPE_CONNECTION_CLOSED: - VmRESTOnDisconnect( pRESTHandle, pSocket, pIoBuffer); - break; - - case VM_SOCK_EVENT_TYPE_UNKNOWN: - dwError = ERROR_INVALID_STATE; - break; - - default: - dwError = ERROR_INVALID_MESSAGE; - break; -#endif - } - } - -cleanup: - - return dwError; - -error : - goto cleanup; -} - -static -DWORD -VmRESTOnNewConnection( - PVMREST_HANDLE pRESTHandle, - PVM_SOCKET pSocket, - PVM_SOCK_IO_BUFFER pIoBuffer - ) -{ - DWORD dwError = REST_ENGINE_SUCCESS; - if (!pSocket) - { - dwError = ERROR_INVALID_PARAMETER; - BAIL_ON_VMREST_ERROR(dwError); - } - -#ifdef WIN32 - dwError = VmRESTTcpReceiveNewData( pRESTHandle, pSocket); - BAIL_ON_VMREST_ERROR(dwError); -#endif -cleanup: - - return dwError; - -error: - - goto cleanup; -} - -static -VOID -VmRESTOnDisconnect( - PVMREST_HANDLE pRESTHandle, - PVM_SOCKET pSocket, - PVM_SOCK_IO_BUFFER pIoBuffer - ) -{ - if (pSocket) - { - VmwSockClose( pRESTHandle, pSocket); - } - - if (pIoBuffer) - { - VmwSockReleaseIoBuffer( pRESTHandle, pIoBuffer); - } -} - -static -DWORD -VmRESTOnDataAvailable( - PVMREST_HANDLE pRESTHandle, - PVM_SOCKET pSocket, - PVM_SOCK_IO_BUFFER pIoBuffer - ) -{ - DWORD dwError = REST_ENGINE_SUCCESS; - - if (!pSocket) - { - dwError = ERROR_INVALID_PARAMETER; - BAIL_ON_VMREST_ERROR(dwError); - } - - dwError = VmRESTReceiveData( pRESTHandle,pSocket, pIoBuffer); - BAIL_ON_VMREST_ERROR(dwError); - -cleanup: - if (pIoBuffer) - { - VmwSockReleaseIoBuffer( pRESTHandle, pIoBuffer); - } - - return dwError; - -error: - - goto cleanup; -} - -static -DWORD -VmRESTReceiveData( - PVMREST_HANDLE pRESTHandle, - PVM_SOCKET pSocket, - PVM_SOCK_IO_BUFFER pIoBuffer - ) -{ - DWORD dwError = REST_ENGINE_SUCCESS; - - if (!pSocket) - { - dwError = ERROR_INVALID_PARAMETER; - BAIL_ON_VMREST_ERROR(dwError); - } - - dwError = VmRESTTcpReceiveData( pRESTHandle,pSocket, pIoBuffer); - BAIL_ON_VMREST_ERROR(dwError); - -cleanup: - if (pIoBuffer) - { - VmwSockReleaseIoBuffer( pRESTHandle, pIoBuffer); - } - - return dwError; - -error: - - goto cleanup; - -} - -static -DWORD -VmRESTTcpReceiveData( - PVMREST_HANDLE pRESTHandle, - PVM_SOCKET pSocket, - PVM_SOCK_IO_BUFFER pIoBuffer - ) -{ - DWORD dwError = REST_ENGINE_SUCCESS; - - if (!pSocket) - { - dwError = ERROR_INVALID_PARAMETER; - BAIL_ON_VMREST_ERROR(dwError); - } - - if (!pIoBuffer) - { - dwError = VmRESTTcpReceiveNewData( pRESTHandle,pSocket); - BAIL_ON_VMREST_ERROR(dwError); - } - -cleanup: - if (pIoBuffer) - { - VmwSockReleaseIoBuffer( pRESTHandle, pIoBuffer); - } - - return dwError; - -error: - - goto cleanup; -} - -static -DWORD -VmRESTTcpReceiveNewData( - PVMREST_HANDLE pRESTHandle, - PVM_SOCKET pSocket - ) -{ - DWORD dwError = REST_ENGINE_SUCCESS; - char appBuffer[MAX_DATA_BUFFER_LEN] = {0}; - uint32_t bytesRead = 0; - - dwError = VmsockPosixGetXBytes( - pRESTHandle, - MAX_DATA_BUFFER_LEN, - appBuffer, - pSocket, - &bytesRead, - 0 - ); - BAIL_ON_VMREST_ERROR(dwError); - - - if (bytesRead > 0) - { - VMREST_LOG_DEBUG(pRESTHandle,"%s","Starting HTTP Parsing."); - dwError = VmRESTProcessIncomingData( - pRESTHandle, - appBuffer, - bytesRead, - pSocket - ); - BAIL_ON_VMREST_ERROR(dwError); - } - - -cleanup: - VMREST_LOG_DEBUG(pRESTHandle,"%s","Calling closed connection...."); - VmRESTDisconnectClient( pRESTHandle, pSocket); - - return dwError; - -error: - - goto cleanup; -} - -static -VOID -VmRESTSockContextFree( - PVMREST_HANDLE pRESTHandle, - PVMREST_SOCK_CONTEXT pSockContext - ) -{ - if (pSockContext->pEventQueue) - { - VmwSockCloseEventQueue( pRESTHandle, pSockContext->pEventQueue); - } - if (pSockContext->pListenerTCP) - { - VmwSockRelease( pRESTHandle, pSockContext->pListenerTCP); - } - if (pSockContext->pListenerTCP6) - { - VmwSockRelease( pRESTHandle, pSockContext->pListenerTCP6); - } - if (pSockContext->pWorkerThreads) - { - DWORD iThr = 0; - - for (; iThr < pSockContext->dwNumThreads; iThr++) - { - PVMREST_THREAD pThread = pSockContext->pWorkerThreads[iThr]; - - if (pThread) - { - VmRESTFreeThread(pThread); - } - } - - VmRESTFreeMemory(pSockContext->pWorkerThreads); - } - if (pSockContext->pMutex) - { - VmRESTFreeMutex(pSockContext->pMutex); - } -} - -static -DWORD -VmRESTDisconnectClient( - PVMREST_HANDLE pRESTHandle, - PVM_SOCKET pSocket - ) -{ - DWORD dwError = REST_ENGINE_SUCCESS; - - if (!pSocket) - { - dwError = ERROR_INVALID_PARAMETER; - BAIL_ON_VMREST_ERROR(dwError); - } - - VmwSockClose( pRESTHandle, pSocket); - VmwSockRelease( pRESTHandle, pSocket); - -cleanup: - - return dwError; - -error: - - goto cleanup; -} - -uint32_t -VmsockPosixGetXBytes( - PVMREST_HANDLE pRESTHandle, - uint32_t bytesRequested, - char* appBuffer, - PVM_SOCKET pSocket, - uint32_t* bytesRead, - uint8_t shouldBlock - ) -{ - uint32_t dwError = REST_ENGINE_SUCCESS; - uint32_t dataIndex = 0; - uint32_t remainingBytes = 0; - uint32_t dataAvailableInCache = 0; - PVM_SOCK_IO_BUFFER pIoBuffer = NULL; - PVM_STREAM_BUFFER pStreamBuffer = NULL; - - if (bytesRequested > MAX_DATA_BUFFER_LEN || appBuffer == NULL || bytesRead == NULL) - { - VMREST_LOG_DEBUG(pRESTHandle,"%s","Bytes to be read %u Large or appBuffer: %s", - bytesRequested, appBuffer); - dwError = VMREST_TRANSPORT_INVALID_PARAM; - } - BAIL_ON_VMREST_ERROR(dwError); - - if (sizeof(appBuffer) > MAX_DATA_BUFFER_LEN) - { - VMREST_LOG_DEBUG(pRESTHandle,"%s","ERROR: Application buffer size too large"); - dwError = VMREST_TRANSPORT_INVALID_PARAM; - } - BAIL_ON_VMREST_ERROR(dwError); - - VmwSockGetStreamBuffer( pRESTHandle, pSocket, &pStreamBuffer); - - if (!pStreamBuffer) - { - dwError = 500; - } - BAIL_ON_VMREST_ERROR(dwError); - - dataIndex = pStreamBuffer->dataProcessed; - - dataAvailableInCache = pStreamBuffer->dataRead - pStreamBuffer->dataProcessed; - - if (dataAvailableInCache >= bytesRequested) - { - /**** Enough data available in stream cache buffer ****/ - memcpy(appBuffer, - &(pStreamBuffer->pData[dataIndex]), - bytesRequested - ); - pStreamBuffer->dataProcessed += bytesRequested; - *bytesRead = bytesRequested; - } - else if(dataAvailableInCache < bytesRequested) - { - /**** Copy all remaining client Stream bytes and perform read ****/ - if (dataAvailableInCache > 0) - { - memcpy(appBuffer, - &(pStreamBuffer->pData[dataIndex]), - dataAvailableInCache - ); - pStreamBuffer->dataProcessed += dataAvailableInCache; - /**** This will be overwritten in case of success ****/ - *bytesRead = dataAvailableInCache; - } - - dwError = VmwSockAllocateIoBuffer( - pRESTHandle, - VM_SOCK_EVENT_TYPE_TCP_REQUEST_DATA_READ, - MAX_DATA_BUFFER_LEN, - &pIoBuffer - ); - BAIL_ON_VMREST_ERROR(dwError); - dwError = VmwSockRead( - pRESTHandle, - pSocket, - pIoBuffer); - //VMREST_LOG_DEBUG(pRESTHandle,"SockRead(), dwError = %u, dataRead %u", dwError, pIoBuffer->dwBytesTransferred); - if (dwError == ERROR_SUCCESS) - { - memset(pStreamBuffer->pData, '\0', MAX_DATA_BUFFER_LEN); - memcpy(pStreamBuffer->pData, pIoBuffer->pData,pIoBuffer->dwBytesTransferred); - pStreamBuffer->dataProcessed = 0; - pStreamBuffer->dataRead = pIoBuffer->dwBytesTransferred; - BAIL_ON_VMREST_ERROR(dwError); - } - else if (dwError == ERROR_IO_PENDING) - { - // fail for linux? -#ifndef WIN32 - pIoBuffer = NULL; -#endif - } - else - { - BAIL_ON_VMREST_ERROR(dwError); - } - - remainingBytes = bytesRequested - dataAvailableInCache; - dataIndex = 0; - - if (remainingBytes > pStreamBuffer->dataRead) - { - remainingBytes = pStreamBuffer->dataRead; - VMREST_LOG_DEBUG(pRESTHandle,"WARNING: Requested %u bytes, available only %u bytes", bytesRequested,(dataAvailableInCache + remainingBytes)); - } - - memcpy((appBuffer + dataAvailableInCache), - &(pStreamBuffer->pData[dataIndex]), - remainingBytes); - pStreamBuffer->dataProcessed = remainingBytes; - *bytesRead = dataAvailableInCache + remainingBytes; - - //VMREST_LOG_DEBUG(pRESTHandle,"dataAvailableInCache %u, remainingBytes %u, appBuffersize %u", dataAvailableInCache, remainingBytes, strlen(appBuffer)); - } - - VmwSockSetStreamBuffer( pRESTHandle, pSocket, pStreamBuffer); - -cleanup: - if (pIoBuffer) - { - VmwSockReleaseIoBuffer( pRESTHandle, pIoBuffer); - } - - return dwError; - -error: - - goto cleanup; - -} - -uint32_t -VmSockPosixAdjustProcessedBytes( - PVMREST_HANDLE pRESTHandle, - PVM_SOCKET pSocket, - uint32_t dataSeen -) -{ - uint32_t dwError = REST_ENGINE_SUCCESS; - PVM_STREAM_BUFFER pStreamBuffer = NULL; - - if (dataSeen > MAX_DATA_BUFFER_LEN) - { - VMREST_LOG_DEBUG(pRESTHandle,"%s","Invalid new Processed Data Index %u", dataSeen); - dwError = VMREST_TRANSPORT_INVALID_PARAM; - } - BAIL_ON_VMREST_ERROR(dwError); - - VmwSockGetStreamBuffer( pRESTHandle, pSocket, &pStreamBuffer); - - if (!pStreamBuffer) - { - dwError = 500; - } - BAIL_ON_VMREST_ERROR(dwError); - - pStreamBuffer->dataProcessed = dataSeen; - - VmwSockSetStreamBuffer( pRESTHandle, pSocket, pStreamBuffer); - -cleanup: - return dwError; -error: - goto cleanup; -} - -uint32_t -VmSockPosixDecrementProcessedBytes( - PVMREST_HANDLE pRESTHandle, - PVM_SOCKET pSocket, - uint32_t offset -) -{ - uint32_t dwError = REST_ENGINE_SUCCESS; - PVM_STREAM_BUFFER pStreamBuffer = NULL; - - if (offset > MAX_DATA_BUFFER_LEN) - { - VMREST_LOG_DEBUG(pRESTHandle,"%s","Invalid new Processed Data Index %u", offset); - dwError = VMREST_TRANSPORT_INVALID_PARAM; - } - BAIL_ON_VMREST_ERROR(dwError); - - VmwSockGetStreamBuffer( pRESTHandle, pSocket, &pStreamBuffer); - - if (!pStreamBuffer) - { - dwError = 500; - } - BAIL_ON_VMREST_ERROR(dwError); - - if (pStreamBuffer->dataProcessed >= offset) - { - pStreamBuffer->dataProcessed = pStreamBuffer->dataProcessed - offset; - } - VmwSockSetStreamBuffer( pRESTHandle, pSocket, pStreamBuffer); - -cleanup: - return dwError; -error: - goto cleanup; -} - - -uint32_t -VmsockPosixWriteDataAtOnce( - PVMREST_HANDLE pRESTHandle, - PVM_SOCKET pSocket, - char* buffer, - uint32_t bytes - ) -{ - uint32_t dwError = REST_ENGINE_SUCCESS; - PVM_SOCK_IO_BUFFER pIoNewBuffer = NULL; - - dwError = VmwSockAllocateIoBuffer( - pRESTHandle, - VM_SOCK_EVENT_TYPE_TCP_RESPONSE_DATA_WRITE, - bytes, - &pIoNewBuffer); - BAIL_ON_VMREST_ERROR(dwError); - - memcpy(pIoNewBuffer->pData, buffer, bytes); - - dwError = VmwSockWrite( - pRESTHandle, - pSocket, - NULL, - 0, - pIoNewBuffer - ); - if (dwError == ERROR_SUCCESS) - { - dwError = REST_ENGINE_SUCCESS; - BAIL_ON_VMREST_ERROR(dwError); - } - else if (dwError == ERROR_IO_PENDING) - { - pIoNewBuffer = NULL; - BAIL_ON_VMREST_ERROR(dwError); - } - -cleanup: - if (pIoNewBuffer) - { - VmwSockReleaseIoBuffer( pRESTHandle, pIoNewBuffer); - } - return dwError; -error: - goto cleanup; -} +/* C-REST-Engine +* +* Copyright (c) 2017 VMware, Inc. All Rights Reserved. +* +* This product is licensed to you under the Apache 2.0 license (the "License"). +* You may not use this product except in compliance with the Apache 2.0 License. +* +* This product may include a number of subcomponents with separate copyright +* notices and license terms. Your use of these subcomponents is subject to the +* terms and conditions of the subcomponent's license, as noted in the LICENSE file. +* +*/ + +#include "includes.h" + +static +VOID +VmRESTSockContextFree( + PVMREST_HANDLE pRESTHandle, + PVMREST_SOCK_CONTEXT pSockInterface + ); + +static +DWORD +VmRESTHandleSocketEvent( + PVMREST_HANDLE pRESTHandle, + PVM_SOCKET pSocket, + VM_SOCK_EVENT_TYPE sockEvent, + PVM_SOCK_IO_BUFFER pIoBuffer, + DWORD dwError + ); + +static +DWORD +VmRESTOnNewConnection( + PVMREST_HANDLE pRESTHandle, + PVM_SOCKET pSocket, + PVM_SOCK_IO_BUFFER pIoBuffer + ); + +static +VOID +VmRESTOnDisconnect( + PVMREST_HANDLE pRESTHandle, + PVM_SOCKET pSocket, + PVM_SOCK_IO_BUFFER pIoBuffer + ); + +static +DWORD +VmRESTOnDataAvailable( + PVMREST_HANDLE pRESTHandle, + PVM_SOCKET pSocket, + PVM_SOCK_IO_BUFFER pIoBuffer + ); + +static +PVOID +VmRESTSockWorkerThreadProc( + PVOID pData + ); + +static +DWORD +VmRESTTcpReceiveNewData( + PVMREST_HANDLE pRESTHandle, + PVM_SOCKET pSocket + ); + +static +DWORD +VmRESTReceiveData( + PVMREST_HANDLE pRESTHandle, + PVM_SOCKET pSocket, + PVM_SOCK_IO_BUFFER pIoBuffer + ); + +static +DWORD +VmRESTTcpReceiveData( + PVMREST_HANDLE pRESTHandle, + PVM_SOCKET pSocket, + PVM_SOCK_IO_BUFFER pIoBuffer + ); + +static +DWORD +VmRESTDisconnectClient( + PVMREST_HANDLE pRESTHandle, + PVM_SOCKET pSocket + ); + +static +PVOID +VmRESTSockWorkerThreadProc( + PVOID pData + ); + +DWORD +VmRESTInitProtocolServer( + PVMREST_HANDLE pRESTHandle + ) +{ + DWORD dwError = REST_ENGINE_SUCCESS; + PVMREST_SOCK_CONTEXT pSockContext = NULL; + DWORD dwFlags = VM_SOCK_CREATE_FLAGS_REUSE_ADDR | + VM_SOCK_CREATE_FLAGS_NON_BLOCK; + DWORD iThr = 0; + char lastPortChar = '\0'; + char* sslCert = NULL; + char* sslKey = NULL; + char* temp = NULL; + PVM_WORKER_THREAD_DATA pThreadData = NULL; + + if (! pRESTHandle || !( pRESTHandle->pRESTConfig)) + { + VMREST_LOG_ERROR(pRESTHandle,"%s","Invalid REST config"); + dwError = REST_ERROR_INVALID_HANDLER; + } + BAIL_ON_VMREST_ERROR(dwError); + + pSockContext = pRESTHandle->pSockContext; + + dwError = VmRESTAllocateMutex(&pSockContext->pMutex); + BAIL_ON_VMREST_ERROR(dwError); + + /**** Init SSL if configured ****/ + if (strlen( pRESTHandle->pRESTConfig->server_port) == 0) + { + VMREST_LOG_ERROR(pRESTHandle,"%s","REST Engine config server port missing"); + dwError = REST_ERROR_INVALID_CONFIG_PORT; + } + BAIL_ON_VMREST_ERROR(dwError); + + lastPortChar = VmRESTUtilsGetLastChar( + pRESTHandle->pRESTConfig->server_port + ); + + if (lastPortChar == 'p' || lastPortChar == 'P') + { + VMREST_LOG_DEBUG(pRESTHandle,"%s","Server initing in plain text wire connection mode"); + temp = pRESTHandle->pRESTConfig->server_port; + while(temp != NULL) + { + if (*temp == 'p' || *temp == 'P') + { + *temp = '\0'; + break; + } + temp++; + } + } + else + { + VMREST_LOG_DEBUG(pRESTHandle,"%s","Server initing in encrypted wire connection mode"); + if (strlen( pRESTHandle->pRESTConfig->ssl_certificate) == 0 || strlen( pRESTHandle->pRESTConfig->ssl_key) == 0) + { + VMREST_LOG_ERROR(pRESTHandle,"%s", "Invalid SSL params"); + dwError = REST_ERROR_INVALID_CONFIG; + } + BAIL_ON_VMREST_ERROR(dwError); + dwFlags = dwFlags | VM_SOCK_IS_SSL; + sslCert = pRESTHandle->pRESTConfig->ssl_certificate; + sslKey = pRESTHandle->pRESTConfig->ssl_key; + } + + /**** Handle IPv4 case ****/ + + dwError = VmwSockOpenServer( + pRESTHandle, + ((unsigned short)atoi( pRESTHandle->pRESTConfig->server_port)), + ((int)atoi( pRESTHandle->pRESTConfig->worker_thread_count)), + dwFlags | VM_SOCK_CREATE_FLAGS_TCP | + VM_SOCK_CREATE_FLAGS_IPV4, + &pSockContext->pListenerTCP, + sslCert, + sslKey + ); + BAIL_ON_VMREST_ERROR(dwError); + +#ifdef AF_INET6 + /**** Handle IPv6 case ****/ + + dwError = VmwSockOpenServer( + pRESTHandle, + ((unsigned short)atoi( pRESTHandle->pRESTConfig->server_port)), + ((int)atoi( pRESTHandle->pRESTConfig->worker_thread_count)), + dwFlags | VM_SOCK_CREATE_FLAGS_TCP | + VM_SOCK_CREATE_FLAGS_IPV6, + &pSockContext->pListenerTCP6, + sslCert, + sslKey + ); + BAIL_ON_VMREST_ERROR(dwError); +#endif + + dwError = VmwSockCreateEventQueue( + pRESTHandle, + -1, + &pSockContext->pEventQueue + ); + BAIL_ON_VMREST_ERROR(dwError); + + dwError = VmwSockEventQueueAdd( + pRESTHandle, + pSockContext->pEventQueue, + pSockContext->pListenerTCP + ); + BAIL_ON_VMREST_ERROR(dwError); + +#ifdef AF_INET6 + dwError = VmwSockEventQueueAdd( + pRESTHandle, + pSockContext->pEventQueue, + pSockContext->pListenerTCP6 + ); + BAIL_ON_VMREST_ERROR(dwError); +#endif + + dwError = VmRESTAllocateMemory( + sizeof(PVMREST_THREAD) * (((int)atoi( pRESTHandle->pRESTConfig->worker_thread_count))) , + (PVOID*)&pSockContext->pWorkerThreads + ); + BAIL_ON_VMREST_ERROR(dwError); + + pSockContext->dwNumThreads = ((int)atoi( pRESTHandle->pRESTConfig->worker_thread_count)); + + for (; iThr < pSockContext->dwNumThreads; iThr++) + { + dwError = VmRESTAllocateMemory( + sizeof(VM_WORKER_THREAD_DATA) , + (PVOID*)&pThreadData + ); + BAIL_ON_VMREST_ERROR(dwError); + pThreadData->pSockContext = pSockContext; + pThreadData-> pRESTHandle = pRESTHandle; + + dwError = VmRESTAllocateMemory( + sizeof(VMREST_THREAD), + (void **)&pSockContext->pWorkerThreads[iThr] + ); + BAIL_ON_VMREST_ERROR(dwError); + + dwError = VmRESTCreateThread( + pSockContext->pWorkerThreads[iThr], + TRUE, + (PVMREST_START_ROUTINE)&VmRESTSockWorkerThreadProc, + pThreadData + ); + BAIL_ON_VMREST_ERROR(dwError); + + pThreadData = NULL; + } + + pRESTHandle->pSockContext = pSockContext; + +cleanup: + + return dwError; + +error: + if (pThreadData != NULL) + { + VmRESTFreeMemory(pThreadData); + pThreadData = NULL; + } + + goto cleanup; +} + +VOID +VmRESTShutdownProtocolServer( + PVMREST_HANDLE pRESTHandle + ) +{ + if (pRESTHandle && pRESTHandle->pSockContext) + { + VmRESTSockContextFree( pRESTHandle, pRESTHandle->pSockContext); + } +} + +static +PVOID +VmRESTSockWorkerThreadProc( + PVOID pData + ) +{ + DWORD dwError = 0; + PVM_WORKER_THREAD_DATA pWorkerData = (PVM_WORKER_THREAD_DATA)pData; + PVMREST_HANDLE pRESTHandle = NULL; + PVMREST_SOCK_CONTEXT pSockContext = NULL; + PVM_SOCKET pSocket = NULL; + PVM_SOCK_IO_BUFFER pIoBuffer = NULL; + + if (pWorkerData != NULL) + { + pRESTHandle = pWorkerData-> pRESTHandle; + pSockContext = pWorkerData->pSockContext; + VmRESTFreeMemory(pWorkerData); + pWorkerData = NULL; + } + else + { + return NULL; + } + + for(;;) + { + VM_SOCK_EVENT_TYPE eventType = VM_SOCK_EVENT_TYPE_UNKNOWN; + + dwError = VmwSockWaitForEvent( + pRESTHandle, + pSockContext->pEventQueue, + -1, + &pSocket, + &eventType, + &pIoBuffer); + + if (dwError == ERROR_SHUTDOWN_IN_PROGRESS) + { + break; + } + dwError = VmRESTHandleSocketEvent( + pRESTHandle, + pSocket, + eventType, + pIoBuffer, + dwError); + + if (dwError == ERROR_SUCCESS || + dwError == ERROR_IO_PENDING) + { + dwError = ERROR_SUCCESS; + } + else + { + pSocket = NULL; + pIoBuffer = NULL; + dwError = 0; + } + BAIL_ON_VMREST_ERROR(dwError); + + } +error: +#ifndef WIN32 + if (pSocket) + { + VmwSockRelease( pRESTHandle, pSocket); + } +#endif + + return NULL; +} + + + +static +DWORD +VmRESTHandleSocketEvent( + PVMREST_HANDLE pRESTHandle, + PVM_SOCKET pSocket, + VM_SOCK_EVENT_TYPE sockEvent, + PVM_SOCK_IO_BUFFER pIoBuffer, + DWORD dwError + ) +{ + if (dwError == ERROR_SUCCESS) + { + switch (sockEvent) + { + case VM_SOCK_EVENT_TYPE_TCP_NEW_CONNECTION: + + dwError = VmRESTOnNewConnection( pRESTHandle, pSocket, pIoBuffer); + BAIL_ON_VMREST_ERROR(dwError); + break; +#ifndef WIN32 + case VM_SOCK_EVENT_TYPE_DATA_AVAILABLE: + dwError = VmRESTOnDataAvailable( pRESTHandle,pSocket, pIoBuffer); + BAIL_ON_VMREST_ERROR(dwError); + break; + + case VM_SOCK_EVENT_TYPE_CONNECTION_CLOSED: + VmRESTOnDisconnect( pRESTHandle, pSocket, pIoBuffer); + break; + + case VM_SOCK_EVENT_TYPE_UNKNOWN: + dwError = ERROR_INVALID_STATE; + break; + + default: + dwError = ERROR_INVALID_MESSAGE; + break; +#endif + } + } + +cleanup: + + return dwError; + +error : + goto cleanup; +} + +static +DWORD +VmRESTOnNewConnection( + PVMREST_HANDLE pRESTHandle, + PVM_SOCKET pSocket, + PVM_SOCK_IO_BUFFER pIoBuffer + ) +{ + DWORD dwError = REST_ENGINE_SUCCESS; + if (!pSocket) + { + dwError = ERROR_INVALID_PARAMETER; + BAIL_ON_VMREST_ERROR(dwError); + } + +#ifdef WIN32 + dwError = VmRESTTcpReceiveNewData( pRESTHandle, pSocket); + BAIL_ON_VMREST_ERROR(dwError); +#endif +cleanup: + + return dwError; + +error: + + goto cleanup; +} + +static +VOID +VmRESTOnDisconnect( + PVMREST_HANDLE pRESTHandle, + PVM_SOCKET pSocket, + PVM_SOCK_IO_BUFFER pIoBuffer + ) +{ + if (pSocket) + { + VmwSockClose( pRESTHandle, pSocket); + } + + if (pIoBuffer) + { + VmwSockReleaseIoBuffer( pRESTHandle, pIoBuffer); + } +} + +static +DWORD +VmRESTOnDataAvailable( + PVMREST_HANDLE pRESTHandle, + PVM_SOCKET pSocket, + PVM_SOCK_IO_BUFFER pIoBuffer + ) +{ + DWORD dwError = REST_ENGINE_SUCCESS; + + if (!pSocket) + { + dwError = ERROR_INVALID_PARAMETER; + BAIL_ON_VMREST_ERROR(dwError); + } + + dwError = VmRESTReceiveData( pRESTHandle,pSocket, pIoBuffer); + BAIL_ON_VMREST_ERROR(dwError); + +cleanup: + if (pIoBuffer) + { + VmwSockReleaseIoBuffer( pRESTHandle, pIoBuffer); + } + + return dwError; + +error: + + goto cleanup; +} + +static +DWORD +VmRESTReceiveData( + PVMREST_HANDLE pRESTHandle, + PVM_SOCKET pSocket, + PVM_SOCK_IO_BUFFER pIoBuffer + ) +{ + DWORD dwError = REST_ENGINE_SUCCESS; + + if (!pSocket) + { + dwError = ERROR_INVALID_PARAMETER; + BAIL_ON_VMREST_ERROR(dwError); + } + + dwError = VmRESTTcpReceiveData( pRESTHandle,pSocket, pIoBuffer); + BAIL_ON_VMREST_ERROR(dwError); + +cleanup: + if (pIoBuffer) + { + VmwSockReleaseIoBuffer( pRESTHandle, pIoBuffer); + } + + return dwError; + +error: + + goto cleanup; + +} + +static +DWORD +VmRESTTcpReceiveData( + PVMREST_HANDLE pRESTHandle, + PVM_SOCKET pSocket, + PVM_SOCK_IO_BUFFER pIoBuffer + ) +{ + DWORD dwError = REST_ENGINE_SUCCESS; + + if (!pSocket) + { + dwError = ERROR_INVALID_PARAMETER; + BAIL_ON_VMREST_ERROR(dwError); + } + + if (!pIoBuffer) + { + dwError = VmRESTTcpReceiveNewData( pRESTHandle,pSocket); + BAIL_ON_VMREST_ERROR(dwError); + } + +cleanup: + if (pIoBuffer) + { + VmwSockReleaseIoBuffer( pRESTHandle, pIoBuffer); + } + + return dwError; + +error: + + goto cleanup; +} + +static +DWORD +VmRESTTcpReceiveNewData( + PVMREST_HANDLE pRESTHandle, + PVM_SOCKET pSocket + ) +{ + DWORD dwError = REST_ENGINE_SUCCESS; + char appBuffer[MAX_DATA_BUFFER_LEN] = {0}; + uint32_t bytesRead = 0; + + dwError = VmsockPosixGetXBytes( + pRESTHandle, + MAX_DATA_BUFFER_LEN, + appBuffer, + pSocket, + &bytesRead, + 0 + ); + BAIL_ON_VMREST_ERROR(dwError); + + + if (bytesRead > 0) + { + VMREST_LOG_DEBUG(pRESTHandle,"%s","Starting HTTP Parsing."); + dwError = VmRESTProcessIncomingData( + pRESTHandle, + appBuffer, + bytesRead, + pSocket + ); + BAIL_ON_VMREST_ERROR(dwError); + } + + +cleanup: + VMREST_LOG_DEBUG(pRESTHandle,"%s","Calling closed connection...."); + VmRESTDisconnectClient( pRESTHandle, pSocket); + + return dwError; + +error: + + goto cleanup; +} + +static +VOID +VmRESTSockContextFree( + PVMREST_HANDLE pRESTHandle, + PVMREST_SOCK_CONTEXT pSockContext + ) +{ + if (pSockContext->pEventQueue) + { + VmwSockCloseEventQueue( pRESTHandle, pSockContext->pEventQueue); + } + if (pSockContext->pListenerTCP) + { + VmwSockRelease( pRESTHandle, pSockContext->pListenerTCP); + } + if (pSockContext->pListenerTCP6) + { + VmwSockRelease( pRESTHandle, pSockContext->pListenerTCP6); + } + if (pSockContext->pWorkerThreads) + { + DWORD iThr = 0; + + for (; iThr < pSockContext->dwNumThreads; iThr++) + { + PVMREST_THREAD pThread = pSockContext->pWorkerThreads[iThr]; + + if (pThread) + { + VmRESTFreeThread(pThread); + } + } + + VmRESTFreeMemory(pSockContext->pWorkerThreads); + } + if (pSockContext->pMutex) + { + VmRESTFreeMutex(pSockContext->pMutex); + } +} + +static +DWORD +VmRESTDisconnectClient( + PVMREST_HANDLE pRESTHandle, + PVM_SOCKET pSocket + ) +{ + DWORD dwError = REST_ENGINE_SUCCESS; + + if (!pSocket) + { + dwError = ERROR_INVALID_PARAMETER; + BAIL_ON_VMREST_ERROR(dwError); + } + + VmwSockClose( pRESTHandle, pSocket); + VmwSockRelease( pRESTHandle, pSocket); + +cleanup: + + return dwError; + +error: + + goto cleanup; +} + +uint32_t +VmsockPosixGetXBytes( + PVMREST_HANDLE pRESTHandle, + uint32_t bytesRequested, + char* appBuffer, + PVM_SOCKET pSocket, + uint32_t* bytesRead, + uint8_t shouldBlock + ) +{ + uint32_t dwError = REST_ENGINE_SUCCESS; + uint32_t dataIndex = 0; + uint32_t remainingBytes = 0; + uint32_t dataAvailableInCache = 0; + PVM_SOCK_IO_BUFFER pIoBuffer = NULL; + PVM_STREAM_BUFFER pStreamBuffer = NULL; + + if (bytesRequested > MAX_DATA_BUFFER_LEN || appBuffer == NULL || bytesRead == NULL) + { + VMREST_LOG_DEBUG(pRESTHandle,"%s","Bytes to be read %u Large or appBuffer: %s", + bytesRequested, appBuffer); + dwError = VMREST_TRANSPORT_INVALID_PARAM; + } + BAIL_ON_VMREST_ERROR(dwError); + + if (sizeof(appBuffer) > MAX_DATA_BUFFER_LEN) + { + VMREST_LOG_DEBUG(pRESTHandle,"%s","ERROR: Application buffer size too large"); + dwError = VMREST_TRANSPORT_INVALID_PARAM; + } + BAIL_ON_VMREST_ERROR(dwError); + + VmwSockGetStreamBuffer( pRESTHandle, pSocket, &pStreamBuffer); + + if (!pStreamBuffer) + { + dwError = 500; + } + BAIL_ON_VMREST_ERROR(dwError); + + dataIndex = pStreamBuffer->dataProcessed; + + dataAvailableInCache = pStreamBuffer->dataRead - pStreamBuffer->dataProcessed; + + if (dataAvailableInCache >= bytesRequested) + { + /**** Enough data available in stream cache buffer ****/ + memcpy(appBuffer, + &(pStreamBuffer->pData[dataIndex]), + bytesRequested + ); + pStreamBuffer->dataProcessed += bytesRequested; + *bytesRead = bytesRequested; + } + else if(dataAvailableInCache < bytesRequested) + { + /**** Copy all remaining client Stream bytes and perform read ****/ + if (dataAvailableInCache > 0) + { + memcpy(appBuffer, + &(pStreamBuffer->pData[dataIndex]), + dataAvailableInCache + ); + pStreamBuffer->dataProcessed += dataAvailableInCache; + /**** This will be overwritten in case of success ****/ + *bytesRead = dataAvailableInCache; + } + + dwError = VmwSockAllocateIoBuffer( + pRESTHandle, + VM_SOCK_EVENT_TYPE_TCP_REQUEST_DATA_READ, + MAX_DATA_BUFFER_LEN, + &pIoBuffer + ); + BAIL_ON_VMREST_ERROR(dwError); + dwError = VmwSockRead( + pRESTHandle, + pSocket, + pIoBuffer); + //VMREST_LOG_DEBUG(pRESTHandle,"SockRead(), dwError = %u, dataRead %u", dwError, pIoBuffer->dwBytesTransferred); + if (dwError == ERROR_SUCCESS) + { + memset(pStreamBuffer->pData, '\0', MAX_DATA_BUFFER_LEN); + memcpy(pStreamBuffer->pData, pIoBuffer->pData,pIoBuffer->dwBytesTransferred); + pStreamBuffer->dataProcessed = 0; + pStreamBuffer->dataRead = pIoBuffer->dwBytesTransferred; + BAIL_ON_VMREST_ERROR(dwError); + } + else if (dwError == ERROR_IO_PENDING) + { + // fail for linux? +#ifndef WIN32 + pIoBuffer = NULL; +#endif + } + else + { + BAIL_ON_VMREST_ERROR(dwError); + } + + remainingBytes = bytesRequested - dataAvailableInCache; + dataIndex = 0; + + if (remainingBytes > pStreamBuffer->dataRead) + { + remainingBytes = pStreamBuffer->dataRead; + VMREST_LOG_DEBUG(pRESTHandle,"WARNING: Requested %u bytes, available only %u bytes", bytesRequested,(dataAvailableInCache + remainingBytes)); + } + + memcpy((appBuffer + dataAvailableInCache), + &(pStreamBuffer->pData[dataIndex]), + remainingBytes); + pStreamBuffer->dataProcessed = remainingBytes; + *bytesRead = dataAvailableInCache + remainingBytes; + + //VMREST_LOG_DEBUG(pRESTHandle,"dataAvailableInCache %u, remainingBytes %u, appBuffersize %u", dataAvailableInCache, remainingBytes, strlen(appBuffer)); + } + + VmwSockSetStreamBuffer( pRESTHandle, pSocket, pStreamBuffer); + +cleanup: + if (pIoBuffer) + { + VmwSockReleaseIoBuffer( pRESTHandle, pIoBuffer); + } + + return dwError; + +error: + + goto cleanup; + +} + +uint32_t +VmSockPosixAdjustProcessedBytes( + PVMREST_HANDLE pRESTHandle, + PVM_SOCKET pSocket, + uint32_t dataSeen +) +{ + uint32_t dwError = REST_ENGINE_SUCCESS; + PVM_STREAM_BUFFER pStreamBuffer = NULL; + + if (dataSeen > MAX_DATA_BUFFER_LEN) + { + VMREST_LOG_DEBUG(pRESTHandle,"%s","Invalid new Processed Data Index %u", dataSeen); + dwError = VMREST_TRANSPORT_INVALID_PARAM; + } + BAIL_ON_VMREST_ERROR(dwError); + + VmwSockGetStreamBuffer( pRESTHandle, pSocket, &pStreamBuffer); + + if (!pStreamBuffer) + { + dwError = 500; + } + BAIL_ON_VMREST_ERROR(dwError); + + pStreamBuffer->dataProcessed = dataSeen; + + VmwSockSetStreamBuffer( pRESTHandle, pSocket, pStreamBuffer); + +cleanup: + return dwError; +error: + goto cleanup; +} + +uint32_t +VmSockPosixDecrementProcessedBytes( + PVMREST_HANDLE pRESTHandle, + PVM_SOCKET pSocket, + uint32_t offset +) +{ + uint32_t dwError = REST_ENGINE_SUCCESS; + PVM_STREAM_BUFFER pStreamBuffer = NULL; + + if (offset > MAX_DATA_BUFFER_LEN) + { + VMREST_LOG_DEBUG(pRESTHandle,"%s","Invalid new Processed Data Index %u", offset); + dwError = VMREST_TRANSPORT_INVALID_PARAM; + } + BAIL_ON_VMREST_ERROR(dwError); + + VmwSockGetStreamBuffer( pRESTHandle, pSocket, &pStreamBuffer); + + if (!pStreamBuffer) + { + dwError = 500; + } + BAIL_ON_VMREST_ERROR(dwError); + + if (pStreamBuffer->dataProcessed >= offset) + { + pStreamBuffer->dataProcessed = pStreamBuffer->dataProcessed - offset; + } + VmwSockSetStreamBuffer( pRESTHandle, pSocket, pStreamBuffer); + +cleanup: + return dwError; +error: + goto cleanup; +} + + +uint32_t +VmsockPosixWriteDataAtOnce( + PVMREST_HANDLE pRESTHandle, + PVM_SOCKET pSocket, + char* buffer, + uint32_t bytes + ) +{ + uint32_t dwError = REST_ENGINE_SUCCESS; + PVM_SOCK_IO_BUFFER pIoNewBuffer = NULL; + + dwError = VmwSockAllocateIoBuffer( + pRESTHandle, + VM_SOCK_EVENT_TYPE_TCP_RESPONSE_DATA_WRITE, + bytes, + &pIoNewBuffer); + BAIL_ON_VMREST_ERROR(dwError); + + memcpy(pIoNewBuffer->pData, buffer, bytes); + + dwError = VmwSockWrite( + pRESTHandle, + pSocket, + NULL, + 0, + pIoNewBuffer + ); + if (dwError == ERROR_SUCCESS) + { + dwError = REST_ENGINE_SUCCESS; + BAIL_ON_VMREST_ERROR(dwError); + } + else if (dwError == ERROR_IO_PENDING) + { + pIoNewBuffer = NULL; + BAIL_ON_VMREST_ERROR(dwError); + } + +cleanup: + if (pIoNewBuffer) + { + VmwSockReleaseIoBuffer( pRESTHandle, pIoNewBuffer); + } + return dwError; +error: + goto cleanup; +} diff -ru c-rest-engine-1.0.3/include/public/vmrest.h c-rest-engine-1.0.4/include/public/vmrest.h --- c-rest-engine-1.0.3/include/public/vmrest.h 2017-07-20 19:57:03.000000000 -0700 +++ c-rest-engine-1.0.4/include/public/vmrest.h 2017-08-21 16:40:55.000000000 -0700 @@ -41,6 +41,7 @@ #define REST_ERROR_BAD_CONFIG_FILE_PATH 110 #define REST_ERROR_PREV_INSTANCE_NOT_CLEAN 111 #define REST_ERROR_INVALID_HANDLER 112 +#define REST_ENGINE_SSL_CONFIG_FILE 113 #define REST_ENGINE_MORE_IO_REQUIRED 7001 #define REST_ENGINE_IO_COMPLETED 0 diff -ru c-rest-engine-1.0.3/server/restengine/defines.h c-rest-engine-1.0.4/server/restengine/defines.h --- c-rest-engine-1.0.3/server/restengine/defines.h 2017-07-20 19:57:03.000000000 -0700 +++ c-rest-engine-1.0.4/server/restengine/defines.h 2017-08-21 16:40:55.000000000 -0700 @@ -25,6 +25,7 @@ #define HTTP_VER_LEN 8 #define HTTP_CHUNKED_DATA_LEN 7 #define HTTP_MIN_CHUNK_DATA_LEN 3 +#define HTTP_CRLF_LEN 2 #define MAX_KEY_VAL_PARAM_LEN 1024 #define MAX_URL_PARAMS_ARR_SIZE 5 diff -ru c-rest-engine-1.0.3/server/restengine/httpProtocolHead.c c-rest-engine-1.0.4/server/restengine/httpProtocolHead.c --- c-rest-engine-1.0.3/server/restengine/httpProtocolHead.c 2017-07-20 19:57:03.000000000 -0700 +++ c-rest-engine-1.0.4/server/restengine/httpProtocolHead.c 2017-08-21 16:40:55.000000000 -0700 @@ -234,7 +234,7 @@ { uint32_t dwError = REST_ENGINE_SUCCESS; char* buffer = NULL; - char local[MAX_REQ_LIN_LEN] = {0}; + char* local = NULL; char attribute[MAX_HTTP_HEADER_ATTR_LEN] = {0}; char value[MAX_HTTP_HEADER_VAL_LEN] = {0}; char* temp = NULL; @@ -242,6 +242,12 @@ size_t attrLen = 0; size_t valLen = 0; + dwError = VmRESTAllocateMemory( + MAX_REQ_LIN_LEN, + (void**)&local + ); + BAIL_ON_VMREST_ERROR(dwError); + buffer = line; temp = local; @@ -263,7 +269,7 @@ *temp = '\0'; strncpy(attribute,local,(MAX_HTTP_HEADER_ATTR_LEN - 1)); attrLen = strlen(attribute); - memset(local,'\0', sizeof(local)); + memset(local,'\0', MAX_REQ_LIN_LEN); temp = local; continue; } @@ -293,6 +299,12 @@ BAIL_ON_VMREST_ERROR(dwError); cleanup: + if (local != NULL) + { + VmRESTFreeMemory(local); + local = NULL; + } + return dwError; error: goto cleanup; @@ -310,7 +322,7 @@ { uint32_t dwError = REST_ENGINE_SUCCESS; char method[MAX_METHOD_LEN] = {0}; - char URI[MAX_URI_LEN]={0}; + char* URI = NULL; char version[MAX_VERSION_LEN] = {0}; if (!line || !pReqPacket || (*resStatus != OK) || lineNo == 0) @@ -320,6 +332,12 @@ } BAIL_ON_VMREST_ERROR(dwError); + dwError = VmRESTAllocateMemory( + MAX_URI_LEN, + (PVOID*)&URI + ); + BAIL_ON_VMREST_ERROR(dwError); + if (lineLen > MAX_REQ_LIN_LEN) { dwError = REQUEST_URI_TOO_LARGE; @@ -337,7 +355,7 @@ resStatus ); BAIL_ON_VMREST_ERROR(dwError); - strcpy(pReqPacket->requestLine->method, method); + strncpy(pReqPacket->requestLine->method, method, (MAX_METHOD_LEN - 1)); dwError = VmRESTHTTPGetReqURI( line, @@ -346,7 +364,7 @@ resStatus ); BAIL_ON_VMREST_ERROR(dwError); - strcpy(pReqPacket->requestLine->uri, URI); + strncpy(pReqPacket->requestLine->uri, URI, (MAX_URI_LEN - 1)); dwError = VmRESTHTTPGetReqVersion( line, @@ -355,7 +373,7 @@ resStatus ); BAIL_ON_VMREST_ERROR(dwError); - strcpy(pReqPacket->requestLine->version, version); + strncpy(pReqPacket->requestLine->version, version, (MAX_VERSION_LEN - 1)); } else { @@ -370,6 +388,11 @@ } cleanup: + if (URI != NULL) + { + VmRESTFreeMemory(URI); + URI = NULL; + } return dwError; error: goto cleanup; @@ -384,123 +407,161 @@ uint32_t* resStatus ) { + int nDataStart = 0; + char sockBuffer[MAX_DATA_BUFFER_LEN]={0}; + char* local = NULL; + char* pszStartNewLine = buffer; + char* pszEndNewLine = NULL; + char* newBuf = NULL; + char* prevBuffer = NULL; + char* prevBufferTemp = NULL; uint32_t dwError = REST_ENGINE_SUCCESS; - uint32_t bytesRead = 0; + uint32_t nProcessed = 0; uint32_t lineNo = 0; - size_t lineLen = 0; - char local[MAX_REQ_LIN_LEN]={0}; - char* temp = buffer; - char* line = local; - char appBuffer[MAX_DATA_BUFFER_LEN]={0}; - uint32_t bytesReadInBuffer = 0; - uint32_t skipRead = 0; - uint32_t extraBytes = 0; + uint32_t nPrevBuf = 0; + uint32_t nLineLen = 0; + uint32_t nBufLen = packetLen; + uint32_t nEmptyPrevBuf = 0; + uint32_t nSockReadRequest = 0; + uint32_t nSockReadActual = 0; + - if (!buffer || !pReqPacket || (*resStatus != OK) || (packetLen <= 4)) + if (!buffer || !pReqPacket || (*resStatus != OK)) { VMREST_LOG_ERROR(pRESTHandle,"%s","Invalid params"); dwError = BAD_REQUEST; *resStatus = BAD_REQUEST; } BAIL_ON_VMREST_ERROR(dwError); - - while(1) - { - if (bytesRead >= (packetLen - 4)) - { - if (temp && (strcmp(temp,"\r\n\r\n") == 0)) - { - skipRead = 1; - } - /**** More socket read required to process the headers ****/ + /**** Allocate all memory for buffers ****/ + dwError = VmRESTAllocateMemory( + MAX_REQ_LIN_LEN, + (PVOID*)&local + ); + BAIL_ON_VMREST_ERROR(dwError); + + dwError = VmRESTAllocateMemory( + MAX_REQ_LIN_LEN, + (PVOID*)&prevBuffer + ); + BAIL_ON_VMREST_ERROR(dwError); + + dwError = VmRESTAllocateMemory( + MAX_REQ_LIN_LEN, + (PVOID*)&prevBufferTemp + ); + BAIL_ON_VMREST_ERROR(dwError); - if (!skipRead) + while(pszStartNewLine != NULL) + { + pszEndNewLine = strstr(pszStartNewLine, "\r\n"); + if (pszEndNewLine != NULL) + { + nLineLen = pszEndNewLine - pszStartNewLine; + VMREST_LOG_DEBUG(pRESTHandle,"Line length is: %u",nLineLen); + if( nLineLen == 0 ) { - extraBytes = packetLen - bytesRead; - dwError = VmSockPosixAdjustProcessedBytes( - pRESTHandle, - pReqPacket->pSocket, - bytesRead - ); + /**** This is the end of all HTTP headers ****/ + nDataStart = nProcessed - nPrevBuf + HTTP_CRLF_LEN; + if ( nDataStart < 0 ) + { + VMREST_LOG_ERROR(pRESTHandle,"Bad request detected, Negative data start postion: %d", nDataStart); + dwError = BAD_REQUEST; + } BAIL_ON_VMREST_ERROR(dwError); - memset(appBuffer, '\0', MAX_DATA_BUFFER_LEN); - dwError = VmsockPosixGetXBytes( + dwError = VmSockPosixAdjustProcessedBytes( pRESTHandle, - MAX_DATA_BUFFER_LEN, - appBuffer, pReqPacket->pSocket, - &bytesReadInBuffer, - 1 + (uint32_t)nDataStart ); BAIL_ON_VMREST_ERROR(dwError); - temp = appBuffer; - bytesRead = 0; - packetLen = bytesReadInBuffer; - - if ((packetLen <= 4) && (strcmp(appBuffer, "\r\n\r\n") != 0)) - { - skipRead = 1; - VMREST_LOG_ERROR(pRESTHandle,"%s","Bad HTTP request detected"); - dwError = VMREST_HTTP_VALIDATION_FAILED; - *resStatus = BAD_REQUEST; - } - BAIL_ON_VMREST_ERROR(dwError); + VMREST_LOG_DEBUG(pRESTHandle,"Finished headers parsing with nProcessed %u", nProcessed); + break; } - } - if((*temp == '\r') && (*(temp+1) == '\n')) - { + strncpy(local, pszStartNewLine, nLineLen); lineNo++; - *line = '\0'; - lineLen = strlen(local); - /* call handler function with reqLine */ + + /**** Found a new line, process it and store in HTTP request pcaket ****/ dwError = VmRESTParseHTTPReqLine( lineNo, local, - (uint32_t)lineLen, + nLineLen, pReqPacket, resStatus ); BAIL_ON_VMREST_ERROR(dwError); - bytesRead = bytesRead + 2; - if((*(temp+2) == '\r') && (*(temp+3) == '\n')) - { - bytesRead = bytesRead + 2; - VMREST_LOG_DEBUG(pRESTHandle,"Finished headers parsing with bytesRead %u", bytesRead); - /**** All headers processed : data starts from here ***/ - dwError = VmSockPosixAdjustProcessedBytes( - pRESTHandle, - pReqPacket->pSocket, - (bytesRead - extraBytes) - ); - BAIL_ON_VMREST_ERROR(dwError); - break; - } - temp = temp + 2; memset(local, '\0', MAX_REQ_LIN_LEN); - line = local; - continue; - } - if ((line - local) < MAX_REQ_LIN_LEN ) - { - *line = *temp; - temp++; - line++; - bytesRead++; + nProcessed = nProcessed + nLineLen + HTTP_CRLF_LEN; + pszStartNewLine = pszEndNewLine + HTTP_CRLF_LEN; + pszEndNewLine = NULL; } - else + else /**** pszEndNewLine == NULL ****/ { - dwError = REQUEST_HEADER_FIELD_TOO_LARGE; + /**** more socket reads will be required to process the headers ****/ + nPrevBuf = nBufLen - nProcessed; + if (nPrevBuf >= MAX_REQ_LIN_LEN) + { + dwError = REQUEST_URI_TOO_LARGE; + VMREST_LOG_ERROR(pRESTHandle,"%s","Too large URI"); + } BAIL_ON_VMREST_ERROR(dwError); + + if (nProcessed != 0) + { + /**** Last socket read had CRLF, so adjust the remaining bytes only ****/ + memset(prevBufferTemp, '\0', MAX_REQ_LIN_LEN); + strncpy(prevBufferTemp, pszStartNewLine, nPrevBuf); + pszStartNewLine = prevBufferTemp; + memset(prevBuffer, '\0', MAX_REQ_LIN_LEN); + } + + strncpy(prevBuffer, pszStartNewLine, nPrevBuf); + VMREST_LOG_DEBUG(pRESTHandle,"Requesting read from socket layer, still processing headers ....."); + memset(sockBuffer, '\0', MAX_DATA_BUFFER_LEN); + + nEmptyPrevBuf = MAX_REQ_LIN_LEN - nPrevBuf; + nSockReadRequest = ((nEmptyPrevBuf > MAX_DATA_BUFFER_LEN) ? MAX_DATA_BUFFER_LEN : nEmptyPrevBuf); + + dwError = VmsockPosixGetXBytes( + pRESTHandle, + nSockReadRequest, + sockBuffer, + pReqPacket->pSocket, + &nSockReadActual, + 1 + ); + BAIL_ON_VMREST_ERROR(dwError); + + newBuf = strncat(prevBuffer, sockBuffer, nSockReadActual); + pszStartNewLine = newBuf; + nBufLen = nSockReadActual + nPrevBuf; + nProcessed = 0; } } + cleanup: + if (local != NULL) + { + VmRESTFreeMemory(local); + local = NULL; + } + if (prevBuffer != NULL) + { + VmRESTFreeMemory(prevBuffer); + prevBuffer = NULL; + } + if (prevBufferTemp != NULL) + { + VmRESTFreeMemory(prevBufferTemp); + prevBufferTemp = NULL; + } + return dwError; error: goto cleanup; } - uint32_t VMRESTWriteChunkedMessageInResponseStream( char* src, @@ -1087,8 +1148,8 @@ char* transferEncoding = NULL; char* expect = NULL; uint32_t done = 0; - char httpURI[MAX_URI_LEN] = {0}; - char endPointURI[MAX_URI_LEN] = {0}; + char* httpURI = NULL; + char* endPointURI = NULL; char* ptr = NULL; PREST_ENDPOINT pEndPoint = NULL; @@ -1111,6 +1172,18 @@ ); BAIL_ON_VMREST_ERROR(dwError); + dwError = VmRESTAllocateMemory( + MAX_URI_LEN, + (PVOID*)&httpURI + ); + BAIL_ON_VMREST_ERROR(dwError); + + dwError = VmRESTAllocateMemory( + MAX_URI_LEN, + (PVOID*)&endPointURI + ); + BAIL_ON_VMREST_ERROR(dwError); + pReqPacket->miscHeader->head = NULL; pResPacket->miscHeader->head = NULL; pReqPacket->pSocket = pSocket; @@ -1308,6 +1381,19 @@ /**** Error response is already sent to client, return success ****/ dwError = REST_ENGINE_SUCCESS; } + + if (httpURI != NULL) + { + VmRESTFreeMemory(httpURI); + httpURI = NULL; + } + + if (endPointURI != NULL) + { + VmRESTFreeMemory(endPointURI); + endPointURI = NULL; + } + return dwError; error: VMREST_LOG_ERROR(pRESTHandle,"Something failed, dwError = %u", dwError); diff -ru c-rest-engine-1.0.3/server/restengine/httpUtilsInternal.c c-rest-engine-1.0.4/server/restengine/httpUtilsInternal.c --- c-rest-engine-1.0.3/server/restengine/httpUtilsInternal.c 2017-07-20 19:57:03.000000000 -0700 +++ c-rest-engine-1.0.4/server/restengine/httpUtilsInternal.c 2017-08-21 16:40:55.000000000 -0700 @@ -484,7 +484,7 @@ } BAIL_ON_VMREST_ERROR(dwError); - strncpy(portNo, pRESTConfig->server_port,MAX_SERVER_PORT_LEN); + strncpy(portNo, pRESTConfig->server_port,(MAX_SERVER_PORT_LEN -1)); lastPortChar = VmRESTUtilsGetLastChar( pRESTConfig->server_port diff -ru c-rest-engine-1.0.3/server/restengine/libmain.c c-rest-engine-1.0.4/server/restengine/libmain.c --- c-rest-engine-1.0.3/server/restengine/libmain.c 2017-07-20 19:57:03.000000000 -0700 +++ c-rest-engine-1.0.4/server/restengine/libmain.c 2017-08-21 16:40:55.000000000 -0700 @@ -100,7 +100,7 @@ uint32_t dwError = REST_ENGINE_SUCCESS; char fileName[MAX_PATH_LEN] = {0}; FILE* fp = NULL; - int writtenBytes = 0; + uint32_t writtenBytes = 0; if (!pRESTHandle || !pDataBuffer || (bufferSize == 0) || (bufferSize > MAX_SSL_DATA_BUF_LEN) || (sslDataType < SSL_DATA_TYPE_KEY) || (sslDataType > SSL_DATA_TYPE_CERT)) { @@ -110,42 +110,42 @@ if (((pRESTHandle->pSSLInfo->isCertSet != SSL_INFO_NOT_SET) && (sslDataType == SSL_DATA_TYPE_CERT))) { - goto cleanup; + dwError = REST_ENGINE_SSL_CONFIG_FILE; } + BAIL_ON_VMREST_ERROR(dwError); if (((pRESTHandle->pSSLInfo->isKeySet != SSL_INFO_NOT_SET) && (sslDataType == SSL_DATA_TYPE_KEY))) { - goto cleanup; + dwError = REST_ENGINE_SSL_CONFIG_FILE; } - memset(fileName, '\0', MAX_PATH_LEN); + BAIL_ON_VMREST_ERROR(dwError); if (sslDataType == SSL_DATA_TYPE_KEY) { - sprintf(fileName, "%s%p.pem","/tmp/key-", pRESTHandle); + snprintf(fileName, (MAX_PATH_LEN - 1),"%s%s.pem", "/tmp/key-port-", pRESTHandle->pRESTConfig->server_port); } else if (sslDataType == SSL_DATA_TYPE_CERT) { - sprintf(fileName, "%s%p.pem","/tmp/cert-", pRESTHandle); + snprintf(fileName, (MAX_PATH_LEN - 1), "%s%s.pem", "/tmp/cert-port-", pRESTHandle->pRESTConfig->server_port); } fp = fopen(fileName, "w+"); - if (fp == NULL) { VMREST_LOG_ERROR(pRESTHandle,"Unable to Open SSL file %s", fileName); dwError = REST_ENGINE_FAILURE; } + BAIL_ON_VMREST_ERROR(dwError); writtenBytes = fwrite(pDataBuffer, 1, bufferSize, fp); + fclose(fp); if (writtenBytes != bufferSize) { - VMREST_LOG_WARNING(pRESTHandle,"Not all buffer bytes written to file, requested %u, written %d", bufferSize, writtenBytes); + VMREST_LOG_WARNING(pRESTHandle,"Not all buffer bytes written to file, requested %u, written %u", bufferSize, writtenBytes); } - fclose(fp); - if (sslDataType == SSL_DATA_TYPE_KEY) { memset(pRESTHandle->pRESTConfig->ssl_key, '\0', MAX_PATH_LEN); @@ -177,6 +177,7 @@ ) { uint32_t dwError = REST_ENGINE_SUCCESS; + int ret = 0; if (!pRESTHandle) { @@ -200,11 +201,23 @@ if (pRESTHandle->pSSLInfo->isCertSet == SSL_INFO_FROM_BUFFER_API) { - remove(pRESTHandle->pRESTConfig->ssl_certificate); + if ((ret = remove(pRESTHandle->pRESTConfig->ssl_certificate)) == -1) + { + VMREST_LOG_ERROR(pRESTHandle, "remove() syscall failed for temp certificate file ()"); + dwError = REST_ENGINE_FAILURE; + } + BAIL_ON_VMREST_ERROR(dwError); } + ret = 0; + if (pRESTHandle->pSSLInfo->isKeySet == SSL_INFO_FROM_BUFFER_API) { - remove(pRESTHandle->pRESTConfig->ssl_key); + if ((ret = remove(pRESTHandle->pRESTConfig->ssl_key)) == -1) + { + VMREST_LOG_ERROR(pRESTHandle, "remove temp file failed ()"); + dwError = REST_ENGINE_FAILURE; + } + BAIL_ON_VMREST_ERROR(dwError); } cleanup: diff -ru c-rest-engine-1.0.3/server/restengine/restProtocolHead.c c-rest-engine-1.0.4/server/restengine/restProtocolHead.c --- c-rest-engine-1.0.3/server/restengine/restProtocolHead.c 2017-07-20 19:57:03.000000000 -0700 +++ c-rest-engine-1.0.4/server/restengine/restProtocolHead.c 2017-08-21 16:40:55.000000000 -0700 @@ -20,10 +20,9 @@ PREST_RESPONSE* ppResponse ) { - char httpPayload[MAX_DATA_BUFFER_LEN] = {0}; char httpMethod[MAX_METHOD_LEN] = {0}; - char httpURI[MAX_URI_LEN] = {0}; - char endPointURI[MAX_URI_LEN] = {0}; + char* httpURI = NULL; + char* endPointURI = NULL; char* ptr = NULL; uint32_t dwError = REST_ENGINE_SUCCESS; uint32_t paramsCount = 0; @@ -31,12 +30,19 @@ VMREST_LOG_DEBUG(pRESTHandle,"%s","Internal Handler called"); - /**** 1. Init all the funcition variables *****/ + /**** 1. Allocate the memory of holding URI *****/ - memset(httpPayload, '\0', MAX_DATA_BUFFER_LEN); - memset(httpMethod, '\0', MAX_METHOD_LEN); - memset(httpURI, '\0', MAX_URI_LEN); - memset(endPointURI, '\0', MAX_URI_LEN); + dwError = VmRESTAllocateMemory( + MAX_URI_LEN, + (void**)&endPointURI + ); + BAIL_ON_VMREST_ERROR(dwError); + + dwError = VmRESTAllocateMemory( + MAX_URI_LEN, + (void**)&httpURI + ); + BAIL_ON_VMREST_ERROR(dwError); /**** 2. Get the method name ****/ @@ -191,6 +197,16 @@ BAIL_ON_VMREST_ERROR(dwError); cleanup: + if (endPointURI != NULL) + { + VmRESTFreeMemory(endPointURI); + endPointURI = NULL; + } + if (httpURI != NULL) + { + VmRESTFreeMemory(httpURI); + httpURI = NULL; + } return dwError; error: goto cleanup; @@ -645,11 +661,17 @@ { strncpy(res, (value +1), (MAX_KEY_VAL_PARAM_LEN -1)); } + else if ((*(value +1) == '\0')) + { + VMREST_LOG_DEBUG(pRESTHandle, "Missing value in key-value pair"); + memset(res, '\0', MAX_KEY_VAL_PARAM_LEN); + } else { + VMREST_LOG_ERROR(pRESTHandle, "Value too large"); dwError = REQUEST_ENTITY_TOO_LARGE; } - } + } } else { @@ -926,8 +948,8 @@ uint32_t* wildCardCount ) { - char httpURI[MAX_URI_LEN] = {0}; - char endPointURI[MAX_URI_LEN] = {0}; + char* httpURI = NULL; + char* endPointURI = NULL; char* ptr = NULL; uint32_t dwError = REST_ENGINE_SUCCESS; uint32_t count = 0; @@ -941,8 +963,17 @@ BAIL_ON_VMREST_ERROR(dwError); *wildCardCount = 0; - memset(httpURI, '\0', MAX_URI_LEN); - memset(endPointURI, '\0', MAX_URI_LEN); + dwError = VmRESTAllocateMemory( + MAX_URI_LEN, + (void**)&endPointURI + ); + BAIL_ON_VMREST_ERROR(dwError); + + dwError = VmRESTAllocateMemory( + MAX_URI_LEN, + (void**)&httpURI + ); + BAIL_ON_VMREST_ERROR(dwError); dwError = VmRESTGetHttpURI( pRequest, @@ -989,6 +1020,17 @@ *wildCardCount = count; cleanup: + if (endPointURI != NULL) + { + VmRESTFreeMemory(endPointURI); + endPointURI = NULL; + } + if (httpURI != NULL) + { + VmRESTFreeMemory(httpURI); + httpURI = NULL; + } + return dwError; error: if (wildCardCount != NULL) @@ -1010,8 +1052,8 @@ uint32_t dwError = REST_ENGINE_SUCCESS; uint32_t count = 0; uint32_t preSlashIndex = 0; - char httpURI[MAX_URI_LEN] = {0}; - char endPointURI[MAX_URI_LEN] = {0}; + char* httpURI = NULL; + char* endPointURI = NULL; char* ptr = NULL; char* pszWildCard = NULL; PREST_ENDPOINT pEndPoint = NULL; @@ -1023,6 +1065,18 @@ } BAIL_ON_VMREST_ERROR(dwError); + dwError = VmRESTAllocateMemory( + MAX_URI_LEN, + (void**)&endPointURI + ); + BAIL_ON_VMREST_ERROR(dwError); + + dwError = VmRESTAllocateMemory( + MAX_URI_LEN, + (void**)&httpURI + ); + BAIL_ON_VMREST_ERROR(dwError); + dwError = VmRESTGetWildCardCount( pRESTHandle, pRequest, @@ -1097,6 +1151,16 @@ cleanup: + if (endPointURI != NULL) + { + VmRESTFreeMemory(endPointURI); + endPointURI = NULL; + } + if (httpURI != NULL) + { + VmRESTFreeMemory(httpURI); + httpURI = NULL; + } return dwError; error: if (pszWildCard) diff -ru c-rest-engine-1.0.3/server/vmrestd/main.c c-rest-engine-1.0.4/server/vmrestd/main.c --- c-rest-engine-1.0.3/server/vmrestd/main.c 2017-07-20 19:57:03.000000000 -0700 +++ c-rest-engine-1.0.4/server/vmrestd/main.c 2017-08-21 16:40:55.000000000 -0700 @@ -81,6 +81,18 @@ dwError = VmRESTInit(NULL,configPath, &gpRESTHandle); dwError = VmRESTInit(NULL,configPath1, &gpRESTHandle1); +// test set SSL info API +#if 0 + char buffer[8092]= {0}; + FILE *fp = fopen("/root/mycert.pem","r"); + + dwError = fread(buffer, 1, 8092, fp); + VmRESTSetSSLInfo(gpRESTHandle, buffer, dwError, SSL_DATA_TYPE_KEY); + VmRESTSetSSLInfo(gpRESTHandle, buffer, dwError, SSL_DATA_TYPE_CERT); + + +#endif + VmRESTRegisterHandler(gpRESTHandle, "/v1/pkg", &gVmRestHandlers, NULL); VmRESTRegisterHandler(gpRESTHandle1, "/v1/blah", &gVmRestHandlers1, NULL); @@ -121,7 +133,7 @@ ) { uint32_t dwError = REST_ENGINE_MORE_IO_REQUIRED; - char AllData[MAX_IN_MEM_PAYLOAD_LEN] = {0}; + char* AllData = NULL; char buffer[4097] = {0}; int nRead = 0; int nWrite = 0; @@ -131,9 +143,11 @@ int resLength = 0; uint32_t index = 0; - memset(AllData, '\0', MAX_IN_MEM_PAYLOAD_LEN); memset(size, '\0', 10); + AllData = malloc(MAX_IN_MEM_PAYLOAD_LEN); + memset(AllData, '\0', MAX_IN_MEM_PAYLOAD_LEN); + bytesRW = 0; while(dwError == REST_ENGINE_MORE_IO_REQUIRED) @@ -230,6 +244,12 @@ BAIL_ON_VMREST_ERROR(dwError); cleanup: + if (AllData != NULL) + { + free(AllData); + AllData = NULL; + } + return dwError; error: goto cleanup; @@ -247,7 +267,7 @@ ) { uint32_t dwError = 0; - char AllData[MAX_IN_MEM_PAYLOAD_LEN] = {0}; + char* AllData = NULL; char buffer[4097] = {0}; int nRead = 0; int nWrite = 0; @@ -259,9 +279,11 @@ FILE* fp = NULL; memset(buffer, '\0', 4097); - memset(AllData, '\0', MAX_IN_MEM_PAYLOAD_LEN); memset(size, '\0', 10); + AllData = malloc(MAX_IN_MEM_PAYLOAD_LEN); + memset(AllData, '\0', MAX_IN_MEM_PAYLOAD_LEN); + dwError = REST_ENGINE_MORE_IO_REQUIRED; fp = fopen("/tmp/image.vmdk","wb+"); @@ -303,6 +325,7 @@ BAIL_ON_VMREST_ERROR(dwError); fclose(fp); + fp = NULL; dwError = VmRESTSetSuccessResponse( pRequest, @@ -368,8 +391,20 @@ BAIL_ON_VMREST_ERROR(dwError); cleanup: + if (AllData != NULL) + { + free(AllData); + AllData = NULL; + } + return dwError; error: + + if (fp != NULL) + { + fclose(fp); + fp = NULL; + } goto cleanup; } diff -ru c-rest-engine-1.0.3/transport/posix/global.c c-rest-engine-1.0.4/transport/posix/global.c --- c-rest-engine-1.0.3/transport/posix/global.c 2017-07-20 19:57:03.000000000 -0700 +++ c-rest-engine-1.0.4/transport/posix/global.c 2017-08-21 16:40:55.000000000 -0700 @@ -15,6 +15,6 @@ int gSSLisedInstaceCount = INVALID; pthread_mutex_t* gSSLThreadLock = NULL; -pthread_mutex_t gGlobalMutex; +pthread_mutex_t gGlobalMutex = PTHREAD_MUTEX_INITIALIZER; diff -ru c-rest-engine-1.0.3/transport/posix/socket.c c-rest-engine-1.0.4/transport/posix/socket.c --- c-rest-engine-1.0.3/transport/posix/socket.c 2017-07-20 19:57:03.000000000 -0700 +++ c-rest-engine-1.0.4/transport/posix/socket.c 2017-08-21 16:40:55.000000000 -0700 @@ -266,15 +266,6 @@ ) { DWORD dwError = REST_ENGINE_SUCCESS; - - if (!pRESTHandle) - { - VMREST_LOG_DEBUG(pRESTHandle,"Invalid REST Handler"); - dwError = REST_ERROR_INVALID_HANDLER; - } - BAIL_ON_VMREST_ERROR(dwError); - - union { #ifdef AF_INET6 @@ -294,6 +285,12 @@ PVM_SOCKET pSocket = NULL; PVM_SOCK_SSL_INFO pSSLInfo = NULL; + if (!pRESTHandle) + { + dwError = REST_ERROR_INVALID_HANDLER; + } + BAIL_ON_VMREST_ERROR(dwError); + if (dwFlags & VM_SOCK_CREATE_FLAGS_IPV6) { #ifdef AF_INET6 @@ -324,11 +321,6 @@ /**** Check if connection is over SSL ****/ if(dwFlags & VM_SOCK_IS_SSL) { - if (gSSLisedInstaceCount == INVALID) - { - pthread_mutex_init(&gGlobalMutex, NULL); - gSSLisedInstaceCount = 0; - } SSL_library_init(); dwError = VmRESTSecureSocket( pRESTHandle, @@ -337,15 +329,16 @@ ); BAIL_ON_POSIX_SOCK_ERROR(dwError); pSSLInfo->isSecure = 1; + pthread_mutex_lock(&gGlobalMutex); - if (gSSLisedInstaceCount == 0) + if (gSSLisedInstaceCount == INVALID) { + gSSLisedInstaceCount = 0; dwError = VmRESTSSLThreadLockInit(); - gSSLisedInstaceCount++; } + gSSLisedInstaceCount++; pthread_mutex_unlock(&gGlobalMutex); BAIL_ON_VMREST_ERROR(dwError); - } else { @@ -727,34 +720,33 @@ ssl = SSL_new(pRESTHandle->pSSLInfo->sslContext); SSL_set_fd(ssl,pSocket->fd); retry: - if ((SSL_accept(ssl) == -1) && (timeOutSec >= 0)) + if ( SSL_accept(ssl) == -1 ) { if (timeOutSec >= 0) { - cntRty++; + cntRty++; #ifdef WIN32 - Sleep(timerMs); + Sleep(timerMs); #else - usleep((timerMs * 1000)); + usleep((timerMs * 1000)); #endif - if (cntRty >= maxTry) - { - timerMs = ((timerMs >= 1000) ? 1000 : (timerMs*10)); - maxTry = ((maxTry <= 1) ? 1 : (maxTry/10)); - timeOutSec--; - cntRty = 0; - } - goto retry; + if (cntRty >= maxTry) + { + timerMs = ((timerMs >= 1000) ? 1000 : (timerMs*10)); + maxTry = ((maxTry <= 1) ? 1 : (maxTry/10)); + timeOutSec--; + cntRty = 0; + } + goto retry; } - - else if(timeOutSec <= 0) + else { - VMREST_LOG_ERROR(pRESTHandle,"SSL accept failed"); - SSL_shutdown(ssl); - SSL_free(ssl); - close(pSocket->fd); - dwError = VMREST_TRANSPORT_SSL_ACCEPT_FAILED; - BAIL_ON_VMREST_ERROR(dwError); + VMREST_LOG_ERROR(pRESTHandle,"SSL accept failed"); + SSL_shutdown(ssl); + SSL_free(ssl); + close(pSocket->fd); + dwError = VMREST_TRANSPORT_SSL_ACCEPT_FAILED; + BAIL_ON_VMREST_ERROR(dwError); } } pSocket->ssl = ssl;