1c29fa5a6Sopenharmony_ci/*
2c29fa5a6Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
3c29fa5a6Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4c29fa5a6Sopenharmony_ci * you may not use this file except in compliance with the License.
5c29fa5a6Sopenharmony_ci * You may obtain a copy of the License at
6c29fa5a6Sopenharmony_ci *
7c29fa5a6Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8c29fa5a6Sopenharmony_ci *
9c29fa5a6Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10c29fa5a6Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11c29fa5a6Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12c29fa5a6Sopenharmony_ci * See the License for the specific language governing permissions and
13c29fa5a6Sopenharmony_ci * limitations under the License.
14c29fa5a6Sopenharmony_ci */
15c29fa5a6Sopenharmony_ci
16c29fa5a6Sopenharmony_ci#include "socket_session_manager.h"
17c29fa5a6Sopenharmony_ci
18c29fa5a6Sopenharmony_ci#include <algorithm>
19c29fa5a6Sopenharmony_ci
20c29fa5a6Sopenharmony_ci#include <sys/socket.h>
21c29fa5a6Sopenharmony_ci#include <unistd.h>
22c29fa5a6Sopenharmony_ci
23c29fa5a6Sopenharmony_ci#include "iservice_registry.h"
24c29fa5a6Sopenharmony_ci#include "system_ability_definition.h"
25c29fa5a6Sopenharmony_ci
26c29fa5a6Sopenharmony_ci#include "devicestatus_define.h"
27c29fa5a6Sopenharmony_ci
28c29fa5a6Sopenharmony_ci#undef LOG_TAG
29c29fa5a6Sopenharmony_ci#define LOG_TAG "SocketSessionManager"
30c29fa5a6Sopenharmony_ci
31c29fa5a6Sopenharmony_cinamespace OHOS {
32c29fa5a6Sopenharmony_cinamespace Msdp {
33c29fa5a6Sopenharmony_cinamespace DeviceStatus {
34c29fa5a6Sopenharmony_cinamespace {
35c29fa5a6Sopenharmony_ciconstexpr int32_t MAX_EPOLL_EVENTS { 64 };
36c29fa5a6Sopenharmony_ci} // namespace
37c29fa5a6Sopenharmony_ci
38c29fa5a6Sopenharmony_ciint32_t SocketSessionManager::Init()
39c29fa5a6Sopenharmony_ci{
40c29fa5a6Sopenharmony_ci    return epollMgr_.Open();
41c29fa5a6Sopenharmony_ci}
42c29fa5a6Sopenharmony_ci
43c29fa5a6Sopenharmony_civoid SocketSessionManager::RegisterApplicationState()
44c29fa5a6Sopenharmony_ci{
45c29fa5a6Sopenharmony_ci    CALL_DEBUG_ENTER;
46c29fa5a6Sopenharmony_ci    auto appMgr = GetAppMgr();
47c29fa5a6Sopenharmony_ci    CHKPV(appMgr);
48c29fa5a6Sopenharmony_ci    appStateObserver_ = sptr<AppStateObserver>::MakeSptr(*this);
49c29fa5a6Sopenharmony_ci    auto err = appMgr->RegisterApplicationStateObserver(appStateObserver_);
50c29fa5a6Sopenharmony_ci    if (err != RET_OK) {
51c29fa5a6Sopenharmony_ci        appStateObserver_ = nullptr;
52c29fa5a6Sopenharmony_ci        FI_HILOGE("IAppMgr::RegisterApplicationStateObserver fail, error:%{public}d", err);
53c29fa5a6Sopenharmony_ci    }
54c29fa5a6Sopenharmony_ci}
55c29fa5a6Sopenharmony_ci
56c29fa5a6Sopenharmony_civoid SocketSessionManager::AppStateObserver::OnProcessDied(const AppExecFwk::ProcessData &processData)
57c29fa5a6Sopenharmony_ci{
58c29fa5a6Sopenharmony_ci    FI_HILOGI("\'%{public}s\' died, pid:%{public}d", processData.bundleName.c_str(), processData.pid);
59c29fa5a6Sopenharmony_ci    socketSessionManager_.ReleaseSessionByPid(processData.pid);
60c29fa5a6Sopenharmony_ci}
61c29fa5a6Sopenharmony_ci
62c29fa5a6Sopenharmony_ciint32_t SocketSessionManager::AllocSocketFd(const std::string& programName, int32_t moduleType, int32_t tokenType,
63c29fa5a6Sopenharmony_ci                                            int32_t uid, int32_t pid, int32_t& clientFd)
64c29fa5a6Sopenharmony_ci{
65c29fa5a6Sopenharmony_ci    CALL_DEBUG_ENTER;
66c29fa5a6Sopenharmony_ci    int32_t sockFds[2] { -1, -1 };
67c29fa5a6Sopenharmony_ci
68c29fa5a6Sopenharmony_ci    if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sockFds) != 0) {
69c29fa5a6Sopenharmony_ci        FI_HILOGE("Call socketpair failed, errno:%{public}s", ::strerror(errno));
70c29fa5a6Sopenharmony_ci        return RET_ERR;
71c29fa5a6Sopenharmony_ci    }
72c29fa5a6Sopenharmony_ci    static constexpr size_t BUFFER_SIZE { 32 * 1024 };
73c29fa5a6Sopenharmony_ci    static constexpr size_t NATIVE_BUFFER_SIZE { 64 * 1024 };
74c29fa5a6Sopenharmony_ci    std::shared_ptr<SocketSession> session { nullptr };
75c29fa5a6Sopenharmony_ci
76c29fa5a6Sopenharmony_ci    if (!SetBufferSize(sockFds[0], BUFFER_SIZE)) {
77c29fa5a6Sopenharmony_ci        goto CLOSE_SOCK;
78c29fa5a6Sopenharmony_ci    }
79c29fa5a6Sopenharmony_ci    if (!SetBufferSize(sockFds[1], tokenType == TokenType::TOKEN_NATIVE ? NATIVE_BUFFER_SIZE : BUFFER_SIZE)) {
80c29fa5a6Sopenharmony_ci        goto CLOSE_SOCK;
81c29fa5a6Sopenharmony_ci    }
82c29fa5a6Sopenharmony_ci
83c29fa5a6Sopenharmony_ci    session = std::make_shared<SocketSession>(programName, moduleType, tokenType, sockFds[0], uid, pid);
84c29fa5a6Sopenharmony_ci    if (epollMgr_.Add(*session) != RET_OK) {
85c29fa5a6Sopenharmony_ci        goto CLOSE_SOCK;
86c29fa5a6Sopenharmony_ci    }
87c29fa5a6Sopenharmony_ci    if (!AddSession(session)) {
88c29fa5a6Sopenharmony_ci        FI_HILOGE("AddSession failed, errCode:%{public}d", ADD_SESSION_FAIL);
89c29fa5a6Sopenharmony_ci        goto CLOSE_SOCK;
90c29fa5a6Sopenharmony_ci    }
91c29fa5a6Sopenharmony_ci
92c29fa5a6Sopenharmony_ci    clientFd = sockFds[1];
93c29fa5a6Sopenharmony_ci    return RET_OK;
94c29fa5a6Sopenharmony_ci
95c29fa5a6Sopenharmony_ciCLOSE_SOCK:
96c29fa5a6Sopenharmony_ci    if (::close(sockFds[0]) != 0) {
97c29fa5a6Sopenharmony_ci        FI_HILOGE("Close(%{public}d) failed:%{public}s", sockFds[0], ::strerror(errno));
98c29fa5a6Sopenharmony_ci    }
99c29fa5a6Sopenharmony_ci    if (::close(sockFds[1]) != 0) {
100c29fa5a6Sopenharmony_ci        FI_HILOGE("Close(%{public}d) failed:%{public}s", sockFds[1], ::strerror(errno));
101c29fa5a6Sopenharmony_ci    }
102c29fa5a6Sopenharmony_ci    return RET_ERR;
103c29fa5a6Sopenharmony_ci}
104c29fa5a6Sopenharmony_ci
105c29fa5a6Sopenharmony_cibool SocketSessionManager::SetBufferSize(int32_t sockFd, int32_t bufSize)
106c29fa5a6Sopenharmony_ci{
107c29fa5a6Sopenharmony_ci    if (::setsockopt(sockFd, SOL_SOCKET, SO_SNDBUF, &bufSize, sizeof(bufSize)) != 0) {
108c29fa5a6Sopenharmony_ci        FI_HILOGE("Set sockopt(%{public}d) failed:%{public}s", sockFd, ::strerror(errno));
109c29fa5a6Sopenharmony_ci        return false;
110c29fa5a6Sopenharmony_ci    }
111c29fa5a6Sopenharmony_ci    if (::setsockopt(sockFd, SOL_SOCKET, SO_RCVBUF, &bufSize, sizeof(bufSize)) != 0) {
112c29fa5a6Sopenharmony_ci        FI_HILOGE("Set sockopt(%{public}d) failed:%{public}s", sockFd, ::strerror(errno));
113c29fa5a6Sopenharmony_ci        return false;
114c29fa5a6Sopenharmony_ci    }
115c29fa5a6Sopenharmony_ci    return true;
116c29fa5a6Sopenharmony_ci}
117c29fa5a6Sopenharmony_ci
118c29fa5a6Sopenharmony_ciSocketSessionPtr SocketSessionManager::FindSessionByPid(int32_t pid) const
119c29fa5a6Sopenharmony_ci{
120c29fa5a6Sopenharmony_ci    auto iter = std::find_if(sessions_.cbegin(), sessions_.cend(),
121c29fa5a6Sopenharmony_ci        [pid](const auto &item) {
122c29fa5a6Sopenharmony_ci            return ((item.second != nullptr) && (item.second->GetPid() == pid));
123c29fa5a6Sopenharmony_ci        });
124c29fa5a6Sopenharmony_ci    return (iter != sessions_.cend() ? iter->second : nullptr);
125c29fa5a6Sopenharmony_ci}
126c29fa5a6Sopenharmony_ci
127c29fa5a6Sopenharmony_civoid SocketSessionManager::Dispatch(const struct epoll_event &ev)
128c29fa5a6Sopenharmony_ci{
129c29fa5a6Sopenharmony_ci    if ((ev.events & EPOLLIN) == EPOLLIN) {
130c29fa5a6Sopenharmony_ci        DispatchOne();
131c29fa5a6Sopenharmony_ci    } else if ((ev.events & (EPOLLHUP | EPOLLERR)) != 0) {
132c29fa5a6Sopenharmony_ci        FI_HILOGE("Epoll hangup:%{public}s", ::strerror(errno));
133c29fa5a6Sopenharmony_ci    }
134c29fa5a6Sopenharmony_ci}
135c29fa5a6Sopenharmony_ci
136c29fa5a6Sopenharmony_civoid SocketSessionManager::DispatchOne()
137c29fa5a6Sopenharmony_ci{
138c29fa5a6Sopenharmony_ci    struct epoll_event evs[MAX_EPOLL_EVENTS];
139c29fa5a6Sopenharmony_ci    int32_t cnt = epollMgr_.WaitTimeout(evs, MAX_EPOLL_EVENTS, 0);
140c29fa5a6Sopenharmony_ci
141c29fa5a6Sopenharmony_ci    for (int32_t index = 0; index < cnt; ++index) {
142c29fa5a6Sopenharmony_ci        IEpollEventSource *source = reinterpret_cast<IEpollEventSource *>(evs[index].data.ptr);
143c29fa5a6Sopenharmony_ci        CHKPC(source);
144c29fa5a6Sopenharmony_ci        if ((evs[index].events & EPOLLIN) == EPOLLIN) {
145c29fa5a6Sopenharmony_ci            source->Dispatch(evs[index]);
146c29fa5a6Sopenharmony_ci        } else if ((evs[index].events & (EPOLLHUP | EPOLLERR)) != 0) {
147c29fa5a6Sopenharmony_ci            FI_HILOGE("Epoll hangup:%{public}s", ::strerror(errno));
148c29fa5a6Sopenharmony_ci            ReleaseSession(source->GetFd());
149c29fa5a6Sopenharmony_ci        }
150c29fa5a6Sopenharmony_ci    }
151c29fa5a6Sopenharmony_ci}
152c29fa5a6Sopenharmony_ci
153c29fa5a6Sopenharmony_civoid SocketSessionManager::ReleaseSession(int32_t fd)
154c29fa5a6Sopenharmony_ci{
155c29fa5a6Sopenharmony_ci    CALL_DEBUG_ENTER;
156c29fa5a6Sopenharmony_ci    if (auto iter = sessions_.find(fd); iter != sessions_.end()) {
157c29fa5a6Sopenharmony_ci        auto session = iter->second;
158c29fa5a6Sopenharmony_ci        sessions_.erase(iter);
159c29fa5a6Sopenharmony_ci
160c29fa5a6Sopenharmony_ci        if (session != nullptr) {
161c29fa5a6Sopenharmony_ci            epollMgr_.Remove(*session);
162c29fa5a6Sopenharmony_ci            NotifySessionDeleted(session);
163c29fa5a6Sopenharmony_ci        }
164c29fa5a6Sopenharmony_ci    }
165c29fa5a6Sopenharmony_ci    DumpSession("DelSession");
166c29fa5a6Sopenharmony_ci}
167c29fa5a6Sopenharmony_ci
168c29fa5a6Sopenharmony_civoid SocketSessionManager::ReleaseSessionByPid(int32_t pid)
169c29fa5a6Sopenharmony_ci{
170c29fa5a6Sopenharmony_ci    CALL_DEBUG_ENTER;
171c29fa5a6Sopenharmony_ci    auto iter = std::find_if(sessions_.cbegin(), sessions_.cend(),
172c29fa5a6Sopenharmony_ci        [pid](const auto &item) {
173c29fa5a6Sopenharmony_ci            return ((item.second != nullptr) && (item.second->GetPid() == pid));
174c29fa5a6Sopenharmony_ci        });
175c29fa5a6Sopenharmony_ci    if (iter != sessions_.end()) {
176c29fa5a6Sopenharmony_ci        auto session = iter->second;
177c29fa5a6Sopenharmony_ci        if (session != nullptr) {
178c29fa5a6Sopenharmony_ci            epollMgr_.Remove(*session);
179c29fa5a6Sopenharmony_ci            NotifySessionDeleted(session);
180c29fa5a6Sopenharmony_ci        }
181c29fa5a6Sopenharmony_ci        sessions_.erase(iter);
182c29fa5a6Sopenharmony_ci    }
183c29fa5a6Sopenharmony_ci    DumpSession("DelSession");
184c29fa5a6Sopenharmony_ci}
185c29fa5a6Sopenharmony_ci
186c29fa5a6Sopenharmony_cisptr<AppExecFwk::IAppMgr> SocketSessionManager::GetAppMgr()
187c29fa5a6Sopenharmony_ci{
188c29fa5a6Sopenharmony_ci    CALL_INFO_TRACE;
189c29fa5a6Sopenharmony_ci    auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
190c29fa5a6Sopenharmony_ci    CHKPP(saMgr);
191c29fa5a6Sopenharmony_ci    auto appMgrObj = saMgr->GetSystemAbility(APP_MGR_SERVICE_ID);
192c29fa5a6Sopenharmony_ci    CHKPP(appMgrObj);
193c29fa5a6Sopenharmony_ci    return iface_cast<AppExecFwk::IAppMgr>(appMgrObj);
194c29fa5a6Sopenharmony_ci}
195c29fa5a6Sopenharmony_ci
196c29fa5a6Sopenharmony_cistd::shared_ptr<SocketSession> SocketSessionManager::FindSession(int32_t fd) const
197c29fa5a6Sopenharmony_ci{
198c29fa5a6Sopenharmony_ci    auto iter = sessions_.find(fd);
199c29fa5a6Sopenharmony_ci    return (iter != sessions_.cend() ? iter->second : nullptr);
200c29fa5a6Sopenharmony_ci}
201c29fa5a6Sopenharmony_ci
202c29fa5a6Sopenharmony_civoid SocketSessionManager::DumpSession(const std::string &title) const
203c29fa5a6Sopenharmony_ci{
204c29fa5a6Sopenharmony_ci    FI_HILOGD("in %s:%s", __func__, title.c_str());
205c29fa5a6Sopenharmony_ci    int32_t i = 0;
206c29fa5a6Sopenharmony_ci
207c29fa5a6Sopenharmony_ci    for (auto &[_, session] : sessions_) {
208c29fa5a6Sopenharmony_ci        CHKPC(session);
209c29fa5a6Sopenharmony_ci        FI_HILOGD("%{public}d, %s", i, session->ToString().c_str());
210c29fa5a6Sopenharmony_ci        i++;
211c29fa5a6Sopenharmony_ci    }
212c29fa5a6Sopenharmony_ci}
213c29fa5a6Sopenharmony_ci
214c29fa5a6Sopenharmony_cibool SocketSessionManager::AddSession(std::shared_ptr<SocketSession> session)
215c29fa5a6Sopenharmony_ci{
216c29fa5a6Sopenharmony_ci    CALL_DEBUG_ENTER;
217c29fa5a6Sopenharmony_ci    CHKPF(session);
218c29fa5a6Sopenharmony_ci    if (sessions_.size() >= MAX_SESSION_ALARM) {
219c29fa5a6Sopenharmony_ci        FI_HILOGE("The number of connections exceeds limit(%{public}zu)", MAX_SESSION_ALARM);
220c29fa5a6Sopenharmony_ci        return false;
221c29fa5a6Sopenharmony_ci    }
222c29fa5a6Sopenharmony_ci    auto [_, inserted] = sessions_.emplace(session->GetFd(), session);
223c29fa5a6Sopenharmony_ci    if (!inserted) {
224c29fa5a6Sopenharmony_ci        FI_HILOGE("Session(%{public}d) has been recorded", session->GetFd());
225c29fa5a6Sopenharmony_ci        return false;
226c29fa5a6Sopenharmony_ci    }
227c29fa5a6Sopenharmony_ci    DumpSession("AddSession");
228c29fa5a6Sopenharmony_ci    return true;
229c29fa5a6Sopenharmony_ci}
230c29fa5a6Sopenharmony_ci
231c29fa5a6Sopenharmony_civoid SocketSessionManager::AddSessionDeletedCallback(int32_t pid, std::function<void(SocketSessionPtr)> callback)
232c29fa5a6Sopenharmony_ci{
233c29fa5a6Sopenharmony_ci    if (callback == nullptr) {
234c29fa5a6Sopenharmony_ci        FI_HILOGE("Callback is none");
235c29fa5a6Sopenharmony_ci        return;
236c29fa5a6Sopenharmony_ci    }
237c29fa5a6Sopenharmony_ci    auto [_, inserted] = callbacks_.emplace(pid, callback);
238c29fa5a6Sopenharmony_ci    if (!inserted) {
239c29fa5a6Sopenharmony_ci        FI_HILOGW("Duplication of session-lost callback for (%{public}d)", pid);
240c29fa5a6Sopenharmony_ci    }
241c29fa5a6Sopenharmony_ci    FI_HILOGI("Start watching socket-session(%{public}d)", pid);
242c29fa5a6Sopenharmony_ci}
243c29fa5a6Sopenharmony_ci
244c29fa5a6Sopenharmony_civoid SocketSessionManager::RemoveSessionDeletedCallback(int32_t pid)
245c29fa5a6Sopenharmony_ci{
246c29fa5a6Sopenharmony_ci    FI_HILOGI("Stop watching socket-session(%{public}d)", pid);
247c29fa5a6Sopenharmony_ci    callbacks_.erase(pid);
248c29fa5a6Sopenharmony_ci}
249c29fa5a6Sopenharmony_ci
250c29fa5a6Sopenharmony_civoid SocketSessionManager::NotifySessionDeleted(std::shared_ptr<SocketSession> session)
251c29fa5a6Sopenharmony_ci{
252c29fa5a6Sopenharmony_ci    CALL_DEBUG_ENTER;
253c29fa5a6Sopenharmony_ci    FI_HILOGD("Session lost, pid:%{public}d", session->GetPid());
254c29fa5a6Sopenharmony_ci    if (auto iter = callbacks_.find(session->GetPid()); iter != callbacks_.end()) {
255c29fa5a6Sopenharmony_ci        if (iter->second) {
256c29fa5a6Sopenharmony_ci            iter->second(session);
257c29fa5a6Sopenharmony_ci        }
258c29fa5a6Sopenharmony_ci        callbacks_.erase(iter);
259c29fa5a6Sopenharmony_ci    }
260c29fa5a6Sopenharmony_ci}
261c29fa5a6Sopenharmony_ci} // namespace DeviceStatus
262c29fa5a6Sopenharmony_ci} // namespace Msdp
263c29fa5a6Sopenharmony_ci} // namespace OHOS
264