You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
205 lines
4.5 KiB
205 lines
4.5 KiB
// 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
|
|
|