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 
GetProcessId()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 
GetTempPath()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 
Create()39 /*static*/ BaseConnection* BaseConnection::Create()
40 {
41     PipeAddr.sun_family = AF_UNIX;
42     return &Connection;
43 }
44 
Destroy(BaseConnection * & c)45 /*static*/ void BaseConnection::Destroy(BaseConnection*& c)
46 {
47     auto self = reinterpret_cast<BaseConnectionUnix*>(c);
48     self->Close();
49     c = nullptr;
50 }
51 
Open()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 
Close()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 
Write(const void * data,size_t length)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 
Read(void * data,size_t length)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 }
126