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 35namespace OHOS { 36namespace MMI { 37UDSServer::~UDSServer() 38{ 39 CALL_DEBUG_ENTER; 40 UdsStop(); 41} 42 43void 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 56int32_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 69int32_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 79bool 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 94void UDSServer::Multicast(const std::vector<int32_t>& fdList, NetPacket& pkt) 95{ 96 for (const auto &item : fdList) { 97 SendMsg(item, pkt); 98 } 99} 100 101int32_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 151int32_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 191void 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 206void UDSServer::OnConnected(SessionPtr sess) 207{ 208 CHKPV(sess); 209 MMI_HILOGI("Session desc:%{public}s", sess->GetDescript().c_str()); 210} 211 212void UDSServer::OnDisconnected(SessionPtr sess) 213{ 214 CHKPV(sess); 215 MMI_HILOGI("Session desc:%{public}s", sess->GetDescript().c_str()); 216} 217 218int32_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 224void UDSServer::SetRecvFun(MsgServerFunCallback fun) 225{ 226 recvFun_ = fun; 227} 228 229void 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 256void UDSServer::OnPacket(int32_t fd, NetPacket& pkt) 257{ 258 auto sess = GetSession(fd); 259 CHKPV(sess); 260 recvFun_(sess, pkt); 261} 262 263void 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 297void 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 313void 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 319void UDSServer::RemoveEpollEvent(int32_t fd) 320{ 321 MMI_HILOGI("Remove %{public}d in epollEvent map", fd); 322 epollEventMap_.erase(fd); 323} 324 325void 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 336SessionPtr 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 347SessionPtr 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 360bool 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 385void 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 406void UDSServer::AddSessionDeletedCallback(std::function<void(SessionPtr)> callback) 407{ 408 CALL_DEBUG_ENTER; 409 callbacks_.push_back(callback); 410} 411 412void 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