// 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