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 softBusError_ = ret;
79 return Status::ERROR;
80 }
81 softBusError_ = 0;
82 expireTime_ = CalcExpireTime();
83 return Status::SUCCESS;
84 }
85
GetSoftBusError()86 int32_t SoftBusClient::GetSoftBusError()
87 {
88 std::lock_guard<std::mutex> lock(mutex_);
89 return softBusError_;
90 }
91
OpenConnect(const ISocketListener * listener)92 Status SoftBusClient::OpenConnect(const ISocketListener *listener)
93 {
94 std::lock_guard<std::mutex> lock(mutex_);
95 auto status = CheckStatus();
96 if (status == Status::SUCCESS || status == Status::RATE_LIMIT) {
97 return status;
98 }
99 if (isOpening_.exchange(true)) {
100 return Status::RATE_LIMIT;
101 }
102 SocketInfo socketInfo;
103 std::string peerName = pipe_.pipeId;
104 socketInfo.peerName = const_cast<char *>(peerName.c_str());
105 std::string networkId = DmAdapter::GetInstance().ToNetworkID(device_.deviceId);
106 socketInfo.peerNetworkId = const_cast<char *>(networkId.c_str());
107 std::string clientName = pipe_.pipeId;
108 socketInfo.name = const_cast<char *>(clientName.c_str());
109 std::string pkgName = "ohos.distributeddata";
110 socketInfo.pkgName = pkgName.data();
111 socketInfo.dataType = DATA_TYPE_BYTES;
112 int32_t clientSocket = Socket(socketInfo);
113 if (clientSocket <= 0) {
114 isOpening_.store(false);
115 ZLOGE("Create the client Socket:%{public}d failed, peerName:%{public}s", clientSocket, socketInfo.peerName);
116 return Status::NETWORK_ERROR;
117 }
118 auto task = [type = type_, clientSocket, listener, client = shared_from_this()]() {
119 if (client == nullptr) {
120 ZLOGE("OpenSessionByAsync client is nullptr.");
121 return;
122 }
123 ZLOGI("Bind Start, device:%{public}s socket:%{public}d type:%{public}u",
124 KvStoreUtils::ToBeAnonymous(client->device_.deviceId).c_str(), clientSocket, type);
125 int32_t status = client->Open(clientSocket, QOS_INFOS[type % QOS_BUTT], listener);
126 Context::GetInstance().NotifySessionReady(client->device_.deviceId, status);
127 client->isOpening_.store(false);
128 };
129 Context::GetInstance().GetThreadPool()->Execute(task);
130 return Status::RATE_LIMIT;
131 }
132
CheckStatus()133 Status SoftBusClient::CheckStatus()
134 {
135 if (bindState_ == 0) {
136 return Status::SUCCESS;
137 }
138 if (isOpening_.load()) {
139 return Status::RATE_LIMIT;
140 }
141 if (bindState_ == 0) {
142 return Status::SUCCESS;
143 }
144 return Status::ERROR;
145 }
146
Open(int32_t socket,const QosTV qos[],const ISocketListener * listener)147 int32_t SoftBusClient::Open(int32_t socket, const QosTV qos[], const ISocketListener *listener)
148 {
149 int32_t status = ::Bind(socket, qos, QOS_COUNT, listener);
150 ZLOGI("Bind %{public}s,session:%{public}s,socketId:%{public}d",
151 KvStoreUtils::ToBeAnonymous(device_.deviceId).c_str(), pipe_.pipeId.c_str(), socket);
152
153 if (status != 0) {
154 ZLOGE("[Bind] device:%{public}s socket failed, session:%{public}s,result:%{public}d",
155 KvStoreUtils::ToBeAnonymous(device_.deviceId).c_str(), pipe_.pipeId.c_str(), status);
156 ::Shutdown(socket);
157 return status;
158 }
159 UpdateExpireTime();
160 uint32_t mtu = 0;
161 std::tie(status, mtu) = GetMtu(socket);
162 if (status != SOFTBUS_OK) {
163 ZLOGE("GetMtu failed, session:%{public}s, socket:%{public}d, status:%{public}d", pipe_.pipeId.c_str(), socket_,
164 status);
165 return status;
166 }
167 {
168 std::lock_guard<std::mutex> lock(mutex_);
169 socket_ = socket;
170 mtu_ = mtu;
171 bindState_ = status;
172 }
173 ZLOGI("open %{public}s, session:%{public}s success, socket:%{public}d",
174 KvStoreUtils::ToBeAnonymous(device_.deviceId).c_str(), pipe_.pipeId.c_str(), socket_);
175 ConnectManager::GetInstance()->OnSessionOpen(DmAdapter::GetInstance().GetDeviceInfo(device_.deviceId).networkId);
176 return status;
177 }
178
GetExpireTime() const179 SoftBusClient::Time SoftBusClient::GetExpireTime() const
180 {
181 std::lock_guard<std::mutex> lock(mutex_);
182 return expireTime_;
183 }
184
GetSocket() const185 int32_t SoftBusClient::GetSocket() const
186 {
187 return socket_;
188 }
189
UpdateExpireTime()190 void SoftBusClient::UpdateExpireTime()
191 {
192 auto expireTime = CalcExpireTime();
193 std::lock_guard<std::mutex> lock(mutex_);
194 if (expireTime > expireTime_) {
195 expireTime_ = expireTime;
196 }
197 }
198
GetMtu(int32_t socket)199 std::pair<int32_t, uint32_t> SoftBusClient::GetMtu(int32_t socket)
200 {
201 uint32_t mtu = 0;
202 auto ret = ::GetMtuSize(socket, &mtu);
203 return { ret, mtu };
204 }
205
GetQoSType() const206 uint32_t SoftBusClient::GetQoSType() const
207 {
208 return type_ % QOS_COUNT;
209 }
210
CalcExpireTime() const211 SoftBusClient::Time SoftBusClient::CalcExpireTime() const
212 {
213 auto delay = type_ == QOS_BR ? BR_CLOSE_DELAY : HML_CLOSE_DELAY;
214 return std::chrono::steady_clock::now() + delay;
215 }
216 } // namespace OHOS::AppDistributedKv