Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

205 lines
4.5 KiB

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