• 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 
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         free(ev.data.ptr);
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 
DumpSession(const std::string & title)301 void UDSServer::DumpSession(const std::string &title)
302 {
303     MMI_HILOGD("in %s: %s", __func__, title.c_str());
304     int32_t i = 0;
305     for (auto &[key, value] : sessionsMap_) {
306         CHKPV(value);
307         MMI_HILOGD("%d, %s", i, value->GetDescript().c_str());
308         i++;
309     }
310 }
311 
GetSession(int32_t fd) const312 SessionPtr UDSServer::GetSession(int32_t fd) const
313 {
314     auto it = sessionsMap_.find(fd);
315     if (it == sessionsMap_.end()) {
316         MMI_HILOGE("Session not found.fd:%{public}d", fd);
317         return nullptr;
318     }
319     CHKPP(it->second);
320     return it->second->GetSharedPtr();
321 }
322 
GetSessionByPid(int32_t pid) const323 SessionPtr UDSServer::GetSessionByPid(int32_t pid) const
324 {
325     int32_t fd = GetClientFd(pid);
326     if (fd <= 0) {
327         MMI_HILOGE("Session not found.pid:%{public}d", pid);
328         return nullptr;
329     }
330     return GetSession(fd);
331 }
332 
AddSession(SessionPtr ses)333 bool UDSServer::AddSession(SessionPtr ses)
334 {
335     CHKPF(ses);
336     MMI_HILOGI("pid:%{public}d,fd:%{public}d", ses->GetPid(), ses->GetFd());
337     auto fd = ses->GetFd();
338     if (fd < 0) {
339         MMI_HILOGE("The fd is less than 0");
340         return false;
341     }
342     auto pid = ses->GetPid();
343     if (pid <= 0) {
344         MMI_HILOGE("Get process failed");
345         return false;
346     }
347     idxPidMap_[pid] = fd;
348     sessionsMap_[fd] = ses;
349     DumpSession("AddSession");
350     if (sessionsMap_.size() > MAX_SESSON_ALARM) {
351         MMI_HILOGW("Too many clients. Warning Value:%{public}d,Current Value:%{public}zd",
352                    MAX_SESSON_ALARM, sessionsMap_.size());
353     }
354     MMI_HILOGI("AddSession end");
355     return true;
356 }
357 
DelSession(int32_t fd)358 void UDSServer::DelSession(int32_t fd)
359 {
360     CALL_DEBUG_ENTER;
361     MMI_HILOGI("fd:%{public}d", fd);
362     if (fd < 0) {
363         MMI_HILOGE("The fd less than 0, errCode:%{public}d", PARAM_INPUT_INVALID);
364         return;
365     }
366     auto pid = GetClientPid(fd);
367     if (pid > 0) {
368         idxPidMap_.erase(pid);
369     }
370     auto it = sessionsMap_.find(fd);
371     if (it != sessionsMap_.end()) {
372         NotifySessionDeleted(it->second);
373         sessionsMap_.erase(it);
374     }
375     DumpSession("DelSession");
376 }
377 
AddSessionDeletedCallback(std::function<void (SessionPtr)> callback)378 void UDSServer::AddSessionDeletedCallback(std::function<void(SessionPtr)> callback)
379 {
380     CALL_DEBUG_ENTER;
381     callbacks_.push_back(callback);
382 }
383 
NotifySessionDeleted(SessionPtr ses)384 void UDSServer::NotifySessionDeleted(SessionPtr ses)
385 {
386     CALL_DEBUG_ENTER;
387     for (const auto &callback : callbacks_) {
388         callback(ses);
389     }
390 }
391 } // namespace MMI
392 } // namespace OHOS
393