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_client.h"
17
18#include "event_handler.h"
19
20#include "devicestatus_define.h"
21#include "intention_identity.h"
22#include "socket_params.h"
23#include "time_cost_chk.h"
24
25#undef LOG_TAG
26#define LOG_TAG "SocketClient"
27
28namespace OHOS {
29namespace Msdp {
30namespace DeviceStatus {
31namespace {
32const std::string THREAD_NAME { "os_ClientEventHandler" };
33}
34
35SocketClient::SocketClient(std::shared_ptr<ITunnelClient> tunnel)
36    : tunnel_(tunnel)
37{
38    auto runner = AppExecFwk::EventRunner::Create(THREAD_NAME);
39    eventHandler_ = std::make_shared<AppExecFwk::EventHandler>(runner);
40}
41
42bool SocketClient::RegisterEvent(MessageId id, std::function<int32_t(const StreamClient&, NetPacket&)> callback)
43{
44    std::lock_guard guard(lock_);
45    auto [_, inserted] = callbacks_.emplace(id, callback);
46    return inserted;
47}
48
49void SocketClient::Start()
50{
51    CALL_DEBUG_ENTER;
52    Reconnect();
53}
54
55void SocketClient::Stop()
56{}
57
58bool SocketClient::Connect()
59{
60    CALL_DEBUG_ENTER;
61    if (socket_ != nullptr) {
62        return true;
63    }
64    auto socket = SocketConnection::Connect(
65        [this] { return this->Socket(); },
66        [this](NetPacket &pkt) { this->OnPacket(pkt); },
67        [this] { this->OnDisconnected(); });
68    CHKPF(socket);
69    CHKPF(eventHandler_);
70    auto errCode = eventHandler_->AddFileDescriptorListener(socket->GetFd(),
71        AppExecFwk::FILE_DESCRIPTOR_INPUT_EVENT, socket, "DeviceStatusTask");
72    if (errCode != ERR_OK) {
73        FI_HILOGE("AddFileDescriptorListener(%{public}d) failed (%{public}u)", socket->GetFd(), errCode);
74        return false;
75    }
76    socket_ = socket;
77    FI_HILOGD("SocketClient started successfully");
78    if (funConnected_ != nullptr) {
79        FI_HILOGI("Execute funConnected");
80        funConnected_();
81    }
82    return true;
83}
84
85int32_t SocketClient::Socket()
86{
87    CALL_DEBUG_ENTER;
88    std::shared_ptr<ITunnelClient> tunnel = tunnel_.lock();
89    CHKPR(tunnel, RET_ERR);
90    AllocSocketPairParam param { GetProgramName(), CONNECT_MODULE_TYPE_FI_CLIENT };
91    AllocSocketPairReply reply;
92
93    int32_t ret = tunnel->Control(Intention::SOCKET, SocketAction::SOCKET_ACTION_CONNECT, param, reply);
94    if (ret != RET_OK) {
95        FI_HILOGE("ITunnelClient::Control fail");
96        return -1;
97    }
98    FI_HILOGD("Connected to intention service (%{public}d)", reply.socketFd);
99    return reply.socketFd;
100}
101
102void SocketClient::OnPacket(NetPacket &pkt)
103{
104    CALL_DEBUG_ENTER;
105    std::lock_guard guard(lock_);
106    OnMsgHandler(*this, pkt);
107}
108
109void SocketClient::OnDisconnected()
110{
111    CALL_DEBUG_ENTER;
112    std::lock_guard guard(lock_);
113    if (socket_ != nullptr) {
114        eventHandler_->RemoveFileDescriptorListener(socket_->GetFd());
115        eventHandler_->RemoveAllEvents();
116        socket_.reset();
117    }
118    if (funDisconnected_ != nullptr) {
119        FI_HILOGI("Execute funDisconnected");
120        funDisconnected_();
121    }
122    if (!eventHandler_->PostTask([this] { this->Reconnect(); }, CLIENT_RECONNECT_COOLING_TIME)) {
123        FI_HILOGE("Failed to post reconnection task");
124    }
125}
126
127void SocketClient::Reconnect()
128{
129    std::lock_guard guard(lock_);
130    if (Connect()) {
131        return;
132    }
133    if (!eventHandler_->PostTask([this] { this->Reconnect(); }, CLIENT_RECONNECT_COOLING_TIME)) {
134        FI_HILOGE("Failed to post reconnection task");
135    }
136}
137
138void SocketClient::OnMsgHandler(const StreamClient &client, NetPacket &pkt)
139{
140    CALL_DEBUG_ENTER;
141    MessageId id = pkt.GetMsgId();
142    TimeCostChk chk("SocketClient::OnMsgHandler", "overtime 300(us)", MAX_OVER_TIME, id);
143    auto iter = callbacks_.find(id);
144    if (iter == callbacks_.end()) {
145        FI_HILOGE("Unknown msg id:%{public}d", id);
146        return;
147    }
148    int32_t ret = iter->second(client, pkt);
149    if (ret < 0) {
150        FI_HILOGE("Msg handling failed, id:%{public}d, ret:%{public}d", id, ret);
151    }
152}
153
154void SocketClient::RegisterConnectedFunction(ConnectCallback funConnected)
155{
156    funConnected_ = funConnected;
157}
158
159void SocketClient::RegisterDisconnectedFunction(ConnectCallback funDisconnected)
160{
161    funDisconnected_ = funDisconnected;
162}
163} // namespace DeviceStatus
164} // namespace Msdp
165} // namespace OHOS