| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| file Copyright.txt or https://cmake.org/licensing for details. */ |
| #include "cmDebuggerPosixPipeConnection.h" |
| |
| #include <cerrno> |
| #include <cstring> |
| #include <stdexcept> |
| #include <utility> |
| |
| #include <unistd.h> |
| |
| #include <sys/socket.h> |
| |
| namespace cmDebugger { |
| |
| #ifndef _WIN32 |
| |
| cmDebuggerPipeConnection_POSIX::cmDebuggerPipeConnection_POSIX( |
| std::string name) |
| : PipeName(std::move(name)) |
| { |
| addr.sun_path[0] = '\0'; |
| } |
| |
| cmDebuggerPipeConnection_POSIX::~cmDebuggerPipeConnection_POSIX() |
| { |
| if (isOpen()) { |
| close(); |
| } |
| } |
| |
| bool cmDebuggerPipeConnection_POSIX::StartListening(std::string& errorMessage) |
| { |
| listen_fd = socket(AF_UNIX, SOCK_STREAM, 0); |
| if (listen_fd < 0) { |
| errorMessage = "Failed to create socket: "; |
| errorMessage += strerror(errno); |
| return false; |
| } |
| |
| addr.sun_family = AF_UNIX; |
| strncpy(addr.sun_path, PipeName.c_str(), sizeof(addr.sun_path)); |
| addr.sun_path[sizeof(addr.sun_path) - 1] = '\0'; |
| if (bind(listen_fd, (sockaddr*)&addr, sizeof(addr)) == -1) { |
| errorMessage = "Failed to bind name '"; |
| errorMessage += addr.sun_path; |
| errorMessage += "' to socket: "; |
| errorMessage += strerror(errno); |
| close_listen(); |
| return false; |
| } |
| |
| if (listen(listen_fd, 1) == -1) { |
| errorMessage = "Failed to listen on socket: "; |
| errorMessage += strerror(errno); |
| close_listen(); |
| return false; |
| } |
| |
| StartedListening.set_value(); |
| return true; |
| } |
| |
| std::shared_ptr<dap::Reader> cmDebuggerPipeConnection_POSIX::GetReader() |
| { |
| return std::static_pointer_cast<dap::Reader>(shared_from_this()); |
| } |
| |
| std::shared_ptr<dap::Writer> cmDebuggerPipeConnection_POSIX::GetWriter() |
| { |
| return std::static_pointer_cast<dap::Writer>(shared_from_this()); |
| } |
| |
| bool cmDebuggerPipeConnection_POSIX::isOpen() |
| { |
| return rw_pipe >= 0; |
| } |
| |
| void cmDebuggerPipeConnection_POSIX::close() |
| { |
| close_listen(); |
| ::close(rw_pipe); |
| rw_pipe = -1; |
| } |
| |
| void cmDebuggerPipeConnection_POSIX::close_listen() |
| { |
| if (strlen(addr.sun_path) > 0) { |
| unlink(addr.sun_path); |
| addr.sun_path[0] = '\0'; |
| } |
| ::close(listen_fd); |
| listen_fd = -1; |
| } |
| |
| void cmDebuggerPipeConnection_POSIX::WaitForConnection() |
| { |
| sockaddr_un laddr; |
| socklen_t len = sizeof(laddr); |
| rw_pipe = accept(listen_fd, (sockaddr*)&laddr, &len); |
| if (rw_pipe < 0) { |
| close(); |
| return; |
| } |
| |
| close_listen(); // no longer need the listen resources |
| } |
| |
| size_t cmDebuggerPipeConnection_POSIX::read(void* buffer, size_t n) |
| { |
| size_t result = 0; |
| if (rw_pipe >= 0) { |
| result = ::read(rw_pipe, buffer, n); |
| if (result == 0) { |
| close(); |
| } |
| } |
| |
| return result; |
| } |
| |
| bool cmDebuggerPipeConnection_POSIX::write(void const* buffer, size_t n) |
| { |
| bool result = false; |
| if (rw_pipe >= 0) { |
| result = ::write(rw_pipe, buffer, n) >= 0; |
| if (!result) { |
| close(); |
| } |
| } |
| |
| return result; |
| } |
| |
| cmDebuggerPipeClient_POSIX::cmDebuggerPipeClient_POSIX(std::string name) |
| : PipeName(std::move(name)) |
| { |
| } |
| |
| cmDebuggerPipeClient_POSIX::~cmDebuggerPipeClient_POSIX() |
| { |
| close(); |
| } |
| |
| void cmDebuggerPipeClient_POSIX::WaitForConnection() |
| { |
| rw_pipe = socket(AF_UNIX, SOCK_STREAM, 0); |
| if (rw_pipe < 0) { |
| throw std::runtime_error(std::string("Failed to create socket: ") + |
| strerror(errno)); |
| } |
| |
| sockaddr_un addr; |
| addr.sun_family = AF_UNIX; |
| strncpy(addr.sun_path, PipeName.c_str(), sizeof(addr.sun_path)); |
| addr.sun_path[sizeof(addr.sun_path) - 1] = '\0'; |
| if (connect(rw_pipe, (sockaddr*)&addr, sizeof(addr)) == -1) { |
| close(); |
| throw std::runtime_error( |
| std::string("Failed to connect path to socket: ") + strerror(errno)); |
| } |
| } |
| |
| bool cmDebuggerPipeClient_POSIX::isOpen() |
| { |
| return rw_pipe >= 0; |
| } |
| |
| void cmDebuggerPipeClient_POSIX::close() |
| { |
| if (isOpen()) { |
| ::close(rw_pipe); |
| rw_pipe = -1; |
| } |
| } |
| |
| size_t cmDebuggerPipeClient_POSIX::read(void* buffer, size_t n) |
| { |
| int count = 0; |
| if (isOpen()) { |
| count = static_cast<int>(::read(rw_pipe, buffer, n)); |
| if (count == 0) { |
| close(); |
| } |
| } |
| |
| return count; |
| } |
| |
| bool cmDebuggerPipeClient_POSIX::write(void const* buffer, size_t n) |
| { |
| int count = 0; |
| if (isOpen()) { |
| count = static_cast<int>(::write(rw_pipe, buffer, n)); |
| if (count < 0) { |
| close(); |
| } |
| } |
| |
| return count > 0; |
| } |
| |
| #endif // !_WIN32 |
| |
| } // namespace cmDebugger |