CMake Nightly Date Stamp
[kiteware-cmake.git] / Source / cmDebuggerWindowsPipeConnection.cxx
blob5f6f8484fe93563f9367211c25b82ba2e0558a75
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"
5 #include <algorithm>
6 #include <cassert>
7 #include <cstring>
8 #include <stdexcept>
9 #include <utility>
11 namespace cmDebugger {
13 #ifdef _WIN32
15 DuplexPipe_WIN32::DuplexPipe_WIN32(HANDLE pipe)
16 : hPipe(pipe)
18 readOp.Offset = readOp.OffsetHigh = 0;
19 readOp.hEvent = CreateEvent(NULL, true, false, NULL);
20 writeOp.Offset = readOp.OffsetHigh = 0;
21 writeOp.hEvent = CreateEvent(NULL, true, false, NULL);
24 DuplexPipe_WIN32::~DuplexPipe_WIN32()
26 close();
29 size_t DuplexPipe_WIN32::read(void* buffer, size_t n)
31 if (hPipe != INVALID_HANDLE_VALUE) {
32 readOp.Offset = readOp.OffsetHigh = 0;
33 ResetEvent(readOp.hEvent);
34 auto r = ReadFile(hPipe, buffer, n, NULL, &readOp);
35 auto err = GetLastError();
36 if (r || err == ERROR_IO_PENDING) {
37 DWORD nRead = 0;
38 if (GetOverlappedResult(hPipe, &readOp, &nRead, true)) {
39 return nRead;
44 return 0;
47 bool DuplexPipe_WIN32::write(void const* buffer, size_t n)
49 if (hPipe != INVALID_HANDLE_VALUE) {
50 writeOp.Offset = writeOp.OffsetHigh = 0;
51 ResetEvent(writeOp.hEvent);
52 auto w = WriteFile(hPipe, buffer, n, NULL, &writeOp);
53 auto err = GetLastError();
54 if (w || err == ERROR_IO_PENDING) {
55 DWORD nWrite = 0;
56 if (GetOverlappedResult(hPipe, &writeOp, &nWrite, true)) {
57 return n == nWrite;
62 return false;
65 void DuplexPipe_WIN32::close()
67 CloseHandle(hPipe);
68 hPipe = INVALID_HANDLE_VALUE;
69 CloseHandle(readOp.hEvent);
70 CloseHandle(writeOp.hEvent);
71 readOp.hEvent = writeOp.hEvent = INVALID_HANDLE_VALUE;
74 bool DuplexPipe_WIN32::WaitForConnection()
76 auto connect = ConnectNamedPipe(hPipe, &readOp);
77 auto err = GetLastError();
78 if (!connect && err == ERROR_IO_PENDING) {
79 DWORD ignored;
80 if (GetOverlappedResult(hPipe, &readOp, &ignored, true)) {
81 return true;
85 return connect || err == ERROR_PIPE_CONNECTED;
88 cmDebuggerPipeConnection_WIN32::cmDebuggerPipeConnection_WIN32(
89 std::string name)
90 : PipeName(std::move(name))
91 , pipes(nullptr)
95 cmDebuggerPipeConnection_WIN32::~cmDebuggerPipeConnection_WIN32()
97 if (isOpen()) {
98 pipes = nullptr;
102 bool cmDebuggerPipeConnection_WIN32::StartListening(std::string& errorMessage)
104 bool result = true;
106 auto hPipe = CreateNamedPipeA(
107 PipeName.c_str(),
108 PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
109 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_REJECT_REMOTE_CLIENTS, 1,
110 1024 * 16, 1024 * 16, NMPWAIT_USE_DEFAULT_WAIT, NULL);
112 if (hPipe == INVALID_HANDLE_VALUE) {
113 auto err = GetLastError();
114 errorMessage = GetErrorMessage(err);
115 result = false;
118 if (result) {
119 pipes = std::make_unique<DuplexPipe_WIN32>(hPipe);
122 StartedListening.set_value();
123 return result;
126 std::string cmDebuggerPipeConnection_WIN32::GetErrorMessage(DWORD errorCode)
128 LPSTR message = nullptr;
129 DWORD size = FormatMessageA(
130 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
131 FORMAT_MESSAGE_IGNORE_INSERTS,
132 nullptr, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
133 (LPSTR)&message, 0, nullptr);
134 std::string errorMessage = "Internal Error with " + this->PipeName + ": " +
135 std::string(message, size);
136 LocalFree(message);
137 return errorMessage;
140 std::shared_ptr<dap::Reader> cmDebuggerPipeConnection_WIN32::GetReader()
142 return std::static_pointer_cast<dap::Reader>(shared_from_this());
145 std::shared_ptr<dap::Writer> cmDebuggerPipeConnection_WIN32::GetWriter()
147 return std::static_pointer_cast<dap::Writer>(shared_from_this());
150 bool cmDebuggerPipeConnection_WIN32::isOpen()
152 return pipes != nullptr;
155 void cmDebuggerPipeConnection_WIN32::close()
157 CloseConnection();
160 void cmDebuggerPipeConnection_WIN32::CloseConnection()
162 if (isOpen()) {
163 pipes->close();
164 pipes = nullptr;
168 void cmDebuggerPipeConnection_WIN32::WaitForConnection()
170 if (!isOpen()) {
171 return;
174 if (pipes->WaitForConnection()) {
175 return;
178 CloseConnection();
181 size_t cmDebuggerPipeConnection_WIN32::read(void* buffer, size_t n)
183 size_t result = 0;
184 if (isOpen()) {
185 result = pipes->read(buffer, n);
186 if (result == 0) {
187 CloseConnection();
191 return result;
194 bool cmDebuggerPipeConnection_WIN32::write(void const* buffer, size_t n)
196 bool result = false;
197 if (isOpen()) {
198 result = pipes->write(buffer, n);
199 if (!result) {
200 CloseConnection();
204 return result;
207 cmDebuggerPipeClient_WIN32::cmDebuggerPipeClient_WIN32(std::string name)
208 : PipeName(std::move(name))
212 cmDebuggerPipeClient_WIN32::~cmDebuggerPipeClient_WIN32()
214 close();
217 void cmDebuggerPipeClient_WIN32::WaitForConnection()
219 if (!isOpen()) {
220 auto hPipe = CreateFileA(PipeName.c_str(), GENERIC_READ | GENERIC_WRITE, 0,
221 NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
222 if (hPipe == INVALID_HANDLE_VALUE) {
223 auto err = GetLastError();
224 throw std::runtime_error(std::string("CreateFile failed for pipe ") +
225 GetErrorMessage(err));
228 pipes = std::make_unique<DuplexPipe_WIN32>(hPipe);
232 std::string cmDebuggerPipeClient_WIN32::GetErrorMessage(DWORD errorCode)
234 LPSTR message = nullptr;
235 DWORD size = FormatMessageA(
236 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
237 FORMAT_MESSAGE_IGNORE_INSERTS,
238 nullptr, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
239 (LPSTR)&message, 0, nullptr);
240 std::string errorMessage =
241 this->PipeName + ": " + std::string(message, size);
242 LocalFree(message);
243 return errorMessage;
246 bool cmDebuggerPipeClient_WIN32::isOpen()
248 return pipes != nullptr;
251 void cmDebuggerPipeClient_WIN32::close()
253 if (isOpen()) {
254 pipes->close();
255 pipes = nullptr;
259 size_t cmDebuggerPipeClient_WIN32::read(void* buffer, size_t n)
261 size_t result = 0;
262 if (isOpen()) {
263 result = pipes->read(buffer, n);
264 if (result == 0) {
265 close();
269 return result;
272 bool cmDebuggerPipeClient_WIN32::write(void const* buffer, size_t n)
274 bool result = false;
275 if (isOpen()) {
276 result = pipes->write(buffer, n);
277 if (!result) {
278 close();
282 return result;
285 #endif // _WIN32
287 } // namespace cmDebugger