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