1// winpipes.cpp - written and placed in the public domain by Wei Dai 2 3#include "pch.h" 4#include "winpipes.h" 5 6#ifdef WINDOWS_PIPES_AVAILABLE 7 8#include "wait.h" 9 10NAMESPACE_BEGIN(CryptoPP) 11 12WindowsHandle::WindowsHandle(HANDLE h, bool own) 13 : m_h(h), m_own(own) 14{ 15} 16 17WindowsHandle::~WindowsHandle() 18{ 19 if (m_own) 20 { 21 try 22 { 23 CloseHandle(); 24 } 25 catch (...) 26 { 27 } 28 } 29} 30 31bool WindowsHandle::HandleValid() const 32{ 33 return m_h && m_h != INVALID_HANDLE_VALUE; 34} 35 36void WindowsHandle::AttachHandle(HANDLE h, bool own) 37{ 38 if (m_own) 39 CloseHandle(); 40 41 m_h = h; 42 m_own = own; 43 HandleChanged(); 44} 45 46HANDLE WindowsHandle::DetachHandle() 47{ 48 HANDLE h = m_h; 49 m_h = INVALID_HANDLE_VALUE; 50 HandleChanged(); 51 return h; 52} 53 54void WindowsHandle::CloseHandle() 55{ 56 if (m_h != INVALID_HANDLE_VALUE) 57 { 58 ::CloseHandle(m_h); 59 m_h = INVALID_HANDLE_VALUE; 60 HandleChanged(); 61 } 62} 63 64// ******************************************************** 65 66void WindowsPipe::HandleError(const char *operation) const 67{ 68 DWORD err = GetLastError(); 69 throw Err(GetHandle(), operation, err); 70} 71 72WindowsPipe::Err::Err(HANDLE s, const std::string& operation, int error) 73 : OS_Error(IO_ERROR, "WindowsPipe: " + operation + " operation failed with error 0x" + IntToString(error, 16), operation, error) 74 , m_h(s) 75{ 76} 77 78// ************************************************************* 79 80WindowsPipeReceiver::WindowsPipeReceiver() 81 : m_resultPending(false), m_eofReceived(false) 82{ 83 m_event.AttachHandle(CreateEvent(NULL, true, false, NULL), true); 84 CheckAndHandleError("CreateEvent", m_event.HandleValid()); 85 memset(&m_overlapped, 0, sizeof(m_overlapped)); 86 m_overlapped.hEvent = m_event; 87} 88 89bool WindowsPipeReceiver::Receive(byte* buf, size_t bufLen) 90{ 91 assert(!m_resultPending && !m_eofReceived); 92 93 HANDLE h = GetHandle(); 94 // don't queue too much at once, or we might use up non-paged memory 95 if (ReadFile(h, buf, UnsignedMin((DWORD)128*1024, bufLen), &m_lastResult, &m_overlapped)) 96 { 97 if (m_lastResult == 0) 98 m_eofReceived = true; 99 } 100 else 101 { 102 switch (GetLastError()) 103 { 104 default: 105 CheckAndHandleError("ReadFile", false); 106 case ERROR_BROKEN_PIPE: 107 case ERROR_HANDLE_EOF: 108 m_lastResult = 0; 109 m_eofReceived = true; 110 break; 111 case ERROR_IO_PENDING: 112 m_resultPending = true; 113 } 114 } 115 return !m_resultPending; 116} 117 118void WindowsPipeReceiver::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack) 119{ 120 if (m_resultPending) 121 container.AddHandle(m_event, CallStack("WindowsPipeReceiver::GetWaitObjects() - result pending", &callStack)); 122 else if (!m_eofReceived) 123 container.SetNoWait(CallStack("WindowsPipeReceiver::GetWaitObjects() - result ready", &callStack)); 124} 125 126unsigned int WindowsPipeReceiver::GetReceiveResult() 127{ 128 if (m_resultPending) 129 { 130 HANDLE h = GetHandle(); 131 if (GetOverlappedResult(h, &m_overlapped, &m_lastResult, false)) 132 { 133 if (m_lastResult == 0) 134 m_eofReceived = true; 135 } 136 else 137 { 138 switch (GetLastError()) 139 { 140 default: 141 CheckAndHandleError("GetOverlappedResult", false); 142 case ERROR_BROKEN_PIPE: 143 case ERROR_HANDLE_EOF: 144 m_lastResult = 0; 145 m_eofReceived = true; 146 } 147 } 148 m_resultPending = false; 149 } 150 return m_lastResult; 151} 152 153// ************************************************************* 154 155WindowsPipeSender::WindowsPipeSender() 156 : m_resultPending(false), m_lastResult(0) 157{ 158 m_event.AttachHandle(CreateEvent(NULL, true, false, NULL), true); 159 CheckAndHandleError("CreateEvent", m_event.HandleValid()); 160 memset(&m_overlapped, 0, sizeof(m_overlapped)); 161 m_overlapped.hEvent = m_event; 162} 163 164void WindowsPipeSender::Send(const byte* buf, size_t bufLen) 165{ 166 DWORD written = 0; 167 HANDLE h = GetHandle(); 168 // don't queue too much at once, or we might use up non-paged memory 169 if (WriteFile(h, buf, UnsignedMin((DWORD)128*1024, bufLen), &written, &m_overlapped)) 170 { 171 m_resultPending = false; 172 m_lastResult = written; 173 } 174 else 175 { 176 if (GetLastError() != ERROR_IO_PENDING) 177 CheckAndHandleError("WriteFile", false); 178 179 m_resultPending = true; 180 } 181} 182 183void WindowsPipeSender::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack) 184{ 185 if (m_resultPending) 186 container.AddHandle(m_event, CallStack("WindowsPipeSender::GetWaitObjects() - result pending", &callStack)); 187 else 188 container.SetNoWait(CallStack("WindowsPipeSender::GetWaitObjects() - result ready", &callStack)); 189} 190 191unsigned int WindowsPipeSender::GetSendResult() 192{ 193 if (m_resultPending) 194 { 195 HANDLE h = GetHandle(); 196 BOOL result = GetOverlappedResult(h, &m_overlapped, &m_lastResult, false); 197 CheckAndHandleError("GetOverlappedResult", result); 198 m_resultPending = false; 199 } 200 return m_lastResult; 201} 202 203NAMESPACE_END 204 205#endif 206