Crypto++
winpipes.cpp
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 
10 NAMESPACE_BEGIN(CryptoPP)
11 
12 WindowsHandle::WindowsHandle(HANDLE h, bool own)
13  : m_h(h), m_own(own)
14 {
15 }
16 
17 WindowsHandle::~WindowsHandle()
18 {
19  if (m_own)
20  {
21  try
22  {
23  CloseHandle();
24  }
25  catch (...)
26  {
27  }
28  }
29 }
30 
31 bool WindowsHandle::HandleValid() const
32 {
33  return m_h && m_h != INVALID_HANDLE_VALUE;
34 }
35 
36 void 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 
46 HANDLE WindowsHandle::DetachHandle()
47 {
48  HANDLE h = m_h;
49  m_h = INVALID_HANDLE_VALUE;
50  HandleChanged();
51  return h;
52 }
53 
54 void 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 
66 void WindowsPipe::HandleError(const char *operation) const
67 {
68  DWORD err = GetLastError();
69  throw Err(GetHandle(), operation, err);
70 }
71 
72 WindowsPipe::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 
80 WindowsPipeReceiver::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 
89 bool 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 
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 
126 unsigned 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 
155 WindowsPipeSender::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 
164 void 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 
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 
191 unsigned 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 
203 NAMESPACE_END
204 
205 #endif