/ src / connection_unix.cpp
connection_unix.cpp
  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  
 12  int GetProcessId()
 13  {
 14      return ::getpid();
 15  }
 16  
 17  struct BaseConnectionUnix : public BaseConnection {
 18      int sock{-1};
 19  };
 20  
 21  static BaseConnectionUnix Connection;
 22  static sockaddr_un PipeAddr{};
 23  #ifdef MSG_NOSIGNAL
 24  static int MsgFlags = MSG_NOSIGNAL;
 25  #else
 26  static int MsgFlags = 0;
 27  #endif
 28  
 29  static 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  
 52  bool 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  
 79  bool 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  
 91  bool 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  
106  bool 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  }