1 /*
2 * Copyright (c) 2021-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
16 #include "uds_server.h"
17 #include <list>
18 #include <cinttypes>
19 #include <sys/socket.h>
20 #include "accesstoken_kit.h"
21 #include "i_multimodal_input_connect.h"
22 #include "ipc_skeleton.h"
23 #include "mmi_log.h"
24 #include "safe_keeper.h"
25 #include "util.h"
26 #include "util_ex.h"
27
28 namespace OHOS {
29 namespace MMI {
30 namespace {
31 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, MMI_LOG_DOMAIN, "UDSServer"};
32 }
33 } // namespace MMI
34 } // namespace OHOS
35
UDSServer()36 OHOS::MMI::UDSServer::UDSServer() {}
37
~UDSServer()38 OHOS::MMI::UDSServer::~UDSServer()
39 {
40 MMI_LOGD("enter");
41 UdsStop();
42 MMI_LOGD("leave");
43 }
44
UdsStop()45 void OHOS::MMI::UDSServer::UdsStop()
46 {
47 std::lock_guard<std::mutex> lock(mux_);
48 isRunning_ = false;
49 if (epollFd_ != -1) {
50 close(epollFd_);
51 epollFd_ = -1;
52 }
53
54 for (const auto &item : sessionsMap_) {
55 item.second->Close();
56 }
57 sessionsMap_.clear();
58 }
59
GetClientFd(int32_t pid)60 int32_t OHOS::MMI::UDSServer::GetClientFd(int32_t pid)
61 {
62 std::lock_guard<std::mutex> lock(mux_);
63 auto it = idxPidMap_.find(pid);
64 if (it == idxPidMap_.end()) {
65 MMI_LOGE("find fd error, Invalid input parameter pid:%{public}d,errCode:%{public}d",
66 pid, SESSION_NOT_FOUND);
67 return RET_ERR;
68 }
69 return it->second;
70 }
71
GetClientPid(int32_t fd)72 int32_t OHOS::MMI::UDSServer::GetClientPid(int32_t fd)
73 {
74 std::lock_guard<std::mutex> lock(mux_);
75 auto it = sessionsMap_.find(fd);
76 if (it == sessionsMap_.end()) {
77 MMI_LOGE("find pid error, Invalid input parameter fd:%{public}d,errCode:%{public}d",
78 fd, SESSION_NOT_FOUND);
79 return RET_ERR;
80 }
81 return it->second->GetPid();
82 }
83
SendMsg(int32_t fd,NetPacket & pkt)84 bool OHOS::MMI::UDSServer::SendMsg(int32_t fd, NetPacket& pkt)
85 {
86 std::lock_guard<std::mutex> lock(mux_);
87 CHKF(fd >= 0, PARAM_INPUT_INVALID);
88 auto ses = GetSession(fd);
89 if (ses == nullptr) {
90 MMI_LOGE("SendMsg fd:%{public}d not found, The message was discarded. errCode:%{public}d",
91 fd, SESSION_NOT_FOUND);
92 return false;
93 }
94 return ses->SendMsg(pkt);
95 }
96
Broadcast(NetPacket & pkt)97 void OHOS::MMI::UDSServer::Broadcast(NetPacket& pkt)
98 {
99 std::lock_guard<std::mutex> lock(mux_);
100 for (const auto &item : sessionsMap_) {
101 item.second->SendMsg(pkt);
102 }
103 }
104
Multicast(const std::vector<int32_t> & fdList,NetPacket & pkt)105 void OHOS::MMI::UDSServer::Multicast(const std::vector<int32_t>& fdList, NetPacket& pkt)
106 {
107 for (const auto &item : fdList) {
108 SendMsg(item, pkt);
109 }
110 }
111
ClearDeadSessionInMap(const int32_t serverFd,const int32_t clientFd)112 bool OHOS::MMI::UDSServer::ClearDeadSessionInMap(const int32_t serverFd, const int32_t clientFd)
113 {
114 auto it = sessionsMap_.find(serverFd);
115 if (it != sessionsMap_.end()) {
116 MMI_LOGE("The session(fd1:%{public}d) on the server side will be closed because it had in map"
117 "errCode:%{public}d", serverFd, SESSION_NOT_FOUND);
118 DelSession(serverFd);
119 }
120
121 it = sessionsMap_.find(clientFd);
122 if (it != sessionsMap_.end()) {
123 MMI_LOGE("The session(fd2:%{public}d) on the server side will be closed because it had in map"
124 "errCode:%{public}d", clientFd, SESSION_NOT_FOUND);
125 DelSession(clientFd);
126 }
127 return true;
128 }
129
AddSocketPairInfo(const std::string & programName,const int32_t moduleType,const int32_t uid,const int32_t pid,int32_t & serverFd,int32_t & toReturnClientFd)130 int32_t OHOS::MMI::UDSServer::AddSocketPairInfo(const std::string& programName,
131 const int32_t moduleType, const int32_t uid, const int32_t pid,
132 int32_t& serverFd, int32_t& toReturnClientFd)
133 {
134 MMI_LOGD("enter");
135 std::lock_guard<std::mutex> lock(mux_);
136 int32_t sockFds[2] = {};
137
138 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockFds) != 0) {
139 MMI_LOGE("call socketpair fail, errno:%{public}d", errno);
140 return RET_ERR;
141 }
142
143 serverFd = sockFds[0];
144 toReturnClientFd = sockFds[1];
145 if (toReturnClientFd < 0) {
146 MMI_LOGE("call fcntl fail, errno:%{public}d", errno);
147 return RET_ERR;
148 }
149
150 constexpr size_t bufferSize = 32 * 1024;
151 setsockopt(sockFds[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
152 setsockopt(sockFds[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
153 setsockopt(sockFds[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
154 setsockopt(sockFds[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
155 SetNonBlockMode(serverFd);
156
157 MMI_LOGD("alloc socketpair, serverFd:%{public}d,clientFd:%{public}d(%{public}d)",
158 serverFd, toReturnClientFd, sockFds[1]);
159 auto closeSocketFdWhenError = [&serverFd, &toReturnClientFd] {
160 close(serverFd);
161 close(toReturnClientFd);
162 serverFd = IMultimodalInputConnect::INVALID_SOCKET_FD;
163 toReturnClientFd = IMultimodalInputConnect::INVALID_SOCKET_FD;
164 };
165
166 std::list<std::function<void()> > cleanTaskList;
167 auto cleanTaskWhenError = [cleanTaskList] {
168 for (const auto &item : cleanTaskList) {
169 item();
170 }
171 };
172
173 cleanTaskList.push_back(closeSocketFdWhenError);
174
175 if (!ClearDeadSessionInMap(serverFd, toReturnClientFd)) {
176 cleanTaskWhenError();
177 MMI_LOGE("IsSocketFdNotUsed error, errCode:%{public}d", CLEAR_DEAD_SESSION_FAIL);
178 return RET_ERR;
179 }
180
181 int32_t ret = RET_OK;
182 ret = AddEpoll(EPOLL_EVENT_SOCKET, serverFd);
183 if (ret != RET_OK) {
184 cleanTaskWhenError();
185 MMI_LOGE("epoll_ctl EPOLL_CTL_ADD return %{public}d,errCode:%{public}d", ret, EPOLL_MODIFY_FAIL);
186 return ret;
187 }
188
189 SessionPtr sess = std::make_shared<UDSSession>(programName, moduleType, serverFd, uid, pid);
190 if (sess == nullptr) {
191 cleanTaskWhenError();
192 MMI_LOGE("make_shared fail. progName:%{public}s,pid:%{public}d,errCode:%{public}d",
193 programName.c_str(), pid, MAKE_SHARED_FAIL);
194 return RET_ERR;
195 }
196 AddPermission(sess);
197 if (!AddSession(sess)) {
198 cleanTaskWhenError();
199 MMI_LOGE("AddSession fail errCode:%{public}d", ADD_SESSION_FAIL);
200 return RET_ERR;
201 }
202 OnConnected(sess);
203 return RET_OK;
204 }
205
AddPermission(SessionPtr sess)206 void OHOS::MMI::UDSServer::AddPermission(SessionPtr sess)
207 {
208 uint32_t callerToken = IPCSkeleton::GetCallingTokenID();
209 int32_t result;
210 std::string permissionMonitor = "ohos.permission.INPUT_MONITORING";
211
212 if (Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(callerToken) ==
213 Security::AccessToken::ATokenTypeEnum::TOKEN_HAP) {
214 MMI_LOGD("get type flag is TOKEN_HAP");
215 result = Security::AccessToken::AccessTokenKit::VerifyAccessToken(callerToken, permissionMonitor);
216 MMI_LOGD("verify access result:%{public}d", result);
217 if (result != Security::AccessToken::PERMISSION_GRANTED) {
218 MMI_LOGD("permission is not granted");
219 sess->AddPermission(false);
220 }
221 }
222 }
223
Dump(int32_t fd)224 void OHOS::MMI::UDSServer::Dump(int32_t fd)
225 {
226 std::lock_guard<std::mutex> lock(mux_);
227 mprintf(fd, "Sessions: count=%d", sessionsMap_.size());
228 std::string strTmp = "fds:[";
229 if (sessionsMap_.empty()) {
230 strTmp = "fds:[]";
231 mprintf(fd, "\t%s", strTmp.c_str());
232 return;
233 }
234 for (const auto& item : sessionsMap_) {
235 strTmp += std::to_string(item.second->GetFd()) + ",";
236 }
237 strTmp.resize(strTmp.size() - 1);
238 strTmp += "]";
239 mprintf(fd, "\t%s", strTmp.c_str());
240 }
241
OnConnected(SessionPtr s)242 void OHOS::MMI::UDSServer::OnConnected(SessionPtr s)
243 {
244 MMI_LOGI("UDSServer::OnConnected session desc:%{public}s", s->GetDescript().c_str());
245 }
246
OnDisconnected(SessionPtr s)247 void OHOS::MMI::UDSServer::OnDisconnected(SessionPtr s)
248 {
249 MMI_LOGI("UDSServer::OnDisconnected session desc:%{public}s", s->GetDescript().c_str());
250 }
251
AddEpoll(EpollEventType type,int32_t fd)252 int32_t OHOS::MMI::UDSServer::AddEpoll(EpollEventType type, int32_t fd)
253 {
254 MMI_LOGE("UDSServer::AddEpoll This information should not exist. Subclasses should implement this function.");
255 return RET_ERR;
256 }
257
SetRecvFun(MsgServerFunCallback fun)258 void OHOS::MMI::UDSServer::SetRecvFun(MsgServerFunCallback fun)
259 {
260 recvFun_ = fun;
261 }
262
ReleaseSession(int32_t fd,epoll_event & ev)263 void OHOS::MMI::UDSServer::ReleaseSession(int32_t fd, epoll_event& ev)
264 {
265 auto secPtr = GetSession(fd);
266 if (secPtr != nullptr) {
267 OnDisconnected(secPtr);
268 DelSession(fd);
269 }
270 if (ev.data.ptr) {
271 free(ev.data.ptr);
272 ev.data.ptr = nullptr;
273 }
274 if (auto it = circleBufMap_.find(fd); it != circleBufMap_.end()) {
275 circleBufMap_.erase(it);
276 }
277 close(fd);
278 }
279
OnPacket(int32_t fd,NetPacket & pkt)280 void OHOS::MMI::UDSServer::OnPacket(int32_t fd, NetPacket& pkt)
281 {
282 auto sess = GetSession(fd);
283 CHKPV(sess);
284 recvFun_(sess, pkt);
285 }
286
OnEpollRecv(int32_t fd,epoll_event & ev)287 void OHOS::MMI::UDSServer::OnEpollRecv(int32_t fd, epoll_event& ev)
288 {
289 if (fd < 0) {
290 MMI_LOGE("Invalid input param fd:%{public}d", fd);
291 return;
292 }
293 auto& buf = circleBufMap_[fd];
294 char szBuf[MAX_PACKET_BUF_SIZE] = {};
295 for (int32_t i = 0; i < MAX_RECV_LIMIT; i++) {
296 auto size = recv(fd, szBuf, MAX_PACKET_BUF_SIZE, MSG_DONTWAIT | MSG_NOSIGNAL);
297 if (size > 0) {
298 if (!buf.Write(szBuf, size)) {
299 MMI_LOGW("Write data faild. size:%{public}zu", size);
300 }
301 OnReadPackets(buf, std::bind(&UDSServer::OnPacket, this, fd, std::placeholders::_1));
302 } else if (size < 0) {
303 if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) {
304 MMI_LOGD("continue for errno EAGAIN|EINTR|EWOULDBLOCK size:%{public}zu errno:%{public}d",
305 size, errno);
306 continue;
307 }
308 MMI_LOGE("recv return %{public}zu errno:%{public}d", size, errno);
309 break;
310 } else {
311 MMI_LOGE("The client side disconnect with the server. size:0 errno:%{public}d", errno);
312 ReleaseSession(fd, ev);
313 break;
314 }
315 if (size < MAX_PACKET_BUF_SIZE) {
316 break;
317 }
318 }
319 }
320
OnEpollEvent(epoll_event & ev)321 void OHOS::MMI::UDSServer::OnEpollEvent(epoll_event& ev)
322 {
323 CHKPV(ev.data.ptr);
324 auto fd = *static_cast<int32_t*>(ev.data.ptr);
325 if (fd < 0) {
326 MMI_LOGE("The fd less than 0, errCode:%{public}d", PARAM_INPUT_INVALID);
327 return;
328 }
329 if ((ev.events & EPOLLERR) || (ev.events & EPOLLHUP)) {
330 MMI_LOGD("EPOLLERR or EPOLLHUP fd:%{public}d,ev.events:0x%{public}x", fd, ev.events);
331 ReleaseSession(fd, ev);
332 } else if (ev.events & EPOLLIN) {
333 OnEpollRecv(fd, ev);
334 }
335 }
336
DumpSession(const std::string & title)337 void OHOS::MMI::UDSServer::DumpSession(const std::string &title)
338 {
339 MMI_LOGD("in %s: %s", __func__, title.c_str());
340 int32_t i = 0;
341 for (auto& r : sessionsMap_) {
342 MMI_LOGD("%d, %s", i, r.second->GetDescript().c_str());
343 i++;
344 }
345 }
346
GetSession(int32_t fd) const347 OHOS::MMI::SessionPtr OHOS::MMI::UDSServer::GetSession(int32_t fd) const
348 {
349 auto it = sessionsMap_.find(fd);
350 if (it == sessionsMap_.end()) {
351 return nullptr;
352 }
353 if (it->second == nullptr) {
354 return nullptr;
355 }
356 return it->second->GetPtr();
357 }
358
AddSession(SessionPtr ses)359 bool OHOS::MMI::UDSServer::AddSession(SessionPtr ses)
360 {
361 CHKPF(ses);
362 MMI_LOGD("AddSession pid:%{public}d,fd:%{public}d", ses->GetPid(), ses->GetFd());
363 auto fd = ses->GetFd();
364 CHKF(fd >= 0, VAL_NOT_EXP);
365 auto pid = ses->GetPid();
366 CHKF(pid > 0, VAL_NOT_EXP);
367 idxPidMap_[pid] = fd;
368 sessionsMap_[fd] = ses;
369 DumpSession("AddSession");
370 if (sessionsMap_.size() > MAX_SESSON_ALARM) {
371 MMI_LOGW("Too many clients. Warning Value:%{public}d,Current Value:%{public}zd",
372 MAX_SESSON_ALARM, sessionsMap_.size());
373 }
374 MMI_LOGI("AddSession end");
375 return true;
376 }
377
DelSession(int32_t fd)378 void OHOS::MMI::UDSServer::DelSession(int32_t fd)
379 {
380 MMI_LOGD("DelSession begin fd:%{public}d", fd);
381 CHK(fd >= 0, PARAM_INPUT_INVALID);
382 auto pid = GetClientPid(fd);
383 if (pid > 0) {
384 idxPidMap_.erase(pid);
385 }
386 auto it = sessionsMap_.find(fd);
387 if (it != sessionsMap_.end()) {
388 NotifySessionDeleted(it->second);
389 sessionsMap_.erase(it);
390 }
391 DumpSession("DelSession");
392 MMI_LOGI("DelSession end");
393 }
394
AddSessionDeletedCallback(std::function<void (SessionPtr)> callback)395 void OHOS::MMI::UDSServer::AddSessionDeletedCallback(std::function<void(SessionPtr)> callback)
396 {
397 MMI_LOGD("Enter");
398 callbacks_.push_back(callback);
399 MMI_LOGD("Leave");
400 }
401
NotifySessionDeleted(SessionPtr ses)402 void OHOS::MMI::UDSServer::NotifySessionDeleted(SessionPtr ses)
403 {
404 MMI_LOGD("Enter");
405 for (const auto& callback : callbacks_) {
406 callback(ses);
407 }
408 MMI_LOGD("Leave");
409 }
410
411