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