Crypto++  5.6.3
Free C++ class library of cryptographic schemes
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 (const Exception&)
26  {
27  assert(0);
28  }
29  }
30 }
31 
32 bool WindowsHandle::HandleValid() const
33 {
34  return m_h && m_h != INVALID_HANDLE_VALUE;
35 }
36 
37 void WindowsHandle::AttachHandle(HANDLE h, bool own)
38 {
39  if (m_own)
40  CloseHandle();
41 
42  m_h = h;
43  m_own = own;
44  HandleChanged();
45 }
46 
47 HANDLE WindowsHandle::DetachHandle()
48 {
49  HANDLE h = m_h;
50  m_h = INVALID_HANDLE_VALUE;
51  HandleChanged();
52  return h;
53 }
54 
55 void WindowsHandle::CloseHandle()
56 {
57  if (m_h != INVALID_HANDLE_VALUE)
58  {
59  ::CloseHandle(m_h);
60  m_h = INVALID_HANDLE_VALUE;
61  HandleChanged();
62  }
63 }
64 
65 // ********************************************************
66 
67 void WindowsPipe::HandleError(const char *operation) const
68 {
69  DWORD err = GetLastError();
70  throw Err(GetHandle(), operation, err);
71 }
72 
73 WindowsPipe::Err::Err(HANDLE s, const std::string& operation, int error)
74  : OS_Error(IO_ERROR, "WindowsPipe: " + operation + " operation failed with error 0x" + IntToString(error, 16), operation, error)
75  , m_h(s)
76 {
77 }
78 
79 // *************************************************************
80 
81 WindowsPipeReceiver::WindowsPipeReceiver()
82  : m_resultPending(false), m_eofReceived(false)
83 {
84  m_event.AttachHandle(CreateEvent(NULL, true, false, NULL), true);
85  CheckAndHandleError("CreateEvent", m_event.HandleValid());
86  memset(&m_overlapped, 0, sizeof(m_overlapped));
87  m_overlapped.hEvent = m_event;
88 }
89 
90 bool WindowsPipeReceiver::Receive(byte* buf, size_t bufLen)
91 {
92  assert(!m_resultPending && !m_eofReceived);
93 
94  const HANDLE h = GetHandle();
95  // don't queue too much at once, or we might use up non-paged memory
96  if (ReadFile(h, buf, UnsignedMin((DWORD)128*1024, bufLen), &m_lastResult, &m_overlapped))
97  {
98  if (m_lastResult == 0)
99  m_eofReceived = true;
100  }
101  else
102  {
103  switch (GetLastError())
104  {
105  default:
106  CheckAndHandleError("ReadFile", false);
107  case ERROR_BROKEN_PIPE:
108  case ERROR_HANDLE_EOF:
109  m_lastResult = 0;
110  m_eofReceived = true;
111  break;
112  case ERROR_IO_PENDING:
113  m_resultPending = true;
114  }
115  }
116  return !m_resultPending;
117 }
118 
119 void WindowsPipeReceiver::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack)
120 {
121  if (m_resultPending)
122  container.AddHandle(m_event, CallStack("WindowsPipeReceiver::GetWaitObjects() - result pending", &callStack));
123  else if (!m_eofReceived)
124  container.SetNoWait(CallStack("WindowsPipeReceiver::GetWaitObjects() - result ready", &callStack));
125 }
126 
127 unsigned int WindowsPipeReceiver::GetReceiveResult()
128 {
129  if (m_resultPending)
130  {
131  const HANDLE h = GetHandle();
132  if (GetOverlappedResult(h, &m_overlapped, &m_lastResult, false))
133  {
134  if (m_lastResult == 0)
135  m_eofReceived = true;
136  }
137  else
138  {
139  switch (GetLastError())
140  {
141  default:
142  CheckAndHandleError("GetOverlappedResult", false);
143  case ERROR_BROKEN_PIPE:
144  case ERROR_HANDLE_EOF:
145  m_lastResult = 0;
146  m_eofReceived = true;
147  }
148  }
149  m_resultPending = false;
150  }
151  return m_lastResult;
152 }
153 
154 // *************************************************************
155 
156 WindowsPipeSender::WindowsPipeSender()
157  : m_resultPending(false), m_lastResult(0)
158 {
159  m_event.AttachHandle(CreateEvent(NULL, true, false, NULL), true);
160  CheckAndHandleError("CreateEvent", m_event.HandleValid());
161  memset(&m_overlapped, 0, sizeof(m_overlapped));
162  m_overlapped.hEvent = m_event;
163 }
164 
165 void WindowsPipeSender::Send(const byte* buf, size_t bufLen)
166 {
167  DWORD written = 0;
168  const HANDLE h = GetHandle();
169  // don't queue too much at once, or we might use up non-paged memory
170  if (WriteFile(h, buf, UnsignedMin((DWORD)128*1024, bufLen), &written, &m_overlapped))
171  {
172  m_resultPending = false;
173  m_lastResult = written;
174  }
175  else
176  {
177  if (GetLastError() != ERROR_IO_PENDING)
178  CheckAndHandleError("WriteFile", false);
179 
180  m_resultPending = true;
181  }
182 }
183 
184 void WindowsPipeSender::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack)
185 {
186  if (m_resultPending)
187  container.AddHandle(m_event, CallStack("WindowsPipeSender::GetWaitObjects() - result pending", &callStack));
188  else
189  container.SetNoWait(CallStack("WindowsPipeSender::GetWaitObjects() - result ready", &callStack));
190 }
191 
192 unsigned int WindowsPipeSender::GetSendResult()
193 {
194  if (m_resultPending)
195  {
196  const HANDLE h = GetHandle();
197  BOOL result = GetOverlappedResult(h, &m_overlapped, &m_lastResult, false);
198  CheckAndHandleError("GetOverlappedResult", result);
199  m_resultPending = false;
200  }
201  return m_lastResult;
202 }
203 
204 NAMESPACE_END
205 
206 #endif
Base class for all exceptions thrown by the library.
Definition: cryptlib.h:139
container of wait objects
Definition: wait.h:151
The operating system reported an error.
Definition: cryptlib.h:217
const T1 UnsignedMin(const T1 &a, const T2 &b)
Safe comparison of values that could be neagtive and incorrectly promoted.
Definition: misc.h:433
std::string IntToString(T value, unsigned int base=10)
Converts a value to a string.
Definition: misc.h:460
Crypto++ library namespace.