#include "connection.h" #include #include #include #include #include #include #include #include namespace discord_rpc { int GetProcessId() { return ::getpid(); } struct BaseConnectionUnix : public BaseConnection { int sock { -1 }; }; static BaseConnectionUnix Connection; static sockaddr_un PipeAddr {}; #ifdef MSG_NOSIGNAL static int MsgFlags = MSG_NOSIGNAL; #else static int MsgFlags = 0; #endif static const char *GetTempPath() { const char *temp = getenv("XDG_RUNTIME_DIR"); temp = temp ? temp : getenv("TMPDIR"); temp = temp ? temp : getenv("TMP"); temp = temp ? temp : getenv("TEMP"); temp = temp ? temp : "/tmp"; return temp; } /*static*/ BaseConnection *BaseConnection::Create() { PipeAddr.sun_family = AF_UNIX; return &Connection; } /*static*/ void BaseConnection::Destroy(BaseConnection *&c) { auto self = reinterpret_cast(c); self->Close(); c = nullptr; } bool BaseConnection::Open() { const char *tempPath = GetTempPath(); auto self = reinterpret_cast(this); self->sock = socket(AF_UNIX, SOCK_STREAM, 0); if (self->sock == -1) { return false; } fcntl(self->sock, F_SETFL, O_NONBLOCK); #ifdef SO_NOSIGPIPE int optval = 1; setsockopt(self->sock, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)); #endif for (int pipeNum = 0; pipeNum < 10; ++pipeNum) { snprintf( PipeAddr.sun_path, sizeof(PipeAddr.sun_path), "%s/discord-ipc-%d", tempPath, pipeNum); int err = connect(self->sock, reinterpret_cast(&PipeAddr), sizeof(PipeAddr)); if (err == 0) { self->isOpen = true; return true; } } self->Close(); return false; } bool BaseConnection::Close() { auto self = reinterpret_cast(this); if (self->sock == -1) { return false; } close(self->sock); self->sock = -1; self->isOpen = false; return true; } bool BaseConnection::Write(const void *data, size_t length) { auto self = reinterpret_cast(this); if (self->sock == -1) { return false; } ssize_t sentBytes = send(self->sock, data, length, MsgFlags); if (sentBytes < 0) { Close(); } return sentBytes == static_cast(length); } bool BaseConnection::Read(void *data, size_t length) { auto self = reinterpret_cast(this); if (self->sock == -1) { return false; } long res = recv(self->sock, data, length, MsgFlags); if (res < 0) { if (errno == EAGAIN) { return false; } Close(); } else if (res == 0) { Close(); } return static_cast(res) == length; } } // namespace discord_rpc