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 "config.h"
5 
6 #if !defined(NO_OS_DEPENDENCE) && defined(WINDOWS_PIPES_AVAILABLE)
7 
8 #include "winpipes.h"
9 #include "wait.h"
10 
11 // Windows 8, Windows Server 2012, and Windows Phone 8.1 need <synchapi.h> and <ioapiset.h>
12 #if defined(CRYPTOPP_WIN32_AVAILABLE)
13 # if ((WINVER >= 0x0602 /*_WIN32_WINNT_WIN8*/) || (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/))
14 # include <synchapi.h>
15 # include <ioapiset.h>
16 # define USE_WINDOWS8_API
17 # endif
18 #endif
19 
20 NAMESPACE_BEGIN(CryptoPP)
21 
22 WindowsHandle::WindowsHandle(HANDLE h, bool own)
23  : m_h(h), m_own(own)
24 {
25 }
26 
27 WindowsHandle::~WindowsHandle()
28 {
29  if (m_own)
30  {
31  try
32  {
33  CloseHandle();
34  }
35  catch (const Exception&)
36  {
37  assert(0);
38  }
39  }
40 }
41 
42 bool WindowsHandle::HandleValid() const
43 {
44  return m_h && m_h != INVALID_HANDLE_VALUE;
45 }
46 
47 void WindowsHandle::AttachHandle(HANDLE h, bool own)
48 {
49  if (m_own)
50  CloseHandle();
51 
52  m_h = h;
53  m_own = own;
54  HandleChanged();
55 }
56 
57 HANDLE WindowsHandle::DetachHandle()
58 {
59  HANDLE h = m_h;
60  m_h = INVALID_HANDLE_VALUE;
61  HandleChanged();
62  return h;
63 }
64 
65 void WindowsHandle::CloseHandle()
66 {
67  if (m_h != INVALID_HANDLE_VALUE)
68  {
69  ::CloseHandle(m_h);
70  m_h = INVALID_HANDLE_VALUE;
71  HandleChanged();
72  }
73 }
74 
75 // ********************************************************
76 
77 void WindowsPipe::HandleError(const char *operation) const
78 {
79  DWORD err = GetLastError();
80  throw Err(GetHandle(), operation, err);
81 }
82 
83 WindowsPipe::Err::Err(HANDLE s, const std::string& operation, int error)
84  : OS_Error(IO_ERROR, "WindowsPipe: " + operation + " operation failed with error 0x" + IntToString(error, 16), operation, error)
85  , m_h(s)
86 {
87 }
88 
89 // *************************************************************
90 
91 WindowsPipeReceiver::WindowsPipeReceiver()
92  : m_resultPending(false), m_eofReceived(false)
93 {
94  m_event.AttachHandle(CreateEvent(NULL, true, false, NULL), true);
95  CheckAndHandleError("CreateEvent", m_event.HandleValid());
96  memset(&m_overlapped, 0, sizeof(m_overlapped));
97  m_overlapped.hEvent = m_event;
98 }
99 
100 bool WindowsPipeReceiver::Receive(byte* buf, size_t bufLen)
101 {
102  assert(!m_resultPending && !m_eofReceived);
103 
104  const HANDLE h = GetHandle();
105  // don't queue too much at once, or we might use up non-paged memory
106  if (ReadFile(h, buf, UnsignedMin((DWORD)128*1024, bufLen), &m_lastResult, &m_overlapped))
107  {
108  if (m_lastResult == 0)
109  m_eofReceived = true;
110  }
111  else
112  {
113  switch (GetLastError())
114  {
115  default:
116  CheckAndHandleError("ReadFile", false);
117  case ERROR_BROKEN_PIPE:
118  case ERROR_HANDLE_EOF:
119  m_lastResult = 0;
120  m_eofReceived = true;
121  break;
122  case ERROR_IO_PENDING:
123  m_resultPending = true;
124  }
125  }
126  return !m_resultPending;
127 }
128 
130 {
131  if (m_resultPending)
132  container.AddHandle(m_event, CallStack("WindowsPipeReceiver::GetWaitObjects() - result pending", &callStack));
133  else if (!m_eofReceived)
134  container.SetNoWait(CallStack("WindowsPipeReceiver::GetWaitObjects() - result ready", &callStack));
135 }
136 
137 unsigned int WindowsPipeReceiver::GetReceiveResult()
138 {
139  if (m_resultPending)
140  {
141 #if defined(USE_WINDOWS8_API)
142  BOOL result = GetOverlappedResultEx(GetHandle(), &m_overlapped, &m_lastResult, INFINITE, FALSE);
143 #else
144  BOOL result = GetOverlappedResult(GetHandle(), &m_overlapped, &m_lastResult, FALSE);
145 #endif
146  if (result)
147  {
148  if (m_lastResult == 0)
149  m_eofReceived = true;
150  }
151  else
152  {
153  switch (GetLastError())
154  {
155  default:
156  CheckAndHandleError("GetOverlappedResult", false);
157  case ERROR_BROKEN_PIPE:
158  case ERROR_HANDLE_EOF:
159  m_lastResult = 0;
160  m_eofReceived = true;
161  }
162  }
163  m_resultPending = false;
164  }
165  return m_lastResult;
166 }
167 
168 // *************************************************************
169 
170 WindowsPipeSender::WindowsPipeSender()
171  : m_resultPending(false), m_lastResult(0)
172 {
173  m_event.AttachHandle(CreateEvent(NULL, true, false, NULL), true);
174  CheckAndHandleError("CreateEvent", m_event.HandleValid());
175  memset(&m_overlapped, 0, sizeof(m_overlapped));
176  m_overlapped.hEvent = m_event;
177 }
178 
179 void WindowsPipeSender::Send(const byte* buf, size_t bufLen)
180 {
181  DWORD written = 0;
182  const HANDLE h = GetHandle();
183  // don't queue too much at once, or we might use up non-paged memory
184  if (WriteFile(h, buf, UnsignedMin((DWORD)128*1024, bufLen), &written, &m_overlapped))
185  {
186  m_resultPending = false;
187  m_lastResult = written;
188  }
189  else
190  {
191  if (GetLastError() != ERROR_IO_PENDING)
192  CheckAndHandleError("WriteFile", false);
193 
194  m_resultPending = true;
195  }
196 }
197 
199 {
200  if (m_resultPending)
201  container.AddHandle(m_event, CallStack("WindowsPipeSender::GetWaitObjects() - result pending", &callStack));
202  else
203  container.SetNoWait(CallStack("WindowsPipeSender::GetWaitObjects() - result ready", &callStack));
204 }
205 
206 unsigned int WindowsPipeSender::GetSendResult()
207 {
208  if (m_resultPending)
209  {
210  const HANDLE h = GetHandle();
211 #if defined(USE_WINDOWS8_API)
212  BOOL result = GetOverlappedResultEx(h, &m_overlapped, &m_lastResult, INFINITE, FALSE);
213  CheckAndHandleError("GetOverlappedResultEx", result);
214 #else
215  BOOL result = GetOverlappedResult(h, &m_overlapped, &m_lastResult, FALSE);
216  CheckAndHandleError("GetOverlappedResult", result);
217 #endif
218  m_resultPending = false;
219  }
220  return m_lastResult;
221 }
222 
223 NAMESPACE_END
224 
225 #endif
Base class for all exceptions thrown by the library.
Definition: cryptlib.h:139
container of wait objects
Definition: wait.h:169
The operating system reported an error.
Definition: cryptlib.h:217
Library configuration file.
void GetWaitObjects(WaitObjectContainer &container, CallStack const &callStack)
Retrieves waitable objects.
Definition: winpipes.cpp:198
void GetWaitObjects(WaitObjectContainer &container, CallStack const &callStack)
Retrieves waitable objects.
Definition: winpipes.cpp:129
bool Receive(byte *buf, size_t bufLen)
receive data from network source, returns whether result is immediately available ...
Definition: winpipes.cpp:100
const T1 UnsignedMin(const T1 &a, const T2 &b)
Safe comparison of values that could be neagtive and incorrectly promoted.
Definition: misc.h:503
std::string IntToString(T value, unsigned int base=10)
Converts a value to a string.
Definition: misc.h:530
Crypto++ library namespace.
Windows Handle.
Definition: winpipes.h:16