bool IIOCPEntry::TimeoutCheck (DWORDLONG dwNow, DWORDLONG dwTimeout) // TimeoutCheck // // Check to see if we need to cancel an operation in progress. // NOTE: We rely on our caller to lock appropriately. // // If we return TRUE, it means the caller should delete us. { if (m_dwOpStartTime == 0) return false; HANDLE hHandle = GetCompletionHandle(); if (hHandle == INVALID_HANDLE_VALUE) return false; DWORDLONG dwElapsed = dwNow - m_dwOpStartTime; if (dwElapsed <= dwTimeout) return false; if (m_iCurrentOp != opNone) { ::CancelIoEx(hHandle, &m_Overlapped); return false; } else return true; }
void CIOCP::DestroyWorker() { m_HandleIndex = 0; for( int i = 0 ; i < m_WorkerNum ; i++ ) PostQueuedCompletionStatus( GetCompletionHandle() , 0 , WORKER_DESTROY_KEY , NULL ); WaitForMultipleObjects( m_WorkerNum , m_hEvent , TRUE , INFINITE ); for( int i = 0 ; i < m_WorkerNum ; i++ ) CloseHandle( m_hEvent[i] ); return ; }
bool IIOCPEntry::BeginWrite (const CString &sData, CString *retsError) // BeginWrite // // Overlapped write on the given handle. Returns FALSE if we get an error. { // Must be in the proper state HANDLE hHandle = GetCompletionHandle(); if (hHandle == INVALID_HANDLE_VALUE || m_iCurrentOp != opNone) { if (retsError) *retsError = ERR_INVALID_STATE; return false; } m_iCurrentOp = opWrite; m_dwOpStartTime = sysGetTickCount64(); // If we don't have a buffer, then we're done. IMemoryBlock *pBuffer = GetBuffer(); if (pBuffer == NULL) { m_iCurrentOp = opNone; if (retsError) *retsError = ERR_INVALID_STATE; return false; } // Initialize operation utlMemSet(&m_Overlapped, sizeof(m_Overlapped)); // Let our subclasses know (this also initializes the buffer) OnBeginWrite(sData); // Write into the buffer DWORD lasterror = 0; if (!::WriteFile(hHandle, pBuffer->GetPointer(), pBuffer->GetLength(), NULL, &m_Overlapped)) lasterror = GetLastError(); // If IO is pending or we succeeded, then nothing to do--we will get an // event on the completion port. if (lasterror == ERROR_IO_PENDING || lasterror == 0) return true; // If another error or 0 bytes read, then we fail else { m_iCurrentOp = opNone; if (retsError) *retsError = strPattern(ERR_FILE_ERROR, lasterror); return false; } }
bool IIOCPEntry::BeginConnection (const CString &sAddress, DWORD dwPort, CString *retsError) // BeginConnection // // Overlapped connection to the given address. { // Must be in the proper state HANDLE hHandle = GetCompletionHandle(); if (hHandle == INVALID_HANDLE_VALUE || m_iCurrentOp != opNone) { if (retsError) *retsError = ERR_INVALID_STATE; return false; } m_iCurrentOp = opConnect; m_dwOpStartTime = sysGetTickCount64(); // Bind the socket before passing to ConnectEx. For some reason the API // does not do its own bind (probably so you can reuse sockets). SOCKADDR_IN LocalAddress; utlMemSet(&LocalAddress, sizeof(LocalAddress), 0); LocalAddress.sin_family = AF_INET; LocalAddress.sin_addr.s_addr = INADDR_ANY; LocalAddress.sin_port = 0; if (::bind((SOCKET)hHandle, (SOCKADDR *)&LocalAddress, sizeof(LocalAddress)) != 0) { m_iCurrentOp = opNone; if (retsError) *retsError = ERR_CANNOT_BIND; return false; } // Get the ConnectEx pointer GUID guidConnectEx = WSAID_CONNECTEX; LPFN_CONNECTEX pfnConnectEx = NULL; DWORD dwBytes; if (::WSAIoctl((SOCKET)hHandle, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidConnectEx, sizeof(guidConnectEx), &pfnConnectEx, sizeof(pfnConnectEx), &dwBytes, NULL, NULL) == SOCKET_ERROR) { m_iCurrentOp = opNone; if (retsError) *retsError = ERR_NOT_SUPPORTED; return false; } // Compose the destination address SOCKADDR_IN Address; if (!CSocket::ComposeAddress(sAddress, dwPort, &Address)) { m_iCurrentOp = opNone; if (retsError) *retsError = strPattern(ERR_INVALID_ADDRESS, sAddress, dwPort); return false; } // Initialize operation utlMemSet(&m_Overlapped, sizeof(m_Overlapped)); // Connect DWORD lasterror = 0; if (!pfnConnectEx((SOCKET)hHandle, (SOCKADDR *)&Address, sizeof(Address), NULL, 0, NULL, &m_Overlapped)) lasterror = ::WSAGetLastError(); // If IO is pending or we succeeded, then nothing to do--we will get an // event on the completion port. if (lasterror == ERROR_IO_PENDING || lasterror == 0) return true; // If another error or 0 bytes read, then we fail else { m_iCurrentOp = opNone; if (retsError) *retsError = strPattern(ERR_FILE_ERROR, lasterror); return false; } }