blob: 05874501546f910dc49626feda145ff135c9e91d [file] [log] [blame]
/* 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