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 }