• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 "socket_session_manager.h"
17 
18 #include <algorithm>
19 
20 #include <sys/socket.h>
21 #include <unistd.h>
22 
23 #include "devicestatus_define.h"
24 
25 namespace OHOS {
26 namespace Msdp {
27 namespace DeviceStatus {
28 namespace {
29 constexpr OHOS::HiviewDFX::HiLogLabel LABEL { LOG_CORE, MSDP_DOMAIN_ID, "SocketSessionManager" };
30 constexpr int32_t MAX_EPOLL_EVENTS { 64 };
31 } // namespace
32 
Init()33 int32_t SocketSessionManager::Init()
34 {
35     return epollMgr_.Open();
36 }
37 
AllocSocketFd(const std::string & programName,int32_t moduleType,int32_t tokenType,int32_t uid,int32_t pid,int32_t & clientFd)38 int32_t SocketSessionManager::AllocSocketFd(const std::string& programName, int32_t moduleType, int32_t tokenType,
39                                             int32_t uid, int32_t pid, int32_t& clientFd)
40 {
41     CALL_DEBUG_ENTER;
42     int32_t sockFds[2] { -1, -1 };
43 
44     if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sockFds) != 0) {
45         FI_HILOGE("Call socketpair failed, errno:%{public}s", ::strerror(errno));
46         return RET_ERR;
47     }
48     static constexpr size_t BUFFER_SIZE { 32 * 1024 };
49     static constexpr size_t NATIVE_BUFFER_SIZE { 64 * 1024 };
50     std::shared_ptr<SocketSession> session { nullptr };
51 
52     if (!SetBufferSize(sockFds[0], BUFFER_SIZE)) {
53         goto CLOSE_SOCK;
54     }
55     if (!SetBufferSize(sockFds[1], tokenType == TokenType::TOKEN_NATIVE ? NATIVE_BUFFER_SIZE : BUFFER_SIZE)) {
56         goto CLOSE_SOCK;
57     }
58 
59     session = std::make_shared<SocketSession>(programName, moduleType, tokenType, sockFds[0], uid, pid);
60     if (epollMgr_.Add(*session) != RET_OK) {
61         goto CLOSE_SOCK;
62     }
63     if (!AddSession(session)) {
64         FI_HILOGE("AddSession failed, errCode:%{public}d", ADD_SESSION_FAIL);
65         goto CLOSE_SOCK;
66     }
67 
68     clientFd = sockFds[1];
69     return RET_OK;
70 
71 CLOSE_SOCK:
72     if (::close(sockFds[0]) != 0) {
73         FI_HILOGE("close(%{public}d) failed:%{public}s", sockFds[0], ::strerror(errno));
74     }
75     if (::close(sockFds[1]) != 0) {
76         FI_HILOGE("close(%{public}d) failed:%{public}s", sockFds[1], ::strerror(errno));
77     }
78     return RET_ERR;
79 }
80 
SetBufferSize(int32_t sockFd,int32_t bufSize)81 bool SocketSessionManager::SetBufferSize(int32_t sockFd, int32_t bufSize)
82 {
83     if (::setsockopt(sockFd, SOL_SOCKET, SO_SNDBUF, &bufSize, sizeof(bufSize)) != 0) {
84         FI_HILOGE("setsockopt(%{public}d) failed:%{public}s", sockFd, ::strerror(errno));
85         return false;
86     }
87     if (::setsockopt(sockFd, SOL_SOCKET, SO_RCVBUF, &bufSize, sizeof(bufSize)) != 0) {
88         FI_HILOGE("setsockopt(%{public}d) failed:%{public}s", sockFd, ::strerror(errno));
89         return false;
90     }
91     return true;
92 }
93 
FindSessionByPid(int32_t pid) const94 SocketSessionPtr SocketSessionManager::FindSessionByPid(int32_t pid) const
95 {
96     auto iter = std::find_if(sessions_.cbegin(), sessions_.cend(),
97         [pid](const auto &item) {
98             return ((item.second != nullptr) && (item.second->GetPid() == pid));
99         });
100     return (iter != sessions_.cend() ? iter->second : nullptr);
101 }
102 
Dispatch(const struct epoll_event & ev)103 void SocketSessionManager::Dispatch(const struct epoll_event &ev)
104 {
105     if ((ev.events & EPOLLIN) == EPOLLIN) {
106         DispatchOne();
107     } else if ((ev.events & (EPOLLHUP | EPOLLERR)) != 0) {
108         FI_HILOGE("Epoll hangup:%{public}s", ::strerror(errno));
109         /// TODO: Add error handling here.
110     }
111 }
112 
DispatchOne()113 void SocketSessionManager::DispatchOne()
114 {
115     struct epoll_event evs[MAX_EPOLL_EVENTS];
116     int32_t cnt = epollMgr_.WaitTimeout(evs, MAX_EPOLL_EVENTS, 0);
117 
118     for (int32_t index = 0; index < cnt; ++index) {
119         IEpollEventSource *source = reinterpret_cast<IEpollEventSource *>(evs[index].data.ptr);
120         CHKPC(source);
121         if ((evs[index].events & EPOLLIN) == EPOLLIN) {
122             source->Dispatch(evs[index]);
123         } else if ((evs[index].events & (EPOLLHUP | EPOLLERR)) != 0) {
124             FI_HILOGE("Epoll hangup:%{public}s", ::strerror(errno));
125             ReleaseSession(source->GetFd());
126         }
127     }
128 }
129 
ReleaseSession(int32_t fd)130 void SocketSessionManager::ReleaseSession(int32_t fd)
131 {
132     CALL_DEBUG_ENTER;
133     if (auto iter = sessions_.find(fd); iter != sessions_.end()) {
134         auto session = iter->second;
135         sessions_.erase(iter);
136 
137         if (session != nullptr) {
138             epollMgr_.Remove(*session);
139             NotifySessionDeleted(session);
140         }
141     }
142     DumpSession("DelSession");
143 }
144 
FindSession(int32_t fd) const145 std::shared_ptr<SocketSession> SocketSessionManager::FindSession(int32_t fd) const
146 {
147     auto iter = sessions_.find(fd);
148     return (iter != sessions_.cend() ? iter->second : nullptr);
149 }
150 
DumpSession(const std::string & title) const151 void SocketSessionManager::DumpSession(const std::string &title) const
152 {
153     FI_HILOGD("in %s:%s", __func__, title.c_str());
154     int32_t i = 0;
155 
156     for (auto &[_, session] : sessions_) {
157         CHKPC(session);
158         FI_HILOGD("%{public}d, %s", i, session->ToString().c_str());
159         i++;
160     }
161 }
162 
AddSession(std::shared_ptr<SocketSession> session)163 bool SocketSessionManager::AddSession(std::shared_ptr<SocketSession> session)
164 {
165     CALL_DEBUG_ENTER;
166     CHKPF(session);
167     if (sessions_.size() >= MAX_SESSION_ALARM) {
168         FI_HILOGE("The number of connections exceeds limit(%{public}zu)", MAX_SESSION_ALARM);
169         return false;
170     }
171     auto [_, inserted] = sessions_.emplace(session->GetFd(), session);
172     if (!inserted) {
173         FI_HILOGE("Session(%{public}d) has been recorded", session->GetFd());
174         return false;
175     }
176     DumpSession("AddSession");
177     return true;
178 }
179 
AddSessionDeletedCallback(int32_t pid,std::function<void (SocketSessionPtr)> callback)180 void SocketSessionManager::AddSessionDeletedCallback(int32_t pid, std::function<void(SocketSessionPtr)> callback)
181 {
182     CALL_DEBUG_ENTER;
183     if (callback == nullptr) {
184         FI_HILOGE("Callback is none");
185         return;
186     }
187     auto [_, inserted] = callbacks_.emplace(pid, callback);
188     if (!inserted) {
189         FI_HILOGW("Duplicate addtion of session-lost callback for (%{public}d)", pid);
190     }
191 }
192 
NotifySessionDeleted(std::shared_ptr<SocketSession> session)193 void SocketSessionManager::NotifySessionDeleted(std::shared_ptr<SocketSession> session)
194 {
195     CALL_DEBUG_ENTER;
196     FI_HILOGD("Session lost, pid:%{public}d", session->GetPid());
197     if (auto iter = callbacks_.find(session->GetPid()); iter != callbacks_.end()) {
198         if (iter->second) {
199             iter->second(session);
200         }
201         callbacks_.erase(iter);
202     }
203 }
204 } // namespace DeviceStatus
205 } // namespace Msdp
206 } // namespace OHOS
207