1f857971dSopenharmony_ci/*
2f857971dSopenharmony_ci * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3f857971dSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4f857971dSopenharmony_ci * you may not use this file except in compliance with the License.
5f857971dSopenharmony_ci * You may obtain a copy of the License at
6f857971dSopenharmony_ci *
7f857971dSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8f857971dSopenharmony_ci *
9f857971dSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10f857971dSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11f857971dSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12f857971dSopenharmony_ci * See the License for the specific language governing permissions and
13f857971dSopenharmony_ci * limitations under the License.
14f857971dSopenharmony_ci */
15f857971dSopenharmony_ci
16f857971dSopenharmony_ci#include "client.h"
17f857971dSopenharmony_ci
18f857971dSopenharmony_ci#include <cinttypes>
19f857971dSopenharmony_ci#include <condition_variable>
20f857971dSopenharmony_ci
21f857971dSopenharmony_ci#include "devicestatus_client.h"
22f857971dSopenharmony_ci#include "fd_listener.h"
23f857971dSopenharmony_ci#include "fi_log.h"
24f857971dSopenharmony_ci#include "proto.h"
25f857971dSopenharmony_ci#include "time_cost_chk.h"
26f857971dSopenharmony_ci#include "include/util.h"
27f857971dSopenharmony_ci
28f857971dSopenharmony_ci#undef LOG_TAG
29f857971dSopenharmony_ci#define LOG_TAG "Client"
30f857971dSopenharmony_ci
31f857971dSopenharmony_cinamespace OHOS {
32f857971dSopenharmony_cinamespace Msdp {
33f857971dSopenharmony_cinamespace DeviceStatus {
34f857971dSopenharmony_cinamespace {
35f857971dSopenharmony_ciconst std::string THREAD_NAME { "os_ClientEventHandler" };
36f857971dSopenharmony_ci} // namespace
37f857971dSopenharmony_ci
38f857971dSopenharmony_ciusing namespace AppExecFwk;
39f857971dSopenharmony_ciClient::~Client()
40f857971dSopenharmony_ci{
41f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
42f857971dSopenharmony_ci    Stop();
43f857971dSopenharmony_ci}
44f857971dSopenharmony_ci
45f857971dSopenharmony_civoid Client::SetEventHandler(EventHandlerPtr eventHandler)
46f857971dSopenharmony_ci{
47f857971dSopenharmony_ci    CHKPV(eventHandler);
48f857971dSopenharmony_ci    eventHandler_ = eventHandler;
49f857971dSopenharmony_ci}
50f857971dSopenharmony_ci
51f857971dSopenharmony_civoid Client::MarkIsEventHandlerChanged(EventHandlerPtr eventHandler)
52f857971dSopenharmony_ci{
53f857971dSopenharmony_ci    CHKPV(eventHandler);
54f857971dSopenharmony_ci    CHKPV(eventHandler_);
55f857971dSopenharmony_ci    auto currentRunner = eventHandler_->GetEventRunner();
56f857971dSopenharmony_ci    CHKPV(currentRunner);
57f857971dSopenharmony_ci    auto newEventRunner = eventHandler->GetEventRunner();
58f857971dSopenharmony_ci    CHKPV(newEventRunner);
59f857971dSopenharmony_ci    isEventHandlerChanged_ = false;
60f857971dSopenharmony_ci    if (currentRunner->GetRunnerThreadName() != newEventRunner->GetRunnerThreadName()) {
61f857971dSopenharmony_ci        isEventHandlerChanged_ = true;
62f857971dSopenharmony_ci        FI_HILOGD("Event handler changed");
63f857971dSopenharmony_ci    }
64f857971dSopenharmony_ci    FI_HILOGD("Current handler name:%{public}s, New handler name:%{public}s",
65f857971dSopenharmony_ci        currentRunner->GetRunnerThreadName().c_str(), newEventRunner->GetRunnerThreadName().c_str());
66f857971dSopenharmony_ci}
67f857971dSopenharmony_ci
68f857971dSopenharmony_cibool Client::SendMessage(const NetPacket &pkt) const
69f857971dSopenharmony_ci{
70f857971dSopenharmony_ci    return SendMsg(pkt);
71f857971dSopenharmony_ci}
72f857971dSopenharmony_ci
73f857971dSopenharmony_cibool Client::GetCurrentConnectedStatus() const
74f857971dSopenharmony_ci{
75f857971dSopenharmony_ci    return GetConnectedStatus();
76f857971dSopenharmony_ci}
77f857971dSopenharmony_ci
78f857971dSopenharmony_ciIClientPtr Client::GetSharedPtr()
79f857971dSopenharmony_ci{
80f857971dSopenharmony_ci    return shared_from_this();
81f857971dSopenharmony_ci}
82f857971dSopenharmony_ci
83f857971dSopenharmony_cibool Client::Start()
84f857971dSopenharmony_ci{
85f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
86f857971dSopenharmony_ci    auto callback = [this](const StreamClient &client, NetPacket &pkt) {
87f857971dSopenharmony_ci        this->OnMsgHandler(client, pkt);
88f857971dSopenharmony_ci    };
89f857971dSopenharmony_ci    if (!StartClient(callback)) {
90f857971dSopenharmony_ci        FI_HILOGE("Client startup failed");
91f857971dSopenharmony_ci        Stop();
92f857971dSopenharmony_ci        return false;
93f857971dSopenharmony_ci    }
94f857971dSopenharmony_ci    if (!StartEventRunner()) {
95f857971dSopenharmony_ci        FI_HILOGE("Start runner failed");
96f857971dSopenharmony_ci        Stop();
97f857971dSopenharmony_ci        return false;
98f857971dSopenharmony_ci    }
99f857971dSopenharmony_ci    FI_HILOGD("Client started successfully");
100f857971dSopenharmony_ci    return true;
101f857971dSopenharmony_ci}
102f857971dSopenharmony_ci
103f857971dSopenharmony_cibool Client::StartEventRunner()
104f857971dSopenharmony_ci{
105f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
106f857971dSopenharmony_ci    CHK_PID_AND_TID();
107f857971dSopenharmony_ci    auto runner = AppExecFwk::EventRunner::Create(THREAD_NAME);
108f857971dSopenharmony_ci    CHKPF(runner);
109f857971dSopenharmony_ci    eventHandler_ = std::make_shared<AppExecFwk::EventHandler>(runner);
110f857971dSopenharmony_ci
111f857971dSopenharmony_ci    FI_HILOGI("Create event handler, thread name:%{public}s", runner->GetRunnerThreadName().c_str());
112f857971dSopenharmony_ci
113f857971dSopenharmony_ci    if (hasConnected_ && fd_ >= 0) {
114f857971dSopenharmony_ci        if (isListening_) {
115f857971dSopenharmony_ci            FI_HILOGI("File fd is in listening");
116f857971dSopenharmony_ci            return true;
117f857971dSopenharmony_ci        }
118f857971dSopenharmony_ci        if (!AddFdListener(fd_)) {
119f857971dSopenharmony_ci            FI_HILOGE("Add fd listener failed");
120f857971dSopenharmony_ci            return false;
121f857971dSopenharmony_ci        }
122f857971dSopenharmony_ci    } else {
123f857971dSopenharmony_ci        if (!eventHandler_->PostTask([this] { this->OnReconnect(); }, CLIENT_RECONNECT_COOLING_TIME)) {
124f857971dSopenharmony_ci            FI_HILOGE("Send reconnect event failed");
125f857971dSopenharmony_ci            return false;
126f857971dSopenharmony_ci        }
127f857971dSopenharmony_ci    }
128f857971dSopenharmony_ci    return true;
129f857971dSopenharmony_ci}
130f857971dSopenharmony_ci
131f857971dSopenharmony_cibool Client::AddFdListener(int32_t fd)
132f857971dSopenharmony_ci{
133f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
134f857971dSopenharmony_ci    if (fd < 0) {
135f857971dSopenharmony_ci        FI_HILOGE("Invalid fd:%{public}d", fd);
136f857971dSopenharmony_ci        return false;
137f857971dSopenharmony_ci    }
138f857971dSopenharmony_ci    CHKPF(eventHandler_);
139f857971dSopenharmony_ci    auto fdListener = std::make_shared<FdListener>(GetSharedPtr());
140f857971dSopenharmony_ci    auto errCode = eventHandler_->AddFileDescriptorListener(fd, FILE_DESCRIPTOR_INPUT_EVENT, fdListener,
141f857971dSopenharmony_ci        "DeviceStatusTask");
142f857971dSopenharmony_ci    if (errCode != ERR_OK) {
143f857971dSopenharmony_ci        FI_HILOGE("Add fd listener failed, fd:%{public}d, code:%{public}u, str:%{public}s", fd, errCode,
144f857971dSopenharmony_ci            GetErrorStr(errCode).c_str());
145f857971dSopenharmony_ci        return false;
146f857971dSopenharmony_ci    }
147f857971dSopenharmony_ci    isRunning_ = true;
148f857971dSopenharmony_ci    FI_HILOGI("serverFd:%{public}d was listening, mask:%{public}u," PRIu64, fd, FILE_DESCRIPTOR_INPUT_EVENT);
149f857971dSopenharmony_ci    return true;
150f857971dSopenharmony_ci}
151f857971dSopenharmony_ci
152f857971dSopenharmony_cibool Client::DelFdListener(int32_t fd)
153f857971dSopenharmony_ci{
154f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
155f857971dSopenharmony_ci    CHKPF(eventHandler_);
156f857971dSopenharmony_ci    if (fd >= 0) {
157f857971dSopenharmony_ci        eventHandler_->RemoveFileDescriptorListener(fd);
158f857971dSopenharmony_ci        FI_HILOGI("Remove file descriptor listener success");
159f857971dSopenharmony_ci    } else {
160f857971dSopenharmony_ci        FI_HILOGE("Invalid fd:%{public}d", fd);
161f857971dSopenharmony_ci    }
162f857971dSopenharmony_ci    auto runner = eventHandler_->GetEventRunner();
163f857971dSopenharmony_ci    CHKPF(runner);
164f857971dSopenharmony_ci    if (runner->GetRunnerThreadName() == THREAD_NAME) {
165f857971dSopenharmony_ci        eventHandler_->RemoveAllEvents();
166f857971dSopenharmony_ci        FI_HILOGI("Remove all events success");
167f857971dSopenharmony_ci    }
168f857971dSopenharmony_ci    isRunning_ = false;
169f857971dSopenharmony_ci    return true;
170f857971dSopenharmony_ci}
171f857971dSopenharmony_ci
172f857971dSopenharmony_civoid Client::OnPacket(NetPacket &pkt)
173f857971dSopenharmony_ci{
174f857971dSopenharmony_ci    recvFun_(*this, pkt);
175f857971dSopenharmony_ci}
176f857971dSopenharmony_ci
177f857971dSopenharmony_civoid Client::OnRecvMsg(const char *buf, size_t size)
178f857971dSopenharmony_ci{
179f857971dSopenharmony_ci    CHKPV(buf);
180f857971dSopenharmony_ci    if (size == 0 || size > MAX_PACKET_BUF_SIZE) {
181f857971dSopenharmony_ci        FI_HILOGE("Invalid input param size, size:%{public}zu", size);
182f857971dSopenharmony_ci        return;
183f857971dSopenharmony_ci    }
184f857971dSopenharmony_ci    if (!circBuf_.Write(buf, size)) {
185f857971dSopenharmony_ci        FI_HILOGW("Write data failed, size:%{public}zu", size);
186f857971dSopenharmony_ci    }
187f857971dSopenharmony_ci    OnReadPackets(circBuf_, [this](NetPacket &pkt) { this->OnPacket(pkt); });
188f857971dSopenharmony_ci}
189f857971dSopenharmony_ci
190f857971dSopenharmony_ciint32_t Client::Reconnect()
191f857971dSopenharmony_ci{
192f857971dSopenharmony_ci    return StartConnect();
193f857971dSopenharmony_ci}
194f857971dSopenharmony_ci
195f857971dSopenharmony_civoid Client::OnReconnect()
196f857971dSopenharmony_ci{
197f857971dSopenharmony_ci    if (Reconnect() == RET_OK) {
198f857971dSopenharmony_ci        FI_HILOGI("Reconnect ok");
199f857971dSopenharmony_ci        return;
200f857971dSopenharmony_ci    }
201f857971dSopenharmony_ci    CHKPV(eventHandler_);
202f857971dSopenharmony_ci    if (!eventHandler_->PostTask([this] { this->OnReconnect(); }, CLIENT_RECONNECT_COOLING_TIME)) {
203f857971dSopenharmony_ci        FI_HILOGE("Post reconnect event failed");
204f857971dSopenharmony_ci    }
205f857971dSopenharmony_ci}
206f857971dSopenharmony_ci
207f857971dSopenharmony_civoid Client::OnDisconnect()
208f857971dSopenharmony_ci{
209f857971dSopenharmony_ci    OnDisconnected();
210f857971dSopenharmony_ci}
211f857971dSopenharmony_ci
212f857971dSopenharmony_civoid Client::RegisterConnectedFunction(ConnectCallback function)
213f857971dSopenharmony_ci{
214f857971dSopenharmony_ci    funConnected_ = function;
215f857971dSopenharmony_ci}
216f857971dSopenharmony_ci
217f857971dSopenharmony_civoid Client::RegisterDisconnectedFunction(ConnectCallback fun)
218f857971dSopenharmony_ci{
219f857971dSopenharmony_ci    funDisconnected_ = fun;
220f857971dSopenharmony_ci}
221f857971dSopenharmony_ci
222f857971dSopenharmony_civoid Client::OnDisconnected()
223f857971dSopenharmony_ci{
224f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
225f857971dSopenharmony_ci    FI_HILOGI("Disconnected from server, fd:%{public}d", fd_);
226f857971dSopenharmony_ci    hasConnected_ = false;
227f857971dSopenharmony_ci    isListening_ = false;
228f857971dSopenharmony_ci    if (funDisconnected_ != nullptr) {
229f857971dSopenharmony_ci        FI_HILOGI("Execute funDisconnected");
230f857971dSopenharmony_ci        funDisconnected_();
231f857971dSopenharmony_ci    }
232f857971dSopenharmony_ci    if (!DelFdListener(fd_)) {
233f857971dSopenharmony_ci        FI_HILOGW("Delete fd listener failed");
234f857971dSopenharmony_ci    }
235f857971dSopenharmony_ci    StreamClient::Stop();
236f857971dSopenharmony_ci    if (hasClient_ && eventHandler_ != nullptr) {
237f857971dSopenharmony_ci        if (!eventHandler_->PostTask([this] { this->OnReconnect(); }, CLIENT_RECONNECT_COOLING_TIME)) {
238f857971dSopenharmony_ci            FI_HILOGE("Send reconnect event task failed");
239f857971dSopenharmony_ci        }
240f857971dSopenharmony_ci    }
241f857971dSopenharmony_ci}
242f857971dSopenharmony_ci
243f857971dSopenharmony_civoid Client::OnConnected()
244f857971dSopenharmony_ci{
245f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
246f857971dSopenharmony_ci    FI_HILOGI("Connection to server succeeded, fd:%{public}d", GetFd());
247f857971dSopenharmony_ci    hasConnected_ = true;
248f857971dSopenharmony_ci    if (funConnected_ != nullptr) {
249f857971dSopenharmony_ci        FI_HILOGI("Execute funConnected");
250f857971dSopenharmony_ci        funConnected_();
251f857971dSopenharmony_ci    }
252f857971dSopenharmony_ci    if (hasClient_ && !isRunning_ && fd_ >= 0 && eventHandler_ != nullptr) {
253f857971dSopenharmony_ci        if (!AddFdListener(fd_)) {
254f857971dSopenharmony_ci            FI_HILOGE("Add fd listener failed");
255f857971dSopenharmony_ci            return;
256f857971dSopenharmony_ci        }
257f857971dSopenharmony_ci        isListening_ = true;
258f857971dSopenharmony_ci    }
259f857971dSopenharmony_ci}
260f857971dSopenharmony_ci
261f857971dSopenharmony_ciint32_t Client::Socket()
262f857971dSopenharmony_ci{
263f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
264f857971dSopenharmony_ci    return -1;
265f857971dSopenharmony_ci}
266f857971dSopenharmony_ci
267f857971dSopenharmony_civoid Client::Stop()
268f857971dSopenharmony_ci{
269f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
270f857971dSopenharmony_ci    StreamClient::Stop();
271f857971dSopenharmony_ci    isRunning_ = false;
272f857971dSopenharmony_ci    if (eventHandler_ != nullptr) {
273f857971dSopenharmony_ci        auto runner = eventHandler_->GetEventRunner();
274f857971dSopenharmony_ci        CHKPV(runner);
275f857971dSopenharmony_ci        if (runner->GetRunnerThreadName() == THREAD_NAME) {
276f857971dSopenharmony_ci            runner->Stop();
277f857971dSopenharmony_ci            eventHandler_->RemoveAllEvents();
278f857971dSopenharmony_ci            eventHandler_->RemoveAllFileDescriptorListeners();
279f857971dSopenharmony_ci            FI_HILOGI("Remove all file descriptor listeners success");
280f857971dSopenharmony_ci        }
281f857971dSopenharmony_ci    }
282f857971dSopenharmony_ci}
283f857971dSopenharmony_ci
284f857971dSopenharmony_civoid Client::OnMsgHandler(const StreamClient &client, NetPacket &pkt)
285f857971dSopenharmony_ci{
286f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
287f857971dSopenharmony_ci    auto id = pkt.GetMsgId();
288f857971dSopenharmony_ci    TimeCostChk chk("Client::OnMsgHandler", "overtime 300(us)", MAX_OVER_TIME, id);
289f857971dSopenharmony_ci    auto callback = GetMsgCallback(id);
290f857971dSopenharmony_ci    if (callback == nullptr) {
291f857971dSopenharmony_ci        FI_HILOGE("Unknown msg id:%{public}d", id);
292f857971dSopenharmony_ci        return;
293f857971dSopenharmony_ci    }
294f857971dSopenharmony_ci    int32_t ret = (*callback)(client, pkt);
295f857971dSopenharmony_ci    if (ret < 0) {
296f857971dSopenharmony_ci        FI_HILOGE("Msg handling failed, id:%{public}d, ret:%{public}d", id, ret);
297f857971dSopenharmony_ci        return;
298f857971dSopenharmony_ci    }
299f857971dSopenharmony_ci}
300f857971dSopenharmony_ci
301f857971dSopenharmony_ciconst std::string& Client::GetErrorStr(ErrCode code) const
302f857971dSopenharmony_ci{
303f857971dSopenharmony_ci    const static std::string defErrString = "Unknown event handler error!";
304f857971dSopenharmony_ci    const static std::map<ErrCode, std::string> mapStrings = {
305f857971dSopenharmony_ci        { ERR_OK, "ERR_OK" },
306f857971dSopenharmony_ci        { EVENT_HANDLER_ERR_INVALID_PARAM, "Invalid parameters" },
307f857971dSopenharmony_ci        { EVENT_HANDLER_ERR_NO_EVENT_RUNNER, "Have not set event runner yet" },
308f857971dSopenharmony_ci        { EVENT_HANDLER_ERR_FD_NOT_SUPPORT, "Not support to listen file descriptors" },
309f857971dSopenharmony_ci        { EVENT_HANDLER_ERR_FD_ALREADY, "File descriptor is already in listening" },
310f857971dSopenharmony_ci        { EVENT_HANDLER_ERR_FD_FAILED, "Failed to listen file descriptor" },
311f857971dSopenharmony_ci        { EVENT_HANDLER_ERR_RUNNER_NO_PERMIT, "No permit to start or stop deposited event runner" },
312f857971dSopenharmony_ci        { EVENT_HANDLER_ERR_RUNNER_ALREADY, "Event runner is already running" }
313f857971dSopenharmony_ci    };
314f857971dSopenharmony_ci    auto it = mapStrings.find(code);
315f857971dSopenharmony_ci    if (it != mapStrings.end()) {
316f857971dSopenharmony_ci        return it->second;
317f857971dSopenharmony_ci    }
318f857971dSopenharmony_ci    return defErrString;
319f857971dSopenharmony_ci}
320f857971dSopenharmony_ci} // namespace DeviceStatus
321f857971dSopenharmony_ci} // namespace Msdp
322f857971dSopenharmony_ci} // namespace OHOS
323