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