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