• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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