/** * @brief Closes the socket * This call does not release the reference to the socket or free it. */ DWORD VmDnsSockWinClose( PVM_SOCKET pSocket ) { VMDNS_LOG_DEBUG("Close Connectiom - Socket: %d", (DWORD)pSocket->hSocket); if (pSocket->hSocket != INVALID_SOCKET) { closesocket(pSocket->hSocket); pSocket->hSocket = INVALID_SOCKET; } return 0; }
VOID VmDnsSockPosixShutdownEventQueue( PVM_SOCK_EVENT_QUEUE pQueue ) { ssize_t bytesWritten = 0; if (pQueue) { InterlockedExchange((LONG*)(&pQueue->bShutdown), TRUE); if (pQueue->pSignalWriter) { char szBuf[] = {0}; bytesWritten = write(pQueue->pSignalWriter->fd, szBuf, sizeof(szBuf)); VMDNS_LOG_DEBUG("%s: write %ld bytes\n", __FUNCTION__, bytesWritten); } } }
BOOLEAN VmDnsValidateRecord( PVMDNS_RECORD pRecord ) { DWORD idx = 0; DWORD dwError = ERROR_SUCCESS; if (pRecord) { dwError = VmDnsFindRecordMethods(pRecord, &idx); if(!dwError) { return gRecordMethods[idx].pfnValidate(pRecord); } } VMDNS_LOG_DEBUG("%s validation of record failed.", __FUNCTION__); return FALSE; }
static DWORD VmDnsCacheRefreshThread( PVOID pArgs ) { DWORD dwError = 0; DWORD newUSN = 0; PVMDNS_CACHE_CONTEXT pCacheContext = (PVMDNS_CACHE_CONTEXT)pArgs; pCacheContext->bRunning = TRUE; pCacheContext->dwLastUSN = 0; dwError = VmDnsStoreGetReplicationStatus(&(pCacheContext->dwLastUSN)); while (!pCacheContext->bShutdown) { if (VMDNS_READY != VmDnsSrvGetState()) { dwError = VmDnsCacheLoadInitialData(pCacheContext); if (dwError) { VMDNS_LOG_DEBUG("DnsCacheRefreshThread loading initial data failed with %u...Retrying", dwError); goto wait; } else { VMDNS_LOG_INFO("DnsCacheRefreshThread loaded initial data, setting VMDNS state to READY."); VmDnsSrvSetState(VMDNS_READY); } } newUSN = 0; VmDnsStoreGetReplicationStatus(&newUSN); if (pCacheContext->dwLastUSN != 0) { // Refresh LRU, Cache etc. dwError = VmDnsCacheSyncZones( pCacheContext->dwLastUSN, pCacheContext ); if (dwError) { VMDNS_LOG_ERROR("DnsCacheRefreshThread zone synchronization failed with %u.", dwError); } } else { VMDNS_LOG_ERROR("DnsCacheRefreshThread failed to get replication status %u.", dwError); } if (newUSN != 0) { pCacheContext->dwLastUSN = newUSN; dwError = VmDnsCachePurgeLRU(pCacheContext); if (dwError) { VMDNS_LOG_ERROR("DnsCacheRefreshThread failed to purge LRU cache with %u.", dwError); } } wait: if (!pCacheContext->bShutdown) { dwError = VmDnsConditionTimedWait( pCacheContext->pRefreshEvent, pCacheContext->pThreadLock, 5 * 1000 ); if (dwError != ETIMEDOUT && dwError != WSAETIMEDOUT && dwError != ERROR_SUCCESS) { VMDNS_LOG_ERROR("DnsCacheRefreshThread failed to wait with %u. Thread DIEING.", dwError); BAIL_ON_VMDNS_ERROR(dwError); } } } cleanup: pCacheContext->bRunning = FALSE; return dwError; error: goto cleanup; }
/** * @brief Writes data to the socket * * @param[in] pSocket Pointer to socket * @param[in] pBuffer Buffer from which bytes have to be written * @param[in] dwBufLen Number of bytes to write from the buffer * @param[in,out] pdwBytesWrtten Number of bytes written to the socket * In case of UDP sockets, it is mandatory to provide the client address and * length. * * @return 0 on success */ DWORD VmDnsSockWinWrite( PVM_SOCKET pSocket, struct sockaddr* pClientAddress, socklen_t addrLength, PVM_SOCK_IO_BUFFER pIoBuffer ) { DWORD dwError = 0; int sockError = 0; PVM_SOCK_IO_CONTEXT pIoContext = NULL; DWORD dwBytesWritten = 0; DWORD dwFlags = 0; WSABUF wsaBuff = { 0 }; LPOVERLAPPED pOverlapped = NULL; if (!pSocket || !pIoBuffer) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDNS_ERROR(dwError); } pIoContext = CONTAINING_RECORD(pIoBuffer, VM_SOCK_IO_CONTEXT, IoBuffer); if (pIoBuffer->dwExpectedSize <= pIoBuffer->dwCurrentSize) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDNS_ERROR(dwError); } wsaBuff.buf = pIoBuffer->pData + pIoBuffer->dwCurrentSize; wsaBuff.len = pIoBuffer->dwExpectedSize - pIoBuffer->dwCurrentSize; pOverlapped = (pSocket->pEventQueue) ? &pIoContext->Overlapped : NULL; if (pSocket->protocol == VM_SOCK_PROTOCOL_UDP) { if (!pClientAddress || addrLength <= 0) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDNS_ERROR(dwError); } memcpy_s( &pIoBuffer->clientAddr, sizeof pIoBuffer->clientAddr, pClientAddress, addrLength); VMDNS_LOG_DEBUG("WSA SendTo - Address: %p, Event: %d, Size: %d", (DWORD)pIoBuffer, pIoContext->eventType, pIoBuffer->dwExpectedSize); sockError = WSASendTo( pSocket->hSocket, &wsaBuff, 1, &dwBytesWritten, dwFlags, (struct sockaddr*)&pIoBuffer->clientAddr, addrLength, pOverlapped, NULL); VMDNS_LOG_DEBUG( "WSA WSASendTo - Status: %d Byes Transfered : %d ", sockError, dwBytesWritten); } else if (pSocket->protocol == VM_SOCK_PROTOCOL_TCP) { VMDNS_LOG_DEBUG("WSA WSASend - Address: %p, Event: %d, Size: %d", (DWORD)pIoBuffer, pIoContext->eventType, pIoBuffer->dwExpectedSize); sockError = WSASend( pSocket->hSocket, &wsaBuff, 1, &dwBytesWritten, dwFlags, pOverlapped, NULL); VMDNS_LOG_DEBUG( "WSA WSASendTo - Status: %d Byes Transfered : %d ", sockError, dwBytesWritten); } if (sockError == SOCKET_ERROR) { dwError = WSAGetLastError(); BAIL_ON_VMDNS_ERROR(dwError); } else if (pSocket->pEventQueue) { dwError = ERROR_IO_PENDING; } pIoContext->IoBuffer.dwCurrentSize += dwBytesWritten; pIoBuffer = NULL; cleanup: return dwError; error: goto cleanup; }
/** * @brief Reads data from the socket * * @param[in] pSocket Pointer to socket * @param[in] pBuffer Buffer to read the data into * @param[in] dwBufSize Maximum size of the passed in buffer * @param[in,out] pdwBytesRead Number of bytes read in to the buffer * @param[in,out,optional] pClientAddress Client address to fill in optionally * @param[in,out,optional] pAddrLength Length of the client address * * @return 0 on success */ DWORD VmDnsSockWinRead( PVM_SOCKET pSocket, PVM_SOCK_IO_BUFFER pIoBuffer ) { DWORD dwError = 0; int sockError = 0; PVM_SOCK_IO_CONTEXT pIoContext = NULL; DWORD dwBytesRead = 0, dwBytesToRead = 0; DWORD dwFlags = 0; WSABUF wsaBuff = { 0 }; LPOVERLAPPED pOverlapped = NULL; if (!pSocket || !pIoBuffer) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDNS_ERROR(dwError); } pIoContext = CONTAINING_RECORD(pIoBuffer, VM_SOCK_IO_CONTEXT, IoBuffer); if (pIoBuffer->dwExpectedSize <= pIoBuffer->dwCurrentSize) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDNS_ERROR(dwError); } wsaBuff.buf = pIoBuffer->pData + pIoBuffer->dwCurrentSize; wsaBuff.len = pIoBuffer->dwExpectedSize - pIoBuffer->dwCurrentSize; pOverlapped = (pSocket->pEventQueue) ? &pIoContext->Overlapped : NULL; if (pSocket->protocol == VM_SOCK_PROTOCOL_UDP) { VMDNS_LOG_DEBUG( "WSA WSARecvFrom - Socket: %d Address: %p, Event: %d, Size: %d", pSocket->hSocket, (DWORD)pIoBuffer, pIoContext->eventType, pIoBuffer->dwExpectedSize); pIoContext->IoBuffer.addrLen = sizeof pIoContext->IoBuffer.clientAddr; sockError = WSARecvFrom( pSocket->hSocket, &wsaBuff, 1, &dwBytesRead, &dwFlags, (struct sockaddr*)&pIoContext->IoBuffer.clientAddr, &pIoContext->IoBuffer.addrLen, pOverlapped, NULL); VMDNS_LOG_DEBUG( "WSA WSARecvFrom - Status: %d Byes Transfered : %d ", sockError, dwBytesRead); if (sockError == SOCKET_ERROR) { dwError = WSAGetLastError(); BAIL_ON_VMDNS_ERROR(dwError); } else if (pSocket->pEventQueue) { dwError = ERROR_IO_PENDING; } } else if (pSocket->protocol == VM_SOCK_PROTOCOL_TCP) { VMDNS_LOG_DEBUG( "WSA WSARecv - Socket: %d Address: %p, Event: %d, Size: %d", pSocket->hSocket, (DWORD)pIoBuffer, pIoContext->eventType, pIoBuffer->dwExpectedSize); sockError = WSARecv( pSocket->hSocket, &wsaBuff, 1, &dwBytesRead, &dwFlags, pOverlapped, NULL); VMDNS_LOG_DEBUG( "WSA WSARecv - Status: %d Byes Transfered : %d ", sockError, dwBytesRead); if (sockError == SOCKET_ERROR) { dwError = WSAGetLastError(); BAIL_ON_VMDNS_ERROR(dwError); } else if (pSocket->pEventQueue) { dwError = ERROR_IO_PENDING; } } pIoContext->IoBuffer.dwCurrentSize += dwBytesRead; cleanup: return dwError; error: goto cleanup; }
/** * @brief Waits for an event on the event queue * * @param[in] pQueue Pointer to event queue * @param[in,optional] iTimeoutMS * Timeout in milliseconds. * Waits forever if (-1) is passed in. * @param[out] ppSocket Pointer to socket that has an event * @param[in,out] pEventType Event type detected on socket * * @return 0 on success */ DWORD VmDnsSockWinWaitForEvent( PVM_SOCK_EVENT_QUEUE pQueue, int iTimeoutMS, PVM_SOCKET* ppSocket, PVM_SOCK_EVENT_TYPE pEventType, PVM_SOCK_IO_BUFFER* ppIoBuffer ) { DWORD dwError = 0; BOOL bRetVal = TRUE; DWORD dwIoSize = 0; PVM_SOCKET pSocket = NULL; PVM_SOCK_IO_CONTEXT pIoContext = NULL; if (!pQueue || !pQueue->hIOCP || !ppIoBuffer || !pEventType) { dwError = ERROR_INTERNAL_ERROR; BAIL_ON_VMDNS_ERROR(dwError); } bRetVal = GetQueuedCompletionStatus( pQueue->hIOCP, &dwIoSize, (PULONG_PTR)&pSocket, (LPOVERLAPPED*)&pIoContext, iTimeoutMS); if (!bRetVal) { dwError = GetLastError(); BAIL_ON_VMDNS_ERROR(dwError); } VMDNS_LOG_DEBUG("IO Completed Socket:%d, Address:%p Event: %d, Size: %d", pSocket ? pSocket->hSocket : 0, &pIoContext->IoBuffer, pIoContext->eventType, dwIoSize); if (dwIoSize) { pIoContext->IoBuffer.dwTotalBytesTransferred += dwIoSize; } else { pIoContext->IoBuffer.dwTotalBytesTransferred = 0; } *ppIoBuffer = &pIoContext->IoBuffer; *ppSocket = pSocket; *pEventType = pIoContext->eventType; cleanup: return dwError; error: if (ppIoBuffer) { *ppIoBuffer = NULL; } if (ppSocket) { *ppSocket = NULL; } goto cleanup; }
DWORD VmDnsSockWinAcceptConnection( PVM_SOCKET pListenSocket, SOCKET clientSocket, struct sockaddr* pClientAddr, int addrlen ) { DWORD dwError = 0; HANDLE hTemp = NULL; const char chOpt = 1; PVM_SOCKET pClientSocket = NULL; PVM_SOCK_IO_BUFFER pIoBuffer = NULL; PVM_SOCK_IO_CONTEXT pIoContext = NULL; if (!pListenSocket || !pListenSocket->hSocket || !pListenSocket->pEventQueue || !pListenSocket->pEventQueue->hIOCP || clientSocket == INVALID_SOCKET) { dwError = ERROR_INVALID_SERVER_STATE; BAIL_ON_VMDNS_ERROR(dwError); } dwError = VmDnsAllocateMemory( sizeof(*pClientSocket), (PVOID*)&pClientSocket); BAIL_ON_VMDNS_ERROR(dwError); pClientSocket->hSocket = clientSocket; pClientSocket->pEventQueue = pListenSocket->pEventQueue; pClientSocket->protocol = pListenSocket->protocol; pClientSocket->type = VM_SOCK_TYPE_SERVER; memcpy_s(&pClientSocket->addr, sizeof pClientSocket->addr, pClientAddr, addrlen); pClientSocket->addrLen = addrlen; pClientSocket->refCount = 1; clientSocket = INVALID_SOCKET; if (setsockopt( pClientSocket->hSocket, IPPROTO_TCP, TCP_NODELAY, &chOpt, sizeof(char))) { dwError = WSAGetLastError(); BAIL_ON_VMDNS_ERROR(dwError); } hTemp = CreateIoCompletionPort( (HANDLE)pClientSocket->hSocket, pListenSocket->pEventQueue->hIOCP, (ULONG_PTR)pClientSocket, 0 ); if (hTemp != pListenSocket->pEventQueue->hIOCP) { dwError = GetLastError(); BAIL_ON_VMDNS_ERROR(dwError); } dwError = VmDnsSockWinAllocateIoBuffer( VM_SOCK_EVENT_TYPE_TCP_NEW_CONNECTION, 0, &pIoBuffer); BAIL_ON_VMDNS_ERROR(dwError); pIoContext = CONTAINING_RECORD(pIoBuffer, VM_SOCK_IO_CONTEXT, IoBuffer); VMDNS_LOG_DEBUG("New Connectiom - Socket: %d Address: %p, Event: %d, Size: %d", pClientSocket->hSocket, (DWORD)pIoBuffer, pIoContext->eventType, pIoBuffer->dwCurrentSize); if (!PostQueuedCompletionStatus( pListenSocket->pEventQueue->hIOCP, 0, (ULONG_PTR)pClientSocket, (LPOVERLAPPED)pIoContext)) { dwError = GetLastError(); BAIL_ON_VMDNS_ERROR(dwError); } pClientSocket = NULL; pIoBuffer = NULL; cleanup: return dwError; error: if (pClientSocket) { VmDnsSockWinFreeSocket(pClientSocket); } if (pIoBuffer) { VmDnsSockWinFreeIoBuffer(pIoBuffer); } goto cleanup; }