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
18 #include <cinttypes>
19 #include <list>
20
21 #include <sys/socket.h>
22
23 #include "dfx_hisysevent.h"
24 #include "i_multimodal_input_connect.h"
25 #include "mmi_log.h"
26 #include "multimodalinput_ipc_interface_code.h"
27 #include "util.h"
28 #include "util_ex.h"
29
30 #undef MMI_LOG_DOMAIN
31 #define MMI_LOG_DOMAIN MMI_LOG_SERVER
32 #undef MMI_LOG_TAG
33 #define MMI_LOG_TAG "UDSServer"
34
35 namespace OHOS {
36 namespace MMI {
~UDSServer()37 UDSServer::~UDSServer()
38 {
39 CALL_DEBUG_ENTER;
40 UdsStop();
41 }
42
UdsStop()43 void UDSServer::UdsStop()
44 {
45 if (epollFd_ != -1) {
46 close(epollFd_);
47 epollFd_ = -1;
48 }
49
50 for (const auto &item : sessionsMap_) {
51 item.second->Close();
52 }
53 sessionsMap_.clear();
54 }
55
GetClientFd(int32_t pid) const56 int32_t UDSServer::GetClientFd(int32_t pid) const
57 {
58 auto it = idxPidMap_.find(pid);
59 if (it == idxPidMap_.end()) {
60 if (pid_ != pid) {
61 pid_ = pid;
62 MMI_HILOGE("Not found pid:%{public}d", pid);
63 }
64 return INVALID_FD;
65 }
66 return it->second;
67 }
68
GetClientPid(int32_t fd) const69 int32_t UDSServer::GetClientPid(int32_t fd) const
70 {
71 auto it = sessionsMap_.find(fd);
72 if (it == sessionsMap_.end()) {
73 MMI_HILOGE("Not found fd:%{public}d", fd);
74 return INVALID_PID;
75 }
76 return it->second->GetPid();
77 }
78
SendMsg(int32_t fd, NetPacket& pkt)79 bool UDSServer::SendMsg(int32_t fd, NetPacket& pkt)
80 {
81 if (fd < 0) {
82 MMI_HILOGE("The fd is less than 0");
83 return false;
84 }
85 auto ses = GetSession(fd);
86 if (ses == nullptr) {
87 MMI_HILOGE("The fd:%{public}d not found, The message was discarded. errCode:%{public}d",
88 fd, SESSION_NOT_FOUND);
89 return false;
90 }
91 return ses->SendMsg(pkt);
92 }
93
Multicast(const std::vector<int32_t>& fdList, NetPacket& pkt)94 void UDSServer::Multicast(const std::vector<int32_t>& fdList, NetPacket& pkt)
95 {
96 for (const auto &item : fdList) {
97 SendMsg(item, pkt);
98 }
99 }
100
AddSocketPairInfo(const std::string& programName, const int32_t moduleType, const int32_t uid, const int32_t pid, int32_t& serverFd, int32_t& toReturnClientFd, int32_t& tokenType)101 int32_t UDSServer::AddSocketPairInfo(const std::string& programName,
102 const int32_t moduleType, const int32_t uid, const int32_t pid,
103 int32_t& serverFd, int32_t& toReturnClientFd, int32_t& tokenType)
104 {
105 CALL_DEBUG_ENTER;
106 int32_t sockFds[2] = { -1 };
107
108 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockFds) != 0) {
109 MMI_HILOGE("Call socketpair failed, errno:%{public}d", errno);
110 return RET_ERR;
111 }
112 serverFd = sockFds[0];
113 toReturnClientFd = sockFds[1];
114 if (serverFd < 0 || toReturnClientFd < 0) {
115 MMI_HILOGE("Call fcntl failed, errno:%{public}d", errno);
116 return RET_ERR;
117 }
118
119 SessionPtr sess = nullptr;
120 if (SetFdProperty(tokenType, serverFd, toReturnClientFd) != RET_OK) {
121 MMI_HILOGE("SetFdProperty failed");
122 goto CLOSE_SOCK;
123 }
124
125 if (AddEpoll(EPOLL_EVENT_SOCKET, serverFd) != RET_OK) {
126 MMI_HILOGE("epoll_ctl EPOLL_CTL_ADD failed, errCode:%{public}d", EPOLL_MODIFY_FAIL);
127 goto CLOSE_SOCK;
128 }
129 sess = std::make_shared<UDSSession>(programName, moduleType, serverFd, uid, pid);
130 if (sess == nullptr) {
131 MMI_HILOGE("make_shared fail. programName:%{public}s, pid:%{public}d, errCode:%{public}d",
132 programName.c_str(), pid, MAKE_SHARED_FAIL);
133 goto CLOSE_SOCK;
134 }
135 sess->SetTokenType(tokenType);
136 if (!AddSession(sess)) {
137 MMI_HILOGE("AddSession fail errCode:%{public}d", ADD_SESSION_FAIL);
138 goto CLOSE_SOCK;
139 }
140 OnConnected(sess);
141 return RET_OK;
142
143 CLOSE_SOCK:
144 close(serverFd);
145 serverFd = IMultimodalInputConnect::INVALID_SOCKET_FD;
146 close(toReturnClientFd);
147 toReturnClientFd = IMultimodalInputConnect::INVALID_SOCKET_FD;
148 return RET_ERR;
149 }
150
SetFdProperty(int32_t& tokenType, int32_t& serverFd, int32_t& toReturnClientFd)151 int32_t UDSServer::SetFdProperty(int32_t& tokenType, int32_t& serverFd, int32_t& toReturnClientFd)
152 {
153 static size_t bufferSize = 64 * 1024;
154 static size_t serverBufferSize = 64 * 1024;
155 static size_t nativeBufferSize = 128 * 1024;
156 #ifdef OHOS_BUILD_ENABLE_ANCO
157 bufferSize = 512 * 1024;
158 nativeBufferSize = 1024 * 1024;
159 #endif // OHOS_BUILD_ENABLE_ANCO
160
161 if (setsockopt(serverFd, SOL_SOCKET, SO_SNDBUF, &serverBufferSize, sizeof(bufferSize)) != 0) {
162 MMI_HILOGE("Setsockopt serverFd failed, errno:%{public}d", errno);
163 return RET_ERR;
164 }
165 if (setsockopt(serverFd, SOL_SOCKET, SO_RCVBUF, &serverBufferSize, sizeof(bufferSize)) != 0) {
166 MMI_HILOGE("Setsockopt serverFd failed, errno:%{public}d", errno);
167 return RET_ERR;
168 }
169 if (tokenType == TokenType::TOKEN_NATIVE) {
170 if (setsockopt(toReturnClientFd, SOL_SOCKET, SO_SNDBUF, &nativeBufferSize, sizeof(nativeBufferSize)) != 0) {
171 MMI_HILOGE("Setsockopt toReturnClientFd failed, errno:%{public}d", errno);
172 return RET_ERR;
173 }
174 if (setsockopt(toReturnClientFd, SOL_SOCKET, SO_RCVBUF, &nativeBufferSize, sizeof(nativeBufferSize)) != 0) {
175 MMI_HILOGE("Setsockopt toReturnClientFd failed, errno:%{public}d", errno);
176 return RET_ERR;
177 }
178 } else {
179 if (setsockopt(toReturnClientFd, SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)) != 0) {
180 MMI_HILOGE("Setsockopt toReturnClientFd failed, errno:%{public}d", errno);
181 return RET_ERR;
182 }
183 if (setsockopt(toReturnClientFd, SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)) != 0) {
184 MMI_HILOGE("Setsockopt toReturnClientFd failed, errno:%{public}d", errno);
185 return RET_ERR;
186 }
187 }
188 return RET_OK;
189 }
190
Dump(int32_t fd, const std::vector<std::string> &args)191 void UDSServer::Dump(int32_t fd, const std::vector<std::string> &args)
192 {
193 CALL_DEBUG_ENTER;
194 mprintf(fd, "Uds_server information:\t");
195 mprintf(fd, "uds_server: count=%zu", sessionsMap_.size());
196 for (const auto &item : sessionsMap_) {
197 std::shared_ptr<UDSSession> udsSession = item.second;
198 CHKPV(udsSession);
199 mprintf(fd,
200 "Uid:%d | Pid:%d | Fd:%d | TokenType:%d | Descript:%s\t",
201 udsSession->GetUid(), udsSession->GetPid(), udsSession->GetFd(),
202 udsSession->GetTokenType(), udsSession->GetDescript().c_str());
203 }
204 }
205
OnConnected(SessionPtr sess)206 void UDSServer::OnConnected(SessionPtr sess)
207 {
208 CHKPV(sess);
209 MMI_HILOGI("Session desc:%{public}s", sess->GetDescript().c_str());
210 }
211
OnDisconnected(SessionPtr sess)212 void UDSServer::OnDisconnected(SessionPtr sess)
213 {
214 CHKPV(sess);
215 MMI_HILOGI("Session desc:%{public}s", sess->GetDescript().c_str());
216 }
217
AddEpoll(EpollEventType type, int32_t fd)218 int32_t UDSServer::AddEpoll(EpollEventType type, int32_t fd)
219 {
220 MMI_HILOGE("This information should not exist. Subclasses should implement this function");
221 return RET_ERR;
222 }
223
SetRecvFun(MsgServerFunCallback fun)224 void UDSServer::SetRecvFun(MsgServerFunCallback fun)
225 {
226 recvFun_ = fun;
227 }
228
ReleaseSession(int32_t fd, epoll_event& ev)229 void UDSServer::ReleaseSession(int32_t fd, epoll_event& ev)
230 {
231 CALL_DEBUG_ENTER;
232 auto secPtr = GetSession(fd);
233 if (secPtr != nullptr) {
234 OnDisconnected(secPtr);
235 DelSession(fd);
236 } else {
237 MMI_HILOGE("Get session secPtr is nullptr, fd:%{public}d", fd);
238 DfxHisysevent::OnClientDisconnect(secPtr, fd, OHOS::HiviewDFX::HiSysEvent::EventType::FAULT);
239 }
240 if (ev.data.ptr) {
241 RemoveEpollEvent(fd);
242 ev.data.ptr = nullptr;
243 }
244 if (auto it = circleBufMap_.find(fd); it != circleBufMap_.end()) {
245 circleBufMap_.erase(it);
246 } else {
247 MMI_HILOGE("Can't find fd");
248 }
249 if (close(fd) == RET_OK) {
250 DfxHisysevent::OnClientDisconnect(secPtr, fd, OHOS::HiviewDFX::HiSysEvent::EventType::BEHAVIOR);
251 } else {
252 DfxHisysevent::OnClientDisconnect(secPtr, fd, OHOS::HiviewDFX::HiSysEvent::EventType::FAULT);
253 }
254 }
255
OnPacket(int32_t fd, NetPacket& pkt)256 void UDSServer::OnPacket(int32_t fd, NetPacket& pkt)
257 {
258 auto sess = GetSession(fd);
259 CHKPV(sess);
260 recvFun_(sess, pkt);
261 }
262
OnEpollRecv(int32_t fd, epoll_event& ev)263 void UDSServer::OnEpollRecv(int32_t fd, epoll_event& ev)
264 {
265 if (fd < 0) {
266 MMI_HILOGE("Invalid input param fd:%{public}d", fd);
267 return;
268 }
269 auto& buf = circleBufMap_[fd];
270 char szBuf[MAX_PACKET_BUF_SIZE] = {};
271 for (int32_t i = 0; i < MAX_RECV_LIMIT; i++) {
272 auto size = recv(fd, szBuf, MAX_PACKET_BUF_SIZE, MSG_DONTWAIT | MSG_NOSIGNAL);
273 if (size > 0) {
274 if (!buf.Write(szBuf, size)) {
275 MMI_HILOGW("Write data failed. size:%{public}zu", size);
276 }
277 OnReadPackets(buf, [this, fd] (NetPacket& pkt) { return this->OnPacket(fd, pkt); });
278 } else if (size < 0) {
279 if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) {
280 MMI_HILOGD("Continue for errno EAGAIN|EINTR|EWOULDBLOCK size:%{public}zu, errno:%{public}d",
281 size, errno);
282 continue;
283 }
284 MMI_HILOGE("Recv return %{public}zu errno:%{public}d", size, errno);
285 break;
286 } else {
287 MMI_HILOGE("The client side disconnect with the server. size:0 errno:%{public}d", errno);
288 ReleaseSession(fd, ev);
289 break;
290 }
291 if (size < MAX_PACKET_BUF_SIZE) {
292 break;
293 }
294 }
295 }
296
OnEpollEvent(epoll_event& ev)297 void UDSServer::OnEpollEvent(epoll_event& ev)
298 {
299 CHKPV(ev.data.ptr);
300 auto fd = ev.data.fd;
301 if (fd < 0) {
302 MMI_HILOGE("The fd less than 0, errCode:%{public}d", PARAM_INPUT_INVALID);
303 return;
304 }
305 if ((ev.events & EPOLLERR) || (ev.events & EPOLLHUP)) {
306 MMI_HILOGI("EPOLLERR or EPOLLHUP fd:%{public}d, ev.events:0x%{public}x", fd, ev.events);
307 ReleaseSession(fd, ev);
308 } else if (ev.events & EPOLLIN) {
309 OnEpollRecv(fd, ev);
310 }
311 }
312
AddEpollEvent(int32_t fd, std::shared_ptr<mmi_epoll_event> epollEvent)313 void UDSServer::AddEpollEvent(int32_t fd, std::shared_ptr<mmi_epoll_event> epollEvent)
314 {
315 MMI_HILOGI("Add %{public}d in epollEvent map", fd);
316 epollEventMap_[fd] = epollEvent;
317 }
318
RemoveEpollEvent(int32_t fd)319 void UDSServer::RemoveEpollEvent(int32_t fd)
320 {
321 MMI_HILOGI("Remove %{public}d in epollEvent map", fd);
322 epollEventMap_.erase(fd);
323 }
324
DumpSession(const std::string &title)325 void UDSServer::DumpSession(const std::string &title)
326 {
327 MMI_HILOGD("in %s: %s", __func__, title.c_str());
328 int32_t i = 0;
329 for (auto &[key, value] : sessionsMap_) {
330 CHKPV(value);
331 MMI_HILOGD("%d, %s", i, value->GetDescript().c_str());
332 i++;
333 }
334 }
335
GetSession(int32_t fd) const336 SessionPtr UDSServer::GetSession(int32_t fd) const
337 {
338 auto it = sessionsMap_.find(fd);
339 if (it == sessionsMap_.end()) {
340 MMI_HILOGE("Session not found. fd:%{public}d", fd);
341 return nullptr;
342 }
343 CHKPP(it->second);
344 return it->second->GetSharedPtr();
345 }
346
GetSessionByPid(int32_t pid) const347 SessionPtr UDSServer::GetSessionByPid(int32_t pid) const
348 {
349 int32_t fd = GetClientFd(pid);
350 if (fd <= 0) {
351 if (pid_ != pid) {
352 pid_ = pid;
353 MMI_HILOGE("Session not found. pid:%{public}d", pid);
354 }
355 return nullptr;
356 }
357 return GetSession(fd);
358 }
359
AddSession(SessionPtr ses)360 bool UDSServer::AddSession(SessionPtr ses)
361 {
362 CHKPF(ses);
363 MMI_HILOGI("pid:%{public}d, fd:%{public}d", ses->GetPid(), ses->GetFd());
364 auto fd = ses->GetFd();
365 if (fd < 0) {
366 MMI_HILOGE("The fd is less than 0");
367 return false;
368 }
369 auto pid = ses->GetPid();
370 if (pid <= 0) {
371 MMI_HILOGE("Get process failed");
372 return false;
373 }
374 idxPidMap_[pid] = fd;
375 sessionsMap_[fd] = ses;
376 DumpSession("AddSession");
377 if (sessionsMap_.size() > MAX_SESSON_ALARM) {
378 MMI_HILOGW("Too many clients. Warning Value:%{public}d, Current Value:%{public}zd",
379 MAX_SESSON_ALARM, sessionsMap_.size());
380 }
381 MMI_HILOGI("AddSession end");
382 return true;
383 }
384
DelSession(int32_t fd)385 void UDSServer::DelSession(int32_t fd)
386 {
387 CALL_DEBUG_ENTER;
388 MMI_HILOGI("fd:%{public}d", fd);
389 if (fd < 0) {
390 MMI_HILOGE("The fd less than 0, errCode:%{public}d", PARAM_INPUT_INVALID);
391 return;
392 }
393 auto pid = GetClientPid(fd);
394 MMI_HILOGI("pid:%{public}d", pid);
395 if (pid > 0) {
396 idxPidMap_.erase(pid);
397 }
398 auto it = sessionsMap_.find(fd);
399 if (it != sessionsMap_.end()) {
400 NotifySessionDeleted(it->second);
401 sessionsMap_.erase(it);
402 }
403 DumpSession("DelSession");
404 }
405
AddSessionDeletedCallback(std::function<void(SessionPtr)> callback)406 void UDSServer::AddSessionDeletedCallback(std::function<void(SessionPtr)> callback)
407 {
408 CALL_DEBUG_ENTER;
409 callbacks_.push_back(callback);
410 }
411
NotifySessionDeleted(SessionPtr ses)412 void UDSServer::NotifySessionDeleted(SessionPtr ses)
413 {
414 CALL_DEBUG_ENTER;
415 for (const auto &callback : callbacks_) {
416 callback(ses);
417 }
418 }
419 } // namespace MMI
420 } // namespace OHOS
421