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 "stream_server.h"
17
18#include <cinttypes>
19
20#include <sys/socket.h>
21
22#include "sensor_errors.h"
23
24#undef LOG_TAG
25#define LOG_TAG "StreamServer"
26
27namespace OHOS {
28namespace Sensors {
29namespace {
30constexpr int32_t INVALID_PID = -1;
31constexpr int32_t INVALID_FD = -1;
32} // namespace
33
34StreamServer::~StreamServer()
35{
36    CALL_LOG_ENTER;
37    std::lock_guard<std::mutex> sessionLock(sessionMutex_);
38    idxPidMap_.clear();
39    for (const auto &item : sessionsMap_) {
40        item.second->Close();
41    }
42    sessionsMap_.clear();
43}
44
45int32_t StreamServer::GetClientFd(int32_t pid)
46{
47    std::lock_guard<std::mutex> sessionLock(sessionMutex_);
48    auto it = idxPidMap_.find(pid);
49    return it == idxPidMap_.end() ? INVALID_FD : it->second;
50}
51
52int32_t StreamServer::GetClientPid(int32_t fd)
53{
54    std::lock_guard<std::mutex> sessionLock(sessionMutex_);
55    auto it = sessionsMap_.find(fd);
56    return it == sessionsMap_.end() ? INVALID_PID : it->second->GetPid();
57}
58
59SessionPtr StreamServer::GetSession(int32_t fd)
60{
61    std::lock_guard<std::mutex> sessionLock(sessionMutex_);
62    auto it = sessionsMap_.find(fd);
63    if (it == sessionsMap_.end()) {
64        SEN_HILOGE("Session not found");
65        return nullptr;
66    }
67    CHKPP(it->second);
68    return it->second->GetSharedPtr();
69}
70
71SessionPtr StreamServer::GetSessionByPid(int32_t pid)
72{
73    int32_t fd = GetClientFd(pid);
74    if (fd <= 0) {
75        SEN_HILOGE("Session not found");
76        return nullptr;
77    }
78    return GetSession(fd);
79}
80
81int32_t StreamServer::AddSocketPairInfo(int32_t uid, int32_t pid, int32_t tokenType,
82    int32_t &serverFd, int32_t &clientFd)
83{
84    CALL_LOG_ENTER;
85    int32_t sockFds[2] = { -1 };
86    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockFds) != 0) {
87        SEN_HILOGE("Socketpair failed, errno:%{public}d", errno);
88        return ERROR;
89    }
90    serverFd = sockFds[0];
91    clientFd = sockFds[1];
92    if (serverFd < 0 || clientFd < 0) {
93        SEN_HILOGE("ServerFd or clientFd is invalid");
94        return ERROR;
95    }
96    static constexpr size_t bufferSize = 32 * 1024;
97    SessionPtr sess = nullptr;
98    if (setsockopt(serverFd, SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)) != 0) {
99        SEN_HILOGE("Setsockopt serverFd send buffer size failed, errno:%{public}d", errno);
100        goto CLOSE_SOCK;
101    }
102    if (setsockopt(serverFd, SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)) != 0) {
103        SEN_HILOGE("Setsockopt serverFd recv buffer size failed, errno:%{public}d", errno);
104        goto CLOSE_SOCK;
105    }
106    if (setsockopt(clientFd, SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)) != 0) {
107        SEN_HILOGE("Setsockopt clientFd send buffer size failed, errno:%{public}d", errno);
108        goto CLOSE_SOCK;
109    }
110    if (setsockopt(clientFd, SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)) != 0) {
111        SEN_HILOGE("Setsockopt clientFd recv buffer size failed, errno:%{public}d", errno);
112        goto CLOSE_SOCK;
113    }
114    sess = std::make_shared<StreamSession>("", serverFd, uid, pid);
115    sess->SetTokenType(tokenType);
116    if (!AddSession(sess)) {
117        SEN_HILOGE("AddSession fail");
118        goto CLOSE_SOCK;
119    }
120    return ERR_OK;
121
122CLOSE_SOCK:
123    close(serverFd);
124    close(clientFd);
125    return ERROR;
126}
127
128bool StreamServer::AddSession(SessionPtr sess)
129{
130    CALL_LOG_ENTER;
131    CHKPF(sess);
132    auto fd = sess->GetFd();
133    if (fd < 0) {
134        SEN_HILOGE("Fd is Invalid");
135        return false;
136    }
137    auto pid = sess->GetPid();
138    if (pid <= 0) {
139        SEN_HILOGE("Pid is invalid");
140        return false;
141    }
142    std::lock_guard<std::mutex> sessionLock(sessionMutex_);
143    if (sessionsMap_.size() > MAX_SESSON_ALARM) {
144        SEN_HILOGE("Too many clients, size:%{public}zu", sessionsMap_.size());
145        return false;
146    }
147    idxPidMap_[pid] = fd;
148    sessionsMap_[fd] = sess;
149    return true;
150}
151
152void StreamServer::DelSession(int32_t pid)
153{
154    CALL_LOG_ENTER;
155    std::lock_guard<std::mutex> sessionLock(sessionMutex_);
156    auto pidIt = idxPidMap_.find(pid);
157    if (pidIt == idxPidMap_.end()) {
158        SEN_HILOGW("Pid session not exist");
159        return;
160    }
161    int32_t fd = pidIt->second;
162    idxPidMap_.erase(pidIt);
163    auto fdIt = sessionsMap_.find(fd);
164    if (fdIt != sessionsMap_.end()) {
165        sessionsMap_.erase(fdIt);
166    }
167    if (fd >= 0) {
168        int32_t ret = close(fd);
169        if (ret != 0) {
170            SEN_HILOGE("Socket fd close failed, ret:%{public}d, errno:%{public}d", ret, errno);
171        }
172    }
173}
174} // namespace Sensors
175} // namespace OHOS