Team Fortress 2 Source Code as on 22/4/2020
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.

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