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 
31 namespace OHOS {
32 namespace Msdp {
33 namespace DeviceStatus {
34 namespace {
35 const std::string THREAD_NAME { "os_ClientEventHandler" };
36 } // namespace
37 
38 using namespace AppExecFwk;
~Client()39 Client::~Client()
40 {
41     CALL_DEBUG_ENTER;
42     Stop();
43 }
44 
SetEventHandler(EventHandlerPtr eventHandler)45 void Client::SetEventHandler(EventHandlerPtr eventHandler)
46 {
47     CHKPV(eventHandler);
48     eventHandler_ = eventHandler;
49 }
50 
MarkIsEventHandlerChanged(EventHandlerPtr eventHandler)51 void 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 
SendMessage(const NetPacket & pkt) const68 bool Client::SendMessage(const NetPacket &pkt) const
69 {
70     return SendMsg(pkt);
71 }
72 
GetCurrentConnectedStatus() const73 bool Client::GetCurrentConnectedStatus() const
74 {
75     return GetConnectedStatus();
76 }
77 
GetSharedPtr()78 IClientPtr Client::GetSharedPtr()
79 {
80     return shared_from_this();
81 }
82 
Start()83 bool 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 
StartEventRunner()103 bool 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 
AddFdListener(int32_t fd)131 bool 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 
DelFdListener(int32_t fd)152 bool 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 
OnPacket(NetPacket & pkt)172 void Client::OnPacket(NetPacket &pkt)
173 {
174     recvFun_(*this, pkt);
175 }
176 
OnRecvMsg(const char * buf,size_t size)177 void 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 
Reconnect()190 int32_t Client::Reconnect()
191 {
192     return StartConnect();
193 }
194 
OnReconnect()195 void 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 
OnDisconnect()207 void Client::OnDisconnect()
208 {
209     OnDisconnected();
210 }
211 
RegisterConnectedFunction(ConnectCallback function)212 void Client::RegisterConnectedFunction(ConnectCallback function)
213 {
214     funConnected_ = function;
215 }
216 
RegisterDisconnectedFunction(ConnectCallback fun)217 void Client::RegisterDisconnectedFunction(ConnectCallback fun)
218 {
219     funDisconnected_ = fun;
220 }
221 
OnDisconnected()222 void 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 
OnConnected()243 void 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 
Socket()261 int32_t Client::Socket()
262 {
263     CALL_DEBUG_ENTER;
264     return -1;
265 }
266 
Stop()267 void 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 
OnMsgHandler(const StreamClient & client,NetPacket & pkt)284 void 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 
GetErrorStr(ErrCode code) const301 const 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