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