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 constexpr size_t bufferSize = 512 * 1024;
154     static constexpr size_t serverBufferSize = 256 * 1024;
155     static constexpr size_t nativeBufferSize = 1024 * 1024;
156     if (setsockopt(serverFd, SOL_SOCKET, SO_SNDBUF, &serverBufferSize, sizeof(serverBufferSize)) != 0) {
157         MMI_HILOGE("setsockopt serverFd failed, errno:%{public}d", errno);
158         return RET_ERR;
159     }
160     if (setsockopt(serverFd, SOL_SOCKET, SO_RCVBUF, &serverBufferSize, sizeof(serverBufferSize)) != 0) {
161         MMI_HILOGE("setsockopt serverFd failed, errno:%{public}d", errno);
162         return RET_ERR;
163     }
164     if (tokenType == TokenType::TOKEN_NATIVE) {
165         if (setsockopt(toReturnClientFd, SOL_SOCKET, SO_SNDBUF, &nativeBufferSize, sizeof(nativeBufferSize)) != 0) {
166             MMI_HILOGE("setsockopt toReturnClientFd failed, errno:%{public}d", errno);
167             return RET_ERR;
168         }
169         if (setsockopt(toReturnClientFd, SOL_SOCKET, SO_RCVBUF, &nativeBufferSize, sizeof(nativeBufferSize)) != 0) {
170             MMI_HILOGE("setsockopt toReturnClientFd failed, errno:%{public}d", errno);
171             return RET_ERR;
172         }
173     } else {
174         if (setsockopt(toReturnClientFd, SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)) != 0) {
175             MMI_HILOGE("setsockopt toReturnClientFd failed, errno:%{public}d", errno);
176             return RET_ERR;
177         }
178         if (setsockopt(toReturnClientFd, SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)) != 0) {
179             MMI_HILOGE("setsockopt toReturnClientFd failed, errno:%{public}d", errno);
180             return RET_ERR;
181         }
182     }
183     return RET_OK;
184 }
185 
Dump(int32_t fd,const std::vector<std::string> & args)186 void UDSServer::Dump(int32_t fd, const std::vector<std::string> &args)
187 {
188     CALL_DEBUG_ENTER;
189     mprintf(fd, "Uds_server information:\t");
190     mprintf(fd, "uds_server: count=%zu", sessionsMap_.size());
191     for (const auto &item : sessionsMap_) {
192         std::shared_ptr<UDSSession> udsSession = item.second;
193         CHKPV(udsSession);
194         mprintf(fd,
195                 "Uid:%d | Pid:%d | Fd:%d | TokenType:%d | Descript:%s\t",
196                 udsSession->GetUid(), udsSession->GetPid(), udsSession->GetFd(),
197                 udsSession->GetTokenType(), udsSession->GetDescript().c_str());
198     }
199 }
200 
OnConnected(SessionPtr sess)201 void UDSServer::OnConnected(SessionPtr sess)
202 {
203     CHKPV(sess);
204     MMI_HILOGI("Session desc:%{public}s", sess->GetDescript().c_str());
205 }
206 
OnDisconnected(SessionPtr sess)207 void UDSServer::OnDisconnected(SessionPtr sess)
208 {
209     CHKPV(sess);
210     MMI_HILOGI("Session desc:%{public}s", sess->GetDescript().c_str());
211 }
212 
AddEpoll(EpollEventType type,int32_t fd)213 int32_t UDSServer::AddEpoll(EpollEventType type, int32_t fd)
214 {
215     MMI_HILOGE("This information should not exist. Subclasses should implement this function");
216     return RET_ERR;
217 }
218 
SetRecvFun(MsgServerFunCallback fun)219 void UDSServer::SetRecvFun(MsgServerFunCallback fun)
220 {
221     recvFun_ = fun;
222 }
223 
ReleaseSession(int32_t fd,epoll_event & ev)224 void UDSServer::ReleaseSession(int32_t fd, epoll_event& ev)
225 {
226     CALL_DEBUG_ENTER;
227     auto secPtr = GetSession(fd);
228     if (secPtr != nullptr) {
229         OnDisconnected(secPtr);
230         DelSession(fd);
231     } else {
232         MMI_HILOGE("Get session secPtr is nullptr, fd:%{public}d", fd);
233         DfxHisysevent::OnClientDisconnect(secPtr, fd, OHOS::HiviewDFX::HiSysEvent::EventType::FAULT);
234     }
235     if (ev.data.ptr) {
236         RemoveEpollEvent(fd);
237         ev.data.ptr = nullptr;
238     }
239     if (auto it = circleBufMap_.find(fd); it != circleBufMap_.end()) {
240         circleBufMap_.erase(it);
241     } else {
242         MMI_HILOGE("Can't find fd");
243     }
244     if (close(fd) == RET_OK) {
245         DfxHisysevent::OnClientDisconnect(secPtr, fd, OHOS::HiviewDFX::HiSysEvent::EventType::BEHAVIOR);
246     } else {
247         DfxHisysevent::OnClientDisconnect(secPtr, fd, OHOS::HiviewDFX::HiSysEvent::EventType::FAULT);
248     }
249 }
250 
OnPacket(int32_t fd,NetPacket & pkt)251 void UDSServer::OnPacket(int32_t fd, NetPacket& pkt)
252 {
253     auto sess = GetSession(fd);
254     CHKPV(sess);
255     recvFun_(sess, pkt);
256 }
257 
OnEpollRecv(int32_t fd,epoll_event & ev)258 void UDSServer::OnEpollRecv(int32_t fd, epoll_event& ev)
259 {
260     if (fd < 0) {
261         MMI_HILOGE("Invalid input param fd:%{public}d", fd);
262         return;
263     }
264     auto& buf = circleBufMap_[fd];
265     char szBuf[MAX_PACKET_BUF_SIZE] = {};
266     for (int32_t i = 0; i < MAX_RECV_LIMIT; i++) {
267         auto size = recv(fd, szBuf, MAX_PACKET_BUF_SIZE, MSG_DONTWAIT | MSG_NOSIGNAL);
268         if (size > 0) {
269             if (!buf.Write(szBuf, size)) {
270                 MMI_HILOGW("Write data failed. size:%{public}zu", size);
271             }
272             OnReadPackets(buf, [this, fd] (NetPacket& pkt) { return this->OnPacket(fd, pkt); });
273         } else if (size < 0) {
274             if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) {
275                 MMI_HILOGD("Continue for errno EAGAIN|EINTR|EWOULDBLOCK size:%{public}zu, errno:%{public}d",
276                     size, errno);
277                 continue;
278             }
279             MMI_HILOGE("Recv return %{public}zu errno:%{public}d", size, errno);
280             break;
281         } else {
282             MMI_HILOGE("The client side disconnect with the server. size:0 errno:%{public}d", errno);
283             ReleaseSession(fd, ev);
284             break;
285         }
286         if (size < MAX_PACKET_BUF_SIZE) {
287             break;
288         }
289     }
290 }
291 
OnEpollEvent(epoll_event & ev)292 void UDSServer::OnEpollEvent(epoll_event& ev)
293 {
294     CHKPV(ev.data.ptr);
295     auto fd = ev.data.fd;
296     if (fd < 0) {
297         MMI_HILOGE("The fd less than 0, errCode:%{public}d", PARAM_INPUT_INVALID);
298         return;
299     }
300     if ((ev.events & EPOLLERR) || (ev.events & EPOLLHUP)) {
301         MMI_HILOGI("EPOLLERR or EPOLLHUP fd:%{public}d, ev.events:0x%{public}x", fd, ev.events);
302         ReleaseSession(fd, ev);
303     } else if (ev.events & EPOLLIN) {
304         OnEpollRecv(fd, ev);
305     }
306 }
307 
AddEpollEvent(int32_t fd,std::shared_ptr<mmi_epoll_event> epollEvent)308 void UDSServer::AddEpollEvent(int32_t fd, std::shared_ptr<mmi_epoll_event> epollEvent)
309 {
310     MMI_HILOGI("Add %{public}d in epollEvent map", fd);
311     epollEventMap_[fd] = epollEvent;
312 }
313 
RemoveEpollEvent(int32_t fd)314 void UDSServer::RemoveEpollEvent(int32_t fd)
315 {
316     MMI_HILOGI("Remove %{public}d in epollEvent map", fd);
317     epollEventMap_.erase(fd);
318 }
319 
DumpSession(const std::string & title)320 void UDSServer::DumpSession(const std::string &title)
321 {
322     MMI_HILOGD("in %s: %s", __func__, title.c_str());
323     int32_t i = 0;
324     for (auto &[key, value] : sessionsMap_) {
325         CHKPV(value);
326         MMI_HILOGD("%d, %s", i, value->GetDescript().c_str());
327         i++;
328     }
329 }
330 
GetSession(int32_t fd) const331 SessionPtr UDSServer::GetSession(int32_t fd) const
332 {
333     auto it = sessionsMap_.find(fd);
334     if (it == sessionsMap_.end()) {
335         MMI_HILOGE("Session not found. fd:%{public}d", fd);
336         return nullptr;
337     }
338     CHKPP(it->second);
339     return it->second->GetSharedPtr();
340 }
341 
GetSessionByPid(int32_t pid) const342 SessionPtr UDSServer::GetSessionByPid(int32_t pid) const
343 {
344     int32_t fd = GetClientFd(pid);
345     if (fd <= 0) {
346         if (pid_ != pid) {
347             pid_ = pid;
348             MMI_HILOGE("Session not found. pid:%{public}d", pid);
349         }
350         return nullptr;
351     }
352     return GetSession(fd);
353 }
354 
AddSession(SessionPtr ses)355 bool UDSServer::AddSession(SessionPtr ses)
356 {
357     CHKPF(ses);
358     MMI_HILOGI("pid:%{public}d, fd:%{public}d", ses->GetPid(), ses->GetFd());
359     auto fd = ses->GetFd();
360     if (fd < 0) {
361         MMI_HILOGE("The fd is less than 0");
362         return false;
363     }
364     auto pid = ses->GetPid();
365     if (pid <= 0) {
366         MMI_HILOGE("Get process failed");
367         return false;
368     }
369     idxPidMap_[pid] = fd;
370     sessionsMap_[fd] = ses;
371     DumpSession("AddSession");
372     if (sessionsMap_.size() > MAX_SESSON_ALARM) {
373         MMI_HILOGW("Too many clients. Warning Value:%{public}d, Current Value:%{public}zd",
374                    MAX_SESSON_ALARM, sessionsMap_.size());
375     }
376     MMI_HILOGI("AddSession end");
377     return true;
378 }
379 
DelSession(int32_t fd)380 void UDSServer::DelSession(int32_t fd)
381 {
382     CALL_DEBUG_ENTER;
383     MMI_HILOGI("fd:%{public}d", fd);
384     if (fd < 0) {
385         MMI_HILOGE("The fd less than 0, errCode:%{public}d", PARAM_INPUT_INVALID);
386         return;
387     }
388     auto pid = GetClientPid(fd);
389     MMI_HILOGI("pid:%{public}d", pid);
390     if (pid > 0) {
391         idxPidMap_.erase(pid);
392     }
393     auto it = sessionsMap_.find(fd);
394     if (it != sessionsMap_.end()) {
395         NotifySessionDeleted(it->second);
396         sessionsMap_.erase(it);
397     }
398     DumpSession("DelSession");
399 }
400 
AddSessionDeletedCallback(std::function<void (SessionPtr)> callback)401 void UDSServer::AddSessionDeletedCallback(std::function<void(SessionPtr)> callback)
402 {
403     CALL_DEBUG_ENTER;
404     callbacks_.push_back(callback);
405 }
406 
NotifySessionDeleted(SessionPtr ses)407 void UDSServer::NotifySessionDeleted(SessionPtr ses)
408 {
409     CALL_DEBUG_ENTER;
410     for (const auto &callback : callbacks_) {
411         callback(ses);
412     }
413 }
414 } // namespace MMI
415 } // namespace OHOS
416