1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "ipc_unix_socket.h"
16
17 #include <poll.h>
18 #include <sys/socket.h>
19 #include <sys/un.h>
20 #include <unistd.h>
21
22 #include "hhlog.h"
23
24 namespace OHOS {
25 namespace Developtools {
26 namespace Hiebpf {
IpcUnixSocketServer()27 IpcUnixSocketServer::IpcUnixSocketServer() {}
28
~IpcUnixSocketServer()29 IpcUnixSocketServer::~IpcUnixSocketServer()
30 {
31 Stop();
32 }
33
Start(const std::string & pathname)34 bool IpcUnixSocketServer::Start(const std::string &pathname)
35 {
36 CHECK_TRUE(serverFd_ == -1, false, "Unix Socket Server is running");
37
38 serverFd_ = socket(AF_UNIX, SOCK_STREAM, 0);
39 CHECK_TRUE(serverFd_ != -1, false, "create Unix Socket Server failed, %d: %s", errno, strerror(errno));
40
41 unlink(pathname.c_str());
42 struct sockaddr_un addr = {0};
43 addr.sun_family = AF_UNIX;
44 std::copy(pathname.c_str(), pathname.c_str() + pathname.size() + 1, addr.sun_path);
45 if (bind(serverFd_, (struct sockaddr*)&addr, sizeof(sockaddr_un)) != 0) {
46 HHLOGE(true, "bind failed, Unix Socket(%s), %d: %s", pathname.c_str(), errno, strerror(errno));
47 close(serverFd_);
48 return false;
49 }
50 if (listen(serverFd_, UNIX_SOCKET_LISTEN_COUNT) != 0) {
51 HHLOGE(true, "listen failed, Unix Socket(%s), %d: %s", pathname.c_str(), errno, strerror(errno));
52 close(serverFd_);
53 unlink(pathname.c_str());
54 return false;
55 }
56 pathName_ = pathname;
57
58 isRunning_ = true;
59 handleThread_ = std::thread(&IpcUnixSocketServer::handleThreadLoop, this);
60
61 return true;
62 }
63
Stop()64 bool IpcUnixSocketServer::Stop()
65 {
66 isRunning_ = false;
67 if (serverFd_ != -1) {
68 close(serverFd_);
69 serverFd_ = -1;
70 }
71 if (clientFd_ != -1) {
72 close(clientFd_);
73 clientFd_ = -1;
74 }
75 if (handleThread_.joinable()) {
76 handleThread_.join();
77 }
78 unlink(pathName_.c_str());
79 return true;
80 }
81
SendMessage(const void * buf,size_t size)82 bool IpcUnixSocketServer::SendMessage(const void *buf, size_t size)
83 {
84 CHECK_TRUE(clientFd_ != -1, false, "no available Unix Socket");
85
86 CHECK_TRUE(send(clientFd_, buf, size, 0) != -1, false,
87 "send failed, Unix Socket(%d) %zu bytes, %d: %s", clientFd_, size, errno, strerror(errno));
88 return true;
89 }
90
handleThreadLoop()91 void IpcUnixSocketServer::handleThreadLoop()
92 {
93 while (isRunning_) {
94 struct pollfd pollFd {serverFd_, POLLIN, 0};
95 const int timeout = 1000;
96 int polled = TEMP_FAILURE_RETRY(poll(&pollFd, 1, timeout));
97 if (polled == 0) { // timeout
98 continue;
99 } else if (polled < 0 || !(pollFd.revents & POLLIN)) {
100 HHLOGE(true, "poll failed, Unix Socket(%d), %d: %s", serverFd_, errno, strerror(errno));
101 close(serverFd_);
102 serverFd_ = -1;
103 break;
104 }
105
106 clientFd_ = accept(serverFd_, nullptr, nullptr);
107 if (clientFd_ == -1) {
108 HHLOGE(true, "accept failed, Unix Socket(%d), %d: %s", serverFd_, errno, strerror(errno));
109 continue;
110 }
111
112 while (isRunning_ && clientFd_ != -1) {
113 uint8_t buf[UNIX_SOCKET_BUFFER_SIZE] = {0};
114 int recvSize = recv(clientFd_, buf, UNIX_SOCKET_BUFFER_SIZE, 0);
115 if (recvSize > 0) {
116 if (handleMessageFn_) {
117 handleMessageFn_(buf, recvSize);
118 }
119 continue;
120 } else if (recvSize == 0) {
121 HHLOGE(true, "recv failed, peer has closed");
122 } else {
123 HHLOGE(true, "recv failed, Unix Socket(%d), %d: %s", clientFd_, errno, strerror(errno));
124 }
125 close(clientFd_);
126 clientFd_ = -1;
127 }
128 }
129 }
130
IpcUnixSocketClient()131 IpcUnixSocketClient::IpcUnixSocketClient() {}
132
~IpcUnixSocketClient()133 IpcUnixSocketClient::~IpcUnixSocketClient()
134 {
135 Disconnect();
136 }
137
Connect(const std::string & pathname)138 bool IpcUnixSocketClient::Connect(const std::string &pathname)
139 {
140 CHECK_TRUE(sockFd_ == -1, false, "Unix Socket has connected");
141
142 sockFd_ = socket(AF_UNIX, SOCK_STREAM, 0);
143 CHECK_TRUE(sockFd_ != -1, false, "create Unix Socket Server failed, %d: %s", errno, strerror(errno));
144
145 struct sockaddr_un addr = {0};
146 addr.sun_family = AF_UNIX;
147 std::copy(pathname.c_str(), pathname.c_str() + pathname.size() + 1, addr.sun_path);
148 if (connect(sockFd_, (struct sockaddr*)&addr, sizeof(sockaddr_un)) == -1) {
149 HHLOGE(true, "connect failed, %d: %s", errno, strerror(errno));
150 sockFd_ = -1;
151 return false;
152 }
153
154 return true;
155 }
156
Disconnect()157 void IpcUnixSocketClient::Disconnect()
158 {
159 if (sockFd_ != -1) {
160 close(sockFd_);
161 sockFd_ = -1;
162 }
163 }
164
SendMessage(const void * buf,size_t size)165 bool IpcUnixSocketClient::SendMessage(const void *buf, size_t size)
166 {
167 CHECK_TRUE(sockFd_ != -1, false, "Unix Socket disconnected");
168
169 if (send(sockFd_, buf, size, 0) != -1) {
170 return true;
171 }
172 HHLOGE(true, "send failed, Unix Socket(%d), %d: %s", sockFd_, errno, strerror(errno));
173 return false;
174 }
175
RecvMessage(void * buf,size_t & size,uint32_t timeout)176 bool IpcUnixSocketClient::RecvMessage(void *buf, size_t &size, uint32_t timeout)
177 {
178 CHECK_TRUE(sockFd_ != -1, false, "Unix Socket disconnected");
179
180 struct pollfd pollFd {sockFd_, POLLIN | POLLERR | POLLHUP, 0};
181 int polled = poll(&pollFd, 1, timeout);
182 if (polled == 0) { // timeout
183 size = 0;
184 return true;
185 } else if (polled < 0 || !(pollFd.revents & POLLIN)) {
186 HHLOGE(true, "poll failed, Unix Socket(%d), %d: %s", sockFd_, errno, strerror(errno));
187 return false;
188 }
189
190 int recvSize = recv(sockFd_, buf, size, 0);
191 if (recvSize > 0) {
192 size = static_cast<size_t>(recvSize);
193 return true;
194 } else if (recvSize == 0) {
195 HHLOGE(true, "recv failed, peer has closed");
196 } else {
197 HHLOGE(true, "recv failed, Unix Socket(%d), %d: %s", sockFd_, errno, strerror(errno));
198 }
199
200 return false;
201 }
202 } // namespace Hiebpf
203 } // namespace Developtools
204 } // namespace OHOS
205