DWORD VmDnsSockPosixSetNonBlocking( PVM_SOCKET pSocket ) { DWORD dwError = 0; BOOLEAN bLocked = FALSE; dwError = VmDnsLockMutex(pSocket->pMutex); BAIL_ON_POSIX_SOCK_ERROR(dwError); bLocked = TRUE; dwError = VmDnsSockPosixSetDescriptorNonBlocking(pSocket->fd); BAIL_ON_POSIX_SOCK_ERROR(dwError); cleanup: if (bLocked) { VmDnsUnlockMutex(pSocket->pMutex); } return dwError; error: goto cleanup; }
DWORD VmDnsSockPosixCloseSocket( PVM_SOCKET pSocket ) { DWORD dwError = 0; BOOLEAN bLocked = FALSE; dwError = VmDnsLockMutex(pSocket->pMutex); BAIL_ON_POSIX_SOCK_ERROR(dwError); bLocked = TRUE; if (pSocket->fd >= 0) { close(pSocket->fd); pSocket->fd = -1; } cleanup: if (bLocked) { VmDnsUnlockMutex(pSocket->pMutex); } return dwError; error: goto cleanup; }
DWORD VmDnsConditionTimedWait( PVMDNS_COND pCondition, PVMDNS_MUTEX pMutex, DWORD dwMilliseconds ) { DWORD dwError = ERROR_SUCCESS; struct timespec ts = {0}; BOOL bLocked = FALSE; if ( ( pCondition == NULL ) || ( pCondition->bInitialized == FALSE ) || ( pMutex == NULL ) || ( pMutex->bInitialized == FALSE ) ) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDNS_ERROR(dwError); } ts.tv_sec = time(NULL) + dwMilliseconds/1000; ts.tv_nsec = 0; dwError = VmDnsLockMutex(pMutex); BAIL_ON_VMDNS_ERROR(dwError); bLocked = TRUE; dwError = pthread_cond_timedwait( &(pCondition->cond), &(pMutex->critSect), &ts ); BAIL_ON_VMDNS_ERROR(dwError); cleanup: if (bLocked) { VmDnsUnlockMutex(pMutex); } return dwError; error: goto cleanup; }
DWORD VmDnsSockPosixSetData( PVM_SOCKET pSocket, PVOID pData, PVOID* ppOldData ) { DWORD dwError = 0; BOOLEAN bLocked = FALSE; PVOID pOldData = NULL; if (!pSocket) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_POSIX_SOCK_ERROR(dwError); } dwError = VmDnsLockMutex(pSocket->pMutex); BAIL_ON_POSIX_SOCK_ERROR(dwError); bLocked = TRUE; pOldData = pSocket->pData; pSocket->pData = pData; if (ppOldData) { *ppOldData = pOldData; } cleanup: if (bLocked) { VmDnsUnlockMutex(pSocket->pMutex); } return dwError; error: if (ppOldData) { *ppOldData = NULL; } goto cleanup; }
DWORD VmDnsSockPosixSetTimeOut( PVM_SOCKET pSocket, DWORD dwTimeOut ) { DWORD dwError = 0; BOOLEAN bLocked = FALSE; if (!pSocket) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_POSIX_SOCK_ERROR(dwError); } if (dwTimeOut) { struct timeval tv = {0}; dwError = VmDnsLockMutex(pSocket->pMutex); BAIL_ON_POSIX_SOCK_ERROR(dwError); bLocked = TRUE; tv.tv_sec = dwTimeOut; if (setsockopt(pSocket->fd, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) < 0) { dwError = LwErrnoToWin32Error(errno); BAIL_ON_POSIX_SOCK_ERROR(dwError); } if (setsockopt(pSocket->fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) { dwError = LwErrnoToWin32Error(errno); BAIL_ON_POSIX_SOCK_ERROR(dwError); } } cleanup: if (bLocked) { VmDnsUnlockMutex(pSocket->pMutex); } return dwError; error: goto cleanup; }
DWORD VmDnsSockPosixGetProtocol( PVM_SOCKET pSocket, PDWORD pdwProtocol ) { DWORD dwError = 0; BOOLEAN bLocked = FALSE; DWORD dwProtocol = 0; if (!pSocket || !pdwProtocol) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_POSIX_SOCK_ERROR(dwError); } dwError = VmDnsLockMutex(pSocket->pMutex); BAIL_ON_POSIX_SOCK_ERROR(dwError); bLocked = TRUE; switch (pSocket->protocol) { case VM_SOCK_PROTOCOL_UDP: dwProtocol = SOCK_DGRAM; break; case VM_SOCK_PROTOCOL_TCP: dwProtocol = SOCK_STREAM; break; default: dwError = ERROR_INTERNAL_ERROR; BAIL_ON_POSIX_SOCK_ERROR(dwError); break; } *pdwProtocol = dwProtocol; cleanup: if (bLocked) { VmDnsUnlockMutex(pSocket->pMutex); } return dwError; error: if (pdwProtocol) { *pdwProtocol = 0; } goto cleanup; }
DWORD VmDnsSockPosixWaitForEvent( PVM_SOCK_EVENT_QUEUE pQueue, int iTimeoutMS, PVM_SOCKET* ppSocket, PVM_SOCK_EVENT_TYPE pEventType, PVM_SOCK_IO_BUFFER* ppIoBuffer ) { DWORD dwError = 0; BOOLEAN bLocked = FALSE; VM_SOCK_EVENT_TYPE eventType = VM_SOCK_EVENT_TYPE_UNKNOWN; PVM_SOCKET pSocket = NULL; PVM_SOCK_IO_BUFFER pIoBuffer = NULL; PVM_SOCK_IO_CONTEXT pIoContext = NULL; uint64_t uiTriggerCount = 0; if (!pQueue || !ppSocket || !pEventType) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_POSIX_SOCK_ERROR(dwError); } dwError = VmDnsLockMutex(pQueue->pMutex); BAIL_ON_POSIX_SOCK_ERROR(dwError); bLocked = TRUE; if (pQueue->bShutdown) { dwError = ERROR_SHUTDOWN_IN_PROGRESS; BAIL_ON_POSIX_SOCK_ERROR(dwError); } if ((pQueue->state == VM_SOCK_POSIX_EVENT_STATE_PROCESS) && (pQueue->iReady >= pQueue->nReady)) { pQueue->state = VM_SOCK_POSIX_EVENT_STATE_WAIT; } if (pQueue->state == VM_SOCK_POSIX_EVENT_STATE_WAIT) { pQueue->iReady = 0; pQueue->nReady = -1; while (pQueue->nReady < 0) { pQueue->nReady = epoll_wait( pQueue->epollFd, pQueue->pEventArray, pQueue->dwSize, iTimeoutMS); if ((pQueue->nReady < 0) && (errno != EINTR)) { dwError = LwErrnoToWin32Error(errno); BAIL_ON_POSIX_SOCK_ERROR(dwError); } if (pQueue->bShutdown) { dwError = ERROR_SHUTDOWN_IN_PROGRESS; BAIL_ON_POSIX_SOCK_ERROR(dwError); } } pQueue->state = VM_SOCK_POSIX_EVENT_STATE_PROCESS; } if (pQueue->state == VM_SOCK_POSIX_EVENT_STATE_PROCESS) { if (pQueue->iReady < pQueue->nReady) { struct epoll_event* pEvent = &pQueue->pEventArray[pQueue->iReady]; PVM_SOCKET pEventSocket = (PVM_SOCKET)pEvent->data.ptr; if (!pEventSocket) { dwError = ERROR_INVALID_STATE; BAIL_ON_POSIX_SOCK_ERROR(dwError); } if (pEvent->events & (EPOLLERR | EPOLLHUP)) { eventType = VM_SOCK_EVENT_TYPE_CONNECTION_CLOSED; pSocket = VmDnsSockPosixAcquireSocket(pEventSocket); dwError = VmDnsSockPosixEventQueueDelete_inlock( pQueue, pSocket); BAIL_ON_POSIX_SOCK_ERROR(dwError); } else if (pEventSocket->type == VM_SOCK_TYPE_LISTENER) { switch (pEventSocket->protocol) { case VM_SOCK_PROTOCOL_TCP: dwError = VmDnsSockPosixAcceptConnection( pEventSocket, &pSocket); BAIL_ON_POSIX_SOCK_ERROR(dwError); dwError = VmDnsSockPosixSetNonBlocking(pSocket); BAIL_ON_POSIX_SOCK_ERROR(dwError); eventType = VM_SOCK_EVENT_TYPE_TCP_NEW_CONNECTION; break; case VM_SOCK_PROTOCOL_UDP: pSocket = VmDnsSockPosixAcquireSocket(pEventSocket); eventType = VM_SOCK_EVENT_TYPE_DATA_AVAILABLE; break; default: dwError = ERROR_INVALID_STATE; BAIL_ON_POSIX_SOCK_ERROR(dwError); break; } } else if (pEventSocket->type == VM_SOCK_TYPE_SERVER) { switch (pEventSocket->protocol) { case VM_SOCK_PROTOCOL_TCP: if (!pEventSocket->pData) { eventType = VM_SOCK_EVENT_TYPE_TCP_REQUEST_SIZE_READ; } pSocket = VmDnsSockPosixAcquireSocket(pEventSocket); break; default: dwError = ERROR_INVALID_STATE; BAIL_ON_POSIX_SOCK_ERROR(dwError); break; } } else if (pEventSocket->type == VM_SOCK_TYPE_SIGNAL) { if (pQueue->bShutdown) { dwError = ERROR_SHUTDOWN_IN_PROGRESS; BAIL_ON_POSIX_SOCK_ERROR(dwError); } else { pSocket = VmDnsSockPosixAcquireSocket(pEventSocket); } } else if (pEventSocket->type == VM_SOCK_TYPE_TIMER) { if (pQueue->bShutdown) { dwError = ERROR_SHUTDOWN_IN_PROGRESS; BAIL_ON_POSIX_SOCK_ERROR(dwError); } else { pSocket = VmDnsSockPosixAcquireSocket(pEventSocket); if (read(pSocket->fd, &uiTriggerCount, sizeof(uiTriggerCount)) < 0) { VMDNS_LOG_ERROR("%s: read() on timer fd failed (%d)", __FUNCTION__, errno); } eventType = VM_SOCK_EVENT_TYPE_TIMER_EXPIRATION; } } else { pSocket = VmDnsSockPosixAcquireSocket(pEventSocket); } } pQueue->iReady++; } dwError = VmDnsSockPosixSetData(pSocket, NULL, (PVOID *)&pIoBuffer); BAIL_ON_POSIX_SOCK_ERROR(dwError); if (pIoBuffer && eventType == VM_SOCK_EVENT_TYPE_UNKNOWN) { pIoContext = CONTAINING_RECORD(pIoBuffer, VM_SOCK_IO_CONTEXT, IoBuffer); eventType = pIoContext->eventType; } *ppSocket = pSocket; *ppIoBuffer = pIoBuffer; *pEventType = eventType; cleanup: if (bLocked) { VmDnsUnlockMutex(pQueue->pMutex); } return dwError; error: if (ppSocket) { *ppSocket = NULL; } if (ppIoBuffer) { *ppIoBuffer = NULL; } if (pEventType) { *pEventType = VM_SOCK_EVENT_TYPE_UNKNOWN; } if (pSocket) { VmDnsSockPosixReleaseSocket(pSocket); } goto cleanup; }
DWORD VmDnsSockPosixWrite( PVM_SOCKET pSocket, const struct sockaddr* pClientAddress, socklen_t addrLength, PVM_SOCK_IO_BUFFER pIoBuffer ) { DWORD dwError = 0; BOOLEAN bLocked = FALSE; int flags = 0; ssize_t nWritten = 0; DWORD dwBytesToWrite = 0; const struct sockaddr* pClientAddressLocal = NULL; socklen_t addrLengthLocal = 0; if (!pSocket || !pIoBuffer || !pIoBuffer->pData) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_POSIX_SOCK_ERROR(dwError); } dwBytesToWrite = pIoBuffer->dwExpectedSize - pIoBuffer->dwCurrentSize; if (pClientAddress && addrLength) { pClientAddressLocal = pClientAddress; addrLengthLocal = addrLength; } else { pClientAddressLocal = &pSocket->addr; addrLengthLocal = pSocket->addrLen; } dwError = VmDnsLockMutex(pSocket->pMutex); BAIL_ON_POSIX_SOCK_ERROR(dwError); bLocked = TRUE; nWritten = sendto( pSocket->fd, pIoBuffer->pData, dwBytesToWrite, flags, pClientAddressLocal, addrLengthLocal); if (nWritten < 0) { dwError = LwErrnoToWin32Error(errno); BAIL_ON_POSIX_SOCK_ERROR(dwError); } pIoBuffer->dwCurrentSize += nWritten; pIoBuffer->dwTotalBytesTransferred += nWritten; cleanup: if (bLocked) { VmDnsUnlockMutex(pSocket->pMutex); } return dwError; error: goto cleanup; }
DWORD VmDnsSockPosixRead( PVM_SOCKET pSocket, PVM_SOCK_IO_BUFFER pIoBuffer ) { DWORD dwError = 0; BOOLEAN bLocked = FALSE; int flags = 0; ssize_t nRead = 0; DWORD dwBufSize = 0; DWORD dwSockAddrLen = 0; if (!pSocket || !pIoBuffer || !pIoBuffer->pData) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_POSIX_SOCK_ERROR(dwError); } if (pIoBuffer->dwExpectedSize < pIoBuffer->dwCurrentSize) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_POSIX_SOCK_ERROR(dwError); } dwBufSize = pIoBuffer->dwExpectedSize - pIoBuffer->dwCurrentSize; dwSockAddrLen = sizeof pIoBuffer->clientAddr; dwError = VmDnsLockMutex(pSocket->pMutex); BAIL_ON_POSIX_SOCK_ERROR(dwError); bLocked = TRUE; nRead = recvfrom( pSocket->fd, pIoBuffer->pData + pIoBuffer->dwCurrentSize, dwBufSize, flags, (struct sockaddr*)&pIoBuffer->clientAddr, &dwSockAddrLen); if (nRead < 0) { dwError = LwErrnoToWin32Error(errno); BAIL_ON_POSIX_SOCK_ERROR(dwError); } pIoBuffer->addrLen = dwSockAddrLen; pIoBuffer->dwCurrentSize += nRead; pIoBuffer->dwTotalBytesTransferred += nRead; cleanup: if (bLocked) { VmDnsUnlockMutex(pSocket->pMutex); } return dwError; error: goto cleanup; }