all repos — mgba @ c0ac5e35c06fe3a30efb444808d8e09f1dc28330

mGBA Game Boy Advance Emulator

src/third-party/discord-rpc/src/connection_unix.cpp (view raw)

  1#include "connection.h"
  2
  3#include <errno.h>
  4#include <fcntl.h>
  5#include <stdio.h>
  6#include <string.h>
  7#include <sys/socket.h>
  8#include <sys/types.h>
  9#include <sys/un.h>
 10#include <unistd.h>
 11
 12int GetProcessId()
 13{
 14    return ::getpid();
 15}
 16
 17struct BaseConnectionUnix : public BaseConnection {
 18    int sock{-1};
 19};
 20
 21static BaseConnectionUnix Connection;
 22static sockaddr_un PipeAddr{};
 23#ifdef MSG_NOSIGNAL
 24static int MsgFlags = MSG_NOSIGNAL;
 25#else
 26static int MsgFlags = 0;
 27#endif
 28
 29static const char* GetTempPath()
 30{
 31    const char* temp = getenv("XDG_RUNTIME_DIR");
 32    temp = temp ? temp : getenv("TMPDIR");
 33    temp = temp ? temp : getenv("TMP");
 34    temp = temp ? temp : getenv("TEMP");
 35    temp = temp ? temp : "/tmp";
 36    return temp;
 37}
 38
 39/*static*/ BaseConnection* BaseConnection::Create()
 40{
 41    PipeAddr.sun_family = AF_UNIX;
 42    return &Connection;
 43}
 44
 45/*static*/ void BaseConnection::Destroy(BaseConnection*& c)
 46{
 47    auto self = reinterpret_cast<BaseConnectionUnix*>(c);
 48    self->Close();
 49    c = nullptr;
 50}
 51
 52bool BaseConnection::Open()
 53{
 54    const char* tempPath = GetTempPath();
 55    auto self = reinterpret_cast<BaseConnectionUnix*>(this);
 56    self->sock = socket(AF_UNIX, SOCK_STREAM, 0);
 57    if (self->sock == -1) {
 58        return false;
 59    }
 60    fcntl(self->sock, F_SETFL, O_NONBLOCK);
 61#ifdef SO_NOSIGPIPE
 62    int optval = 1;
 63    setsockopt(self->sock, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval));
 64#endif
 65
 66    for (int pipeNum = 0; pipeNum < 10; ++pipeNum) {
 67        snprintf(
 68          PipeAddr.sun_path, sizeof(PipeAddr.sun_path), "%s/discord-ipc-%d", tempPath, pipeNum);
 69        int err = connect(self->sock, (const sockaddr*)&PipeAddr, sizeof(PipeAddr));
 70        if (err == 0) {
 71            self->isOpen = true;
 72            return true;
 73        }
 74    }
 75    self->Close();
 76    return false;
 77}
 78
 79bool BaseConnection::Close()
 80{
 81    auto self = reinterpret_cast<BaseConnectionUnix*>(this);
 82    if (self->sock == -1) {
 83        return false;
 84    }
 85    close(self->sock);
 86    self->sock = -1;
 87    self->isOpen = false;
 88    return true;
 89}
 90
 91bool BaseConnection::Write(const void* data, size_t length)
 92{
 93    auto self = reinterpret_cast<BaseConnectionUnix*>(this);
 94
 95    if (self->sock == -1) {
 96        return false;
 97    }
 98
 99    ssize_t sentBytes = send(self->sock, data, length, MsgFlags);
100    if (sentBytes < 0) {
101        Close();
102    }
103    return sentBytes == (ssize_t)length;
104}
105
106bool BaseConnection::Read(void* data, size_t length)
107{
108    auto self = reinterpret_cast<BaseConnectionUnix*>(this);
109
110    if (self->sock == -1) {
111        return false;
112    }
113
114    int res = (int)recv(self->sock, data, length, MsgFlags);
115    if (res < 0) {
116        if (errno == EAGAIN) {
117            return false;
118        }
119        Close();
120    }
121    else if (res == 0) {
122        Close();
123    }
124    return res == (int)length;
125}