cmDebuggerWindowsPipeConnection.cxx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmDebuggerWindowsPipeConnection.h"
  4. #include <algorithm>
  5. #include <cassert>
  6. #include <cstring>
  7. #include <stdexcept>
  8. #include <utility>
  9. namespace cmDebugger {
  10. #ifdef _WIN32
  11. DuplexPipe_WIN32::DuplexPipe_WIN32(HANDLE pipe)
  12. : hPipe(pipe)
  13. {
  14. readOp.Offset = readOp.OffsetHigh = 0;
  15. readOp.hEvent = CreateEvent(NULL, true, false, NULL);
  16. writeOp.Offset = readOp.OffsetHigh = 0;
  17. writeOp.hEvent = CreateEvent(NULL, true, false, NULL);
  18. }
  19. DuplexPipe_WIN32::~DuplexPipe_WIN32()
  20. {
  21. close();
  22. }
  23. size_t DuplexPipe_WIN32::read(void* buffer, size_t n)
  24. {
  25. if (hPipe != INVALID_HANDLE_VALUE) {
  26. readOp.Offset = readOp.OffsetHigh = 0;
  27. ResetEvent(readOp.hEvent);
  28. auto r = ReadFile(hPipe, buffer, n, NULL, &readOp);
  29. auto err = GetLastError();
  30. if (r || err == ERROR_IO_PENDING) {
  31. DWORD nRead = 0;
  32. if (GetOverlappedResult(hPipe, &readOp, &nRead, true)) {
  33. return nRead;
  34. }
  35. }
  36. }
  37. return 0;
  38. }
  39. bool DuplexPipe_WIN32::write(void const* buffer, size_t n)
  40. {
  41. if (hPipe != INVALID_HANDLE_VALUE) {
  42. writeOp.Offset = writeOp.OffsetHigh = 0;
  43. ResetEvent(writeOp.hEvent);
  44. auto w = WriteFile(hPipe, buffer, n, NULL, &writeOp);
  45. auto err = GetLastError();
  46. if (w || err == ERROR_IO_PENDING) {
  47. DWORD nWrite = 0;
  48. if (GetOverlappedResult(hPipe, &writeOp, &nWrite, true)) {
  49. return n == nWrite;
  50. }
  51. }
  52. }
  53. return false;
  54. }
  55. void DuplexPipe_WIN32::close()
  56. {
  57. CloseHandle(hPipe);
  58. hPipe = INVALID_HANDLE_VALUE;
  59. CloseHandle(readOp.hEvent);
  60. CloseHandle(writeOp.hEvent);
  61. readOp.hEvent = writeOp.hEvent = INVALID_HANDLE_VALUE;
  62. }
  63. bool DuplexPipe_WIN32::WaitForConnection()
  64. {
  65. auto connect = ConnectNamedPipe(hPipe, &readOp);
  66. auto err = GetLastError();
  67. if (!connect && err == ERROR_IO_PENDING) {
  68. DWORD ignored;
  69. if (GetOverlappedResult(hPipe, &readOp, &ignored, true)) {
  70. return true;
  71. }
  72. }
  73. return connect || err == ERROR_PIPE_CONNECTED;
  74. }
  75. cmDebuggerPipeConnection_WIN32::cmDebuggerPipeConnection_WIN32(
  76. std::string name)
  77. : PipeName(std::move(name))
  78. , pipes(nullptr)
  79. {
  80. }
  81. cmDebuggerPipeConnection_WIN32::~cmDebuggerPipeConnection_WIN32()
  82. {
  83. if (isOpen()) {
  84. pipes = nullptr;
  85. }
  86. }
  87. bool cmDebuggerPipeConnection_WIN32::StartListening(std::string& errorMessage)
  88. {
  89. bool result = true;
  90. auto hPipe = CreateNamedPipeA(
  91. PipeName.c_str(),
  92. PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
  93. PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_REJECT_REMOTE_CLIENTS, 1,
  94. 1024 * 16, 1024 * 16, NMPWAIT_USE_DEFAULT_WAIT, NULL);
  95. if (hPipe == INVALID_HANDLE_VALUE) {
  96. auto err = GetLastError();
  97. errorMessage = GetErrorMessage(err);
  98. result = false;
  99. }
  100. if (result) {
  101. pipes = std::make_unique<DuplexPipe_WIN32>(hPipe);
  102. }
  103. StartedListening.set_value();
  104. return result;
  105. }
  106. std::string cmDebuggerPipeConnection_WIN32::GetErrorMessage(DWORD errorCode)
  107. {
  108. LPSTR message = nullptr;
  109. DWORD size = FormatMessageA(
  110. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
  111. FORMAT_MESSAGE_IGNORE_INSERTS,
  112. nullptr, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  113. (LPSTR)&message, 0, nullptr);
  114. std::string errorMessage = "Internal Error with " + this->PipeName + ": " +
  115. std::string(message, size);
  116. LocalFree(message);
  117. return errorMessage;
  118. }
  119. std::shared_ptr<dap::Reader> cmDebuggerPipeConnection_WIN32::GetReader()
  120. {
  121. return std::static_pointer_cast<dap::Reader>(shared_from_this());
  122. }
  123. std::shared_ptr<dap::Writer> cmDebuggerPipeConnection_WIN32::GetWriter()
  124. {
  125. return std::static_pointer_cast<dap::Writer>(shared_from_this());
  126. }
  127. bool cmDebuggerPipeConnection_WIN32::isOpen()
  128. {
  129. return pipes != nullptr;
  130. }
  131. void cmDebuggerPipeConnection_WIN32::close()
  132. {
  133. CloseConnection();
  134. }
  135. void cmDebuggerPipeConnection_WIN32::CloseConnection()
  136. {
  137. if (isOpen()) {
  138. pipes->close();
  139. pipes = nullptr;
  140. }
  141. }
  142. void cmDebuggerPipeConnection_WIN32::WaitForConnection()
  143. {
  144. if (!isOpen()) {
  145. return;
  146. }
  147. if (pipes->WaitForConnection()) {
  148. return;
  149. }
  150. CloseConnection();
  151. }
  152. size_t cmDebuggerPipeConnection_WIN32::read(void* buffer, size_t n)
  153. {
  154. size_t result = 0;
  155. if (isOpen()) {
  156. result = pipes->read(buffer, n);
  157. if (result == 0) {
  158. CloseConnection();
  159. }
  160. }
  161. return result;
  162. }
  163. bool cmDebuggerPipeConnection_WIN32::write(void const* buffer, size_t n)
  164. {
  165. bool result = false;
  166. if (isOpen()) {
  167. result = pipes->write(buffer, n);
  168. if (!result) {
  169. CloseConnection();
  170. }
  171. }
  172. return result;
  173. }
  174. cmDebuggerPipeClient_WIN32::cmDebuggerPipeClient_WIN32(std::string name)
  175. : PipeName(std::move(name))
  176. {
  177. }
  178. cmDebuggerPipeClient_WIN32::~cmDebuggerPipeClient_WIN32()
  179. {
  180. close();
  181. }
  182. void cmDebuggerPipeClient_WIN32::WaitForConnection()
  183. {
  184. if (!isOpen()) {
  185. auto hPipe = CreateFileA(PipeName.c_str(), GENERIC_READ | GENERIC_WRITE, 0,
  186. NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
  187. if (hPipe == INVALID_HANDLE_VALUE) {
  188. auto err = GetLastError();
  189. throw std::runtime_error(std::string("CreateFile failed for pipe ") +
  190. GetErrorMessage(err));
  191. }
  192. pipes = std::make_unique<DuplexPipe_WIN32>(hPipe);
  193. }
  194. }
  195. std::string cmDebuggerPipeClient_WIN32::GetErrorMessage(DWORD errorCode)
  196. {
  197. LPSTR message = nullptr;
  198. DWORD size = FormatMessageA(
  199. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
  200. FORMAT_MESSAGE_IGNORE_INSERTS,
  201. nullptr, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  202. (LPSTR)&message, 0, nullptr);
  203. std::string errorMessage =
  204. this->PipeName + ": " + std::string(message, size);
  205. LocalFree(message);
  206. return errorMessage;
  207. }
  208. bool cmDebuggerPipeClient_WIN32::isOpen()
  209. {
  210. return pipes != nullptr;
  211. }
  212. void cmDebuggerPipeClient_WIN32::close()
  213. {
  214. if (isOpen()) {
  215. pipes->close();
  216. pipes = nullptr;
  217. }
  218. }
  219. size_t cmDebuggerPipeClient_WIN32::read(void* buffer, size_t n)
  220. {
  221. size_t result = 0;
  222. if (isOpen()) {
  223. result = pipes->read(buffer, n);
  224. if (result == 0) {
  225. close();
  226. }
  227. }
  228. return result;
  229. }
  230. bool cmDebuggerPipeClient_WIN32::write(void const* buffer, size_t n)
  231. {
  232. bool result = false;
  233. if (isOpen()) {
  234. result = pipes->write(buffer, n);
  235. if (!result) {
  236. close();
  237. }
  238. }
  239. return result;
  240. }
  241. #endif // _WIN32
  242. } // namespace cmDebugger