Crypto++  5.6.5
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  CRYPTOPP_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_lastResult(0), 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  CRYPTOPP_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  // Fall through for non-fatal
118  case ERROR_BROKEN_PIPE:
119  case ERROR_HANDLE_EOF:
120  m_lastResult = 0;
121  m_eofReceived = true;
122  break;
123  case ERROR_IO_PENDING:
124  m_resultPending = true;
125  }
126  }
127  return !m_resultPending;
128 }
129 
131 {
132  if (m_resultPending)
133  container.AddHandle(m_event, CallStack("WindowsPipeReceiver::GetWaitObjects() - result pending", &callStack));
134  else if (!m_eofReceived)
135  container.SetNoWait(CallStack("WindowsPipeReceiver::GetWaitObjects() - result ready", &callStack));
136 }
137 
138 unsigned int WindowsPipeReceiver::GetReceiveResult()
139 {
140  if (m_resultPending)
141  {
142 #if defined(USE_WINDOWS8_API)
143  BOOL result = GetOverlappedResultEx(GetHandle(), &m_overlapped, &m_lastResult, INFINITE, FALSE);
144 #else
145  BOOL result = GetOverlappedResult(GetHandle(), &m_overlapped, &m_lastResult, FALSE);
146 #endif
147  if (result)
148  {
149  if (m_lastResult == 0)
150  m_eofReceived = true;
151  }
152  else
153  {
154  switch (GetLastError())
155  {
156  default:
157  CheckAndHandleError("GetOverlappedResult", false);
158  // Fall through for non-fatal
159  case ERROR_BROKEN_PIPE:
160  case ERROR_HANDLE_EOF:
161  m_lastResult = 0;
162  m_eofReceived = true;
163  }
164  }
165  m_resultPending = false;
166  }
167  return m_lastResult;
168 }
169 
170 // *************************************************************
171 
172 WindowsPipeSender::WindowsPipeSender()
173  : m_lastResult(0), m_resultPending(false)
174 {
175  m_event.AttachHandle(CreateEvent(NULL, true, false, NULL), true);
176  CheckAndHandleError("CreateEvent", m_event.HandleValid());
177  memset(&m_overlapped, 0, sizeof(m_overlapped));
178  m_overlapped.hEvent = m_event;
179 }
180 
181 void WindowsPipeSender::Send(const byte* buf, size_t bufLen)
182 {
183  DWORD written = 0;
184  const HANDLE h = GetHandle();
185  // don't queue too much at once, or we might use up non-paged memory
186  if (WriteFile(h, buf, UnsignedMin((DWORD)128*1024, bufLen), &written, &m_overlapped))
187  {
188  m_resultPending = false;
189  m_lastResult = written;
190  }
191  else
192  {
193  if (GetLastError() != ERROR_IO_PENDING)
194  CheckAndHandleError("WriteFile", false);
195 
196  m_resultPending = true;
197  }
198 }
199 
201 {
202  if (m_resultPending)
203  container.AddHandle(m_event, CallStack("WindowsPipeSender::GetWaitObjects() - result pending", &callStack));
204  else
205  container.SetNoWait(CallStack("WindowsPipeSender::GetWaitObjects() - result ready", &callStack));
206 }
207 
208 unsigned int WindowsPipeSender::GetSendResult()
209 {
210  if (m_resultPending)
211  {
212  const HANDLE h = GetHandle();
213 #if defined(USE_WINDOWS8_API)
214  BOOL result = GetOverlappedResultEx(h, &m_overlapped, &m_lastResult, INFINITE, FALSE);
215  CheckAndHandleError("GetOverlappedResultEx", result);
216 #else
217  BOOL result = GetOverlappedResult(h, &m_overlapped, &m_lastResult, FALSE);
218  CheckAndHandleError("GetOverlappedResult", result);
219 #endif
220  m_resultPending = false;
221  }
222  return m_lastResult;
223 }
224 
225 NAMESPACE_END
226 
227 #endif
Base class for all exceptions thrown by the library.
Definition: cryptlib.h:140
container of wait objects
Definition: wait.h:169
The operating system reported an error.
Definition: cryptlib.h:219
Library configuration file.
void GetWaitObjects(WaitObjectContainer &container, CallStack const &callStack)
Retrieves waitable objects.
Definition: winpipes.cpp:200
void GetWaitObjects(WaitObjectContainer &container, CallStack const &callStack)
Retrieves waitable objects.
Definition: winpipes.cpp:130
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:512
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:62
std::string IntToString(T value, unsigned int base=10)
Converts a value to a string.
Definition: misc.h:539
Crypto++ library namespace.
Windows Handle.
Definition: winpipes.h:16