1 /*
2  * Copyright (c) 2022 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 #define LOG_TAG "SoftBusClient"
17 #include "softbus_client.h"
18 
19 #include "communicator_context.h"
20 #include "communication/connect_manager.h"
21 #include "device_manager_adapter.h"
22 #include "inner_socket.h"
23 #include "kvstore_utils.h"
24 #include "log_print.h"
25 #include "softbus_error_code.h"
26 
27 namespace OHOS::AppDistributedKv {
28 using namespace OHOS::DistributedKv;
29 using DmAdapter = OHOS::DistributedData::DeviceManagerAdapter;
30 using Context = DistributedData::CommunicatorContext;
SoftBusClient(const PipeInfo& pipeInfo, const DeviceId& deviceId, uint32_t type)31 SoftBusClient::SoftBusClient(const PipeInfo& pipeInfo, const DeviceId& deviceId, uint32_t type)
32     : type_(type), pipe_(pipeInfo), device_(deviceId)
33 {
34     mtu_ = DEFAULT_MTU_SIZE;
35 }
36 
~SoftBusClient()37 SoftBusClient::~SoftBusClient()
38 {
39     ZLOGI("Shutdown socket:%{public}d", socket_);
40     if (socket_ > 0) {
41         Shutdown(socket_);
42     }
43 }
44 
operator ==(int32_t socket) const45 bool SoftBusClient::operator==(int32_t socket) const
46 {
47     return socket_ == socket;
48 }
49 
operator ==(const std::string &deviceId) const50 bool SoftBusClient::operator==(const std::string &deviceId) const
51 {
52     return device_.deviceId == deviceId;
53 }
54 
GetMtuSize() const55 uint32_t SoftBusClient::GetMtuSize() const
56 {
57     ZLOGD("get mtu size socket:%{public}d mtu:%{public}d", socket_, mtu_);
58     return mtu_;
59 }
60 
GetTimeout() const61 uint32_t SoftBusClient::GetTimeout() const
62 {
63     return DEFAULT_TIMEOUT;
64 }
65 
SendData(const DataInfo &dataInfo, const ISocketListener *listener)66 Status SoftBusClient::SendData(const DataInfo &dataInfo, const ISocketListener *listener)
67 {
68     std::lock_guard<std::mutex> lock(mutex_);
69     auto result = CheckStatus();
70     if (result != Status::SUCCESS) {
71         return result;
72     }
73     ZLOGD("send data socket:%{public}d, data size:%{public}u.", socket_, dataInfo.length);
74     int32_t ret = SendBytes(socket_, dataInfo.data, dataInfo.length);
75     if (ret != SOFTBUS_OK) {
76         expireTime_ = std::chrono::steady_clock::now();
77         ZLOGE("send data to socket%{public}d failed, ret:%{public}d.", socket_, ret);
78         return Status::ERROR;
79     }
80     expireTime_ = CalcExpireTime();
81     return Status::SUCCESS;
82 }
83 
OpenConnect(const ISocketListener *listener)84 Status SoftBusClient::OpenConnect(const ISocketListener *listener)
85 {
86     std::lock_guard<std::mutex> lock(mutex_);
87     auto status = CheckStatus();
88     if (status == Status::SUCCESS || status == Status::RATE_LIMIT) {
89         return status;
90     }
91     if (isOpening_.exchange(true)) {
92         return Status::RATE_LIMIT;
93     }
94     SocketInfo socketInfo;
95     std::string peerName = pipe_.pipeId;
96     socketInfo.peerName = const_cast<char *>(peerName.c_str());
97     std::string networkId = DmAdapter::GetInstance().ToNetworkID(device_.deviceId);
98     socketInfo.peerNetworkId = const_cast<char *>(networkId.c_str());
99     std::string clientName = pipe_.pipeId;
100     socketInfo.name = const_cast<char *>(clientName.c_str());
101     std::string pkgName = "ohos.distributeddata";
102     socketInfo.pkgName = pkgName.data();
103     socketInfo.dataType = DATA_TYPE_BYTES;
104     int32_t clientSocket = Socket(socketInfo);
105     if (clientSocket <= 0) {
106         isOpening_.store(false);
107         ZLOGE("Create the client Socket:%{public}d failed, peerName:%{public}s", clientSocket, socketInfo.peerName);
108         return Status::NETWORK_ERROR;
109     }
110     auto task = [type = type_, clientSocket, listener, client = shared_from_this()]() {
111         if (client == nullptr) {
112             ZLOGE("OpenSessionByAsync client is nullptr.");
113             return;
114         }
115         ZLOGI("Bind Start, device:%{public}s socket:%{public}d type:%{public}u",
116             KvStoreUtils::ToBeAnonymous(client->device_.deviceId).c_str(), clientSocket, type);
117         auto status = client->Open(clientSocket, QOS_INFOS[type % QOS_BUTT], listener);
118         if (status == Status::SUCCESS) {
119             Context::GetInstance().NotifySessionReady(client->device_.deviceId);
120         }
121         client->isOpening_.store(false);
122     };
123     Context::GetInstance().GetThreadPool()->Execute(task);
124     return Status::RATE_LIMIT;
125 }
126 
CheckStatus()127 Status SoftBusClient::CheckStatus()
128 {
129     if (bindState_ == 0) {
130         return Status::SUCCESS;
131     }
132     if (isOpening_.load()) {
133         return Status::RATE_LIMIT;
134     }
135     if (bindState_ == 0) {
136         return Status::SUCCESS;
137     }
138     return Status::ERROR;
139 }
140 
Open(int32_t socket, const QosTV qos[], const ISocketListener *listener)141 Status SoftBusClient::Open(int32_t socket, const QosTV qos[], const ISocketListener *listener)
142 {
143     int32_t status = ::Bind(socket, qos, QOS_COUNT, listener);
144     ZLOGI("Bind %{public}s,session:%{public}s,socketId:%{public}d",
145         KvStoreUtils::ToBeAnonymous(device_.deviceId).c_str(), pipe_.pipeId.c_str(), socket);
146 
147     if (status != 0) {
148         ZLOGE("[Bind] device:%{public}s socket failed, session:%{public}s,result:%{public}d",
149             KvStoreUtils::ToBeAnonymous(device_.deviceId).c_str(), pipe_.pipeId.c_str(), status);
150         ::Shutdown(socket);
151         return Status::NETWORK_ERROR;
152     }
153     UpdateExpireTime();
154     uint32_t mtu = 0;
155     std::tie(status, mtu) = GetMtu(socket);
156     if (status != SOFTBUS_OK) {
157         ZLOGE("GetMtu failed, session:%{public}s, socket:%{public}d", pipe_.pipeId.c_str(), socket_);
158         return Status::NETWORK_ERROR;
159     }
160     {
161         std::lock_guard<std::mutex> lock(mutex_);
162         socket_ = socket;
163         mtu_ = mtu;
164         bindState_ = status;
165     }
166     ZLOGI("open %{public}s, session:%{public}s success, socket:%{public}d",
167         KvStoreUtils::ToBeAnonymous(device_.deviceId).c_str(), pipe_.pipeId.c_str(), socket_);
168     ConnectManager::GetInstance()->OnSessionOpen(DmAdapter::GetInstance().GetDeviceInfo(device_.deviceId).networkId);
169     return Status::SUCCESS;
170 }
171 
GetExpireTime() const172 SoftBusClient::Time SoftBusClient::GetExpireTime() const
173 {
174     std::lock_guard<std::mutex> lock(mutex_);
175     return expireTime_;
176 }
177 
GetSocket() const178 int32_t SoftBusClient::GetSocket() const
179 {
180     return socket_;
181 }
182 
UpdateExpireTime()183 void SoftBusClient::UpdateExpireTime()
184 {
185     auto expireTime = CalcExpireTime();
186     std::lock_guard<std::mutex> lock(mutex_);
187     if (expireTime > expireTime_) {
188         expireTime_ = expireTime;
189     }
190 }
191 
GetMtu(int32_t socket)192 std::pair<int32_t, uint32_t> SoftBusClient::GetMtu(int32_t socket)
193 {
194     uint32_t mtu = 0;
195     auto ret = ::GetMtuSize(socket, &mtu);
196     return { ret, mtu };
197 }
198 
GetQoSType() const199 uint32_t SoftBusClient::GetQoSType() const
200 {
201     return type_ % QOS_COUNT;
202 }
203 
CalcExpireTime() const204 SoftBusClient::Time SoftBusClient::CalcExpireTime() const
205 {
206     auto delay = type_ == QOS_BR ? BR_CLOSE_DELAY : HML_CLOSE_DELAY;
207     return std::chrono::steady_clock::now() + delay;
208 }
209 } // namespace OHOS::AppDistributedKv