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}