// winpipes.cpp - written and placed in the public domain by Wei Dai #include "pch.h" #include "winpipes.h" #ifdef WINDOWS_PIPES_AVAILABLE #include "wait.h" NAMESPACE_BEGIN(CryptoPP) WindowsHandle::WindowsHandle(HANDLE h, bool own) : m_h(h), m_own(own) { } WindowsHandle::~WindowsHandle() { if (m_own) { try { CloseHandle(); } catch (...) { } } } bool WindowsHandle::HandleValid() const { return m_h && m_h != INVALID_HANDLE_VALUE; } void WindowsHandle::AttachHandle(HANDLE h, bool own) { if (m_own) CloseHandle(); m_h = h; m_own = own; HandleChanged(); } HANDLE WindowsHandle::DetachHandle() { HANDLE h = m_h; m_h = INVALID_HANDLE_VALUE; HandleChanged(); return h; } void WindowsHandle::CloseHandle() { if (m_h != INVALID_HANDLE_VALUE) { ::CloseHandle(m_h); m_h = INVALID_HANDLE_VALUE; HandleChanged(); } } // ******************************************************** void WindowsPipe::HandleError(const char *operation) const { DWORD err = GetLastError(); throw Err(GetHandle(), operation, err); } WindowsPipe::Err::Err(HANDLE s, const std::string& operation, int error) : OS_Error(IO_ERROR, "WindowsPipe: " + operation + " operation failed with error 0x" + IntToString(error, 16), operation, error) , m_h(s) { } // ************************************************************* WindowsPipeReceiver::WindowsPipeReceiver() : m_resultPending(false), m_eofReceived(false) { m_event.AttachHandle(CreateEvent(NULL, true, false, NULL), true); CheckAndHandleError("CreateEvent", m_event.HandleValid()); memset(&m_overlapped, 0, sizeof(m_overlapped)); m_overlapped.hEvent = m_event; } bool WindowsPipeReceiver::Receive(byte* buf, size_t bufLen) { assert(!m_resultPending && !m_eofReceived); HANDLE h = GetHandle(); // don't queue too much at once, or we might use up non-paged memory if (ReadFile(h, buf, UnsignedMin((DWORD)128*1024, bufLen), &m_lastResult, &m_overlapped)) { if (m_lastResult == 0) m_eofReceived = true; } else { switch (GetLastError()) { default: CheckAndHandleError("ReadFile", false); case ERROR_BROKEN_PIPE: case ERROR_HANDLE_EOF: m_lastResult = 0; m_eofReceived = true; break; case ERROR_IO_PENDING: m_resultPending = true; } } return !m_resultPending; } void WindowsPipeReceiver::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack) { if (m_resultPending) container.AddHandle(m_event, CallStack("WindowsPipeReceiver::GetWaitObjects() - result pending", &callStack)); else if (!m_eofReceived) container.SetNoWait(CallStack("WindowsPipeReceiver::GetWaitObjects() - result ready", &callStack)); } unsigned int WindowsPipeReceiver::GetReceiveResult() { if (m_resultPending) { HANDLE h = GetHandle(); if (GetOverlappedResult(h, &m_overlapped, &m_lastResult, false)) { if (m_lastResult == 0) m_eofReceived = true; } else { switch (GetLastError()) { default: CheckAndHandleError("GetOverlappedResult", false); case ERROR_BROKEN_PIPE: case ERROR_HANDLE_EOF: m_lastResult = 0; m_eofReceived = true; } } m_resultPending = false; } return m_lastResult; } // ************************************************************* WindowsPipeSender::WindowsPipeSender() : m_resultPending(false), m_lastResult(0) { m_event.AttachHandle(CreateEvent(NULL, true, false, NULL), true); CheckAndHandleError("CreateEvent", m_event.HandleValid()); memset(&m_overlapped, 0, sizeof(m_overlapped)); m_overlapped.hEvent = m_event; } void WindowsPipeSender::Send(const byte* buf, size_t bufLen) { DWORD written = 0; HANDLE h = GetHandle(); // don't queue too much at once, or we might use up non-paged memory if (WriteFile(h, buf, UnsignedMin((DWORD)128*1024, bufLen), &written, &m_overlapped)) { m_resultPending = false; m_lastResult = written; } else { if (GetLastError() != ERROR_IO_PENDING) CheckAndHandleError("WriteFile", false); m_resultPending = true; } } void WindowsPipeSender::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack) { if (m_resultPending) container.AddHandle(m_event, CallStack("WindowsPipeSender::GetWaitObjects() - result pending", &callStack)); else container.SetNoWait(CallStack("WindowsPipeSender::GetWaitObjects() - result ready", &callStack)); } unsigned int WindowsPipeSender::GetSendResult() { if (m_resultPending) { HANDLE h = GetHandle(); BOOL result = GetOverlappedResult(h, &m_overlapped, &m_lastResult, false); CheckAndHandleError("GetOverlappedResult", result); m_resultPending = false; } return m_lastResult; } NAMESPACE_END #endif