/* 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 #include #include #include #include #include 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 cmDebuggerPipeConnection_POSIX::GetReader() { return std::static_pointer_cast(shared_from_this()); } std::shared_ptr cmDebuggerPipeConnection_POSIX::GetWriter() { return std::static_pointer_cast(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(::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(::write(rw_pipe, buffer, n)); if (count < 0) { close(); } } return count > 0; } #endif // !_WIN32 } // namespace cmDebugger