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
18 #include "softbus_client.h"
19
20 #include "communicator_context.h"
21 #include "communication/connect_manager.h"
22 #include "inner_socket.h"
23 #include "log_print.h"
24 #include "softbus_error_code.h"
25 #include "utils/anonymous.h"
26
27 namespace OHOS::AppDistributedKv {
28 using namespace OHOS::DistributedKv;
29 using namespace OHOS::DistributedData;
30
SoftBusClient(const PipeInfo & pipeInfo,const DeviceId & deviceId,const std::string & networkId,uint32_t type,const SessionAccessInfo & accessInfo)31 SoftBusClient::SoftBusClient(const PipeInfo& pipeInfo, const DeviceId& deviceId, const std::string& networkId,
32 uint32_t type, const SessionAccessInfo &accessInfo) : type_(type), pipe_(pipeInfo), device_(deviceId),
33 networkId_(networkId), accessInfo_(accessInfo)
34 {
35 mtu_ = DEFAULT_MTU_SIZE;
36 }
37
~SoftBusClient()38 SoftBusClient::~SoftBusClient()
39 {
40 ZLOGI("Shutdown socket:%{public}d, deviceId:%{public}s", socket_, Anonymous::Change(device_.deviceId).c_str());
41 if (socket_ > 0) {
42 Shutdown(socket_);
43 }
44 }
45
operator ==(int32_t socket) const46 bool SoftBusClient::operator==(int32_t socket) const
47 {
48 return socket_ == socket;
49 }
50
operator ==(const std::string & deviceId) const51 bool SoftBusClient::operator==(const std::string &deviceId) const
52 {
53 return device_.deviceId == deviceId;
54 }
55
GetMtuBuffer() const56 uint32_t SoftBusClient::GetMtuBuffer() const
57 {
58 ZLOGD("get mtu size socket:%{public}d mtu:%{public}d", socket_, mtu_);
59 return mtu_;
60 }
61
GetTimeout() const62 uint32_t SoftBusClient::GetTimeout() const
63 {
64 return DEFAULT_TIMEOUT;
65 }
66
SendData(const DataInfo & dataInfo)67 Status SoftBusClient::SendData(const DataInfo &dataInfo)
68 {
69 std::lock_guard<std::mutex> lock(mutex_);
70 auto result = CheckStatus();
71 if (result != Status::SUCCESS) {
72 return result;
73 }
74 ZLOGD("send data socket:%{public}d, data size:%{public}u.", socket_, dataInfo.length);
75 int32_t ret = SendBytes(socket_, dataInfo.data, dataInfo.length);
76 if (ret != SOFTBUS_OK) {
77 expireTime_ = std::chrono::steady_clock::now();
78 ZLOGE("send data to socket%{public}d failed, ret:%{public}d.", socket_, ret);
79 softBusError_ = ret;
80 return Status::ERROR;
81 }
82 softBusError_ = 0;
83 expireTime_ = CalcExpireTime();
84 return Status::SUCCESS;
85 }
86
GetSoftBusError()87 int32_t SoftBusClient::GetSoftBusError()
88 {
89 std::lock_guard<std::mutex> lock(mutex_);
90 return softBusError_;
91 }
92
OpenConnect(const ISocketListener * listener)93 Status SoftBusClient::OpenConnect(const ISocketListener *listener)
94 {
95 std::lock_guard<std::mutex> lock(mutex_);
96 auto status = CheckStatus();
97 if (status == Status::SUCCESS || status == Status::RATE_LIMIT) {
98 return status;
99 }
100 if (isOpening_.exchange(true)) {
101 return Status::RATE_LIMIT;
102 }
103 int32_t clientSocket = CreateSocket();
104 if (clientSocket <= 0) {
105 isOpening_.store(false);
106 return Status::NETWORK_ERROR;
107 }
108 auto task = [type = type_, clientSocket, listener, client = shared_from_this()]() {
109 if (client == nullptr) {
110 ZLOGE("OpenSessionByAsync client is nullptr.");
111 return;
112 }
113 ZLOGI("Bind Start, device:%{public}s socket:%{public}d type:%{public}u",
114 Anonymous::Change(client->device_.deviceId).c_str(), clientSocket, type);
115 int32_t status = client->Open(clientSocket, type, listener);
116 CommunicatorContext::GetInstance().NotifySessionReady(client->device_.deviceId, status);
117 client->isOpening_.store(false);
118 };
119 auto executorPool = CommunicatorContext::GetInstance().GetThreadPool();
120 if (executorPool == nullptr) {
121 return Status::NETWORK_ERROR;
122 }
123 executorPool->Execute(task);
124 return Status::RATE_LIMIT;
125 }
126
CreateSocket() const127 int32_t SoftBusClient::CreateSocket() const
128 {
129 SocketInfo socketInfo;
130 std::string peerName = pipe_.pipeId;
131 socketInfo.peerName = const_cast<char *>(peerName.c_str());
132 auto networkId = GetNetworkId();
133 socketInfo.peerNetworkId = const_cast<char *>(networkId.c_str());
134 std::string clientName = pipe_.pipeId;
135 socketInfo.name = const_cast<char *>(clientName.c_str());
136 std::string pkgName = "ohos.distributeddata";
137 socketInfo.pkgName = pkgName.data();
138 socketInfo.dataType = DATA_TYPE_BYTES;
139 int32_t socket = Socket(socketInfo);
140 if (socket <= 0) {
141 ZLOGE("Create the client Socket:%{public}d failed, peerName:%{public}s", socket, socketInfo.peerName);
142 return socket;
143 }
144 if (accessInfo_.isOHType) {
145 SocketAccessInfo info;
146 info.userId = accessInfo_.userId;
147 info.localTokenId = accessInfo_.tokenId;
148 AccessExtraInfo extraInfo;
149 extraInfo.bundleName = accessInfo_.bundleName;
150 extraInfo.accountId = accessInfo_.accountId;
151 extraInfo.storeId = accessInfo_.storeId;
152 std::string extraInfoStr = Serializable::Marshall(extraInfo);
153 if (extraInfoStr.empty()) {
154 ZLOGE("Marshall access info fail");
155 return INVALID_SOCKET_ID;
156 }
157 info.extraAccessInfo = const_cast<char *>(extraInfoStr.c_str());
158 auto status = SetAccessInfo(socket, info);
159 if (status != SOFTBUS_OK) {
160 ZLOGE("SetAccessInfo fail, status:%{public}d, userId:%{public}d, bundleName:%{public}s,"
161 "accountId:%{public}s, storeId:%{public}s", status, info.userId, extraInfo.bundleName.c_str(),
162 Anonymous::Change(extraInfo.accountId).c_str(), Anonymous::Change(extraInfo.storeId).c_str());
163 return INVALID_SOCKET_ID;
164 }
165 }
166 return socket;
167 }
168
CheckStatus()169 Status SoftBusClient::CheckStatus()
170 {
171 if (bindState_ == 0) {
172 return Status::SUCCESS;
173 }
174 if (isOpening_.load()) {
175 return Status::RATE_LIMIT;
176 }
177 if (bindState_ == 0) {
178 return Status::SUCCESS;
179 }
180 return Status::ERROR;
181 }
182
Open(int32_t socket,uint32_t type,const ISocketListener * listener,bool async)183 int32_t SoftBusClient::Open(int32_t socket, uint32_t type, const ISocketListener *listener, bool async)
184 {
185 auto networkId = GetNetworkId();
186 ZLOGI("Bind start, device:%{public}s, networkId:%{public}s, session:%{public}s, socketId:%{public}d",
187 Anonymous::Change(device_.deviceId).c_str(), Anonymous::Change(networkId).c_str(),
188 pipe_.pipeId.c_str(), socket);
189 int32_t status = Bind(socket, QOS_INFOS[type % QOS_BUTT], QOS_COUNTS[type % QOS_BUTT], listener);
190 if (status != SOFTBUS_OK) {
191 ZLOGE("Bind fail, device:%{public}s, networkId:%{public}s, socketId:%{public}d, result:%{public}d",
192 Anonymous::Change(device_.deviceId).c_str(), Anonymous::Change(networkId).c_str(), socket, status);
193 Shutdown(socket);
194 return status;
195 }
196 uint32_t mtu = 0;
197 std::tie(status, mtu) = GetMtu(socket);
198 if (status != SOFTBUS_OK) {
199 ZLOGE("GetMtu failed, session:%{public}s, socket:%{public}d, status:%{public}d", pipe_.pipeId.c_str(), socket_,
200 status);
201 Shutdown(socket);
202 return status;
203 }
204 UpdateBindInfo(socket, mtu, status, async);
205 expireTime_ = CalcExpireTime();
206 ZLOGI("Bind success, device:%{public}s, networkId:%{public}s, session:%{public}s, socketId:%{public}d",
207 Anonymous::Change(device_.deviceId).c_str(), Anonymous::Change(networkId).c_str(),
208 pipe_.pipeId.c_str(), socket);
209 ConnectManager::GetInstance()->OnSessionOpen(networkId);
210 return status;
211 }
212
GetExpireTime() const213 SoftBusClient::Time SoftBusClient::GetExpireTime() const
214 {
215 std::lock_guard<std::mutex> lock(mutex_);
216 return expireTime_;
217 }
218
GetSocket() const219 int32_t SoftBusClient::GetSocket() const
220 {
221 return socket_;
222 }
223
UpdateBindInfo(int32_t socket,uint32_t mtu,int32_t status,bool async)224 void SoftBusClient::UpdateBindInfo(int32_t socket, uint32_t mtu, int32_t status, bool async)
225 {
226 if (async) {
227 std::lock_guard<std::mutex> lock(mutex_);
228 socket_ = socket;
229 mtu_ = mtu;
230 bindState_ = status;
231 } else {
232 socket_ = socket;
233 mtu_ = mtu;
234 bindState_ = status;
235 }
236 }
237
GetMtu(int32_t socket)238 std::pair<int32_t, uint32_t> SoftBusClient::GetMtu(int32_t socket)
239 {
240 uint32_t mtu = 0;
241 auto ret = GetMtuSize(socket, &mtu);
242 return { ret, mtu };
243 }
244
GetQoSType() const245 uint32_t SoftBusClient::GetQoSType() const
246 {
247 return type_ % QOS_BUTT;
248 }
249
CalcExpireTime() const250 SoftBusClient::Time SoftBusClient::CalcExpireTime() const
251 {
252 auto delay = type_ == QOS_BR ? BR_CLOSE_DELAY : HML_CLOSE_DELAY;
253 return std::chrono::steady_clock::now() + delay;
254 }
255
ReuseConnect(const ISocketListener * listener)256 Status SoftBusClient::ReuseConnect(const ISocketListener *listener)
257 {
258 std::lock_guard<std::mutex> lock(mutex_);
259 auto checkStatus = CheckStatus();
260 if (checkStatus == Status::SUCCESS) {
261 expireTime_ = CalcExpireTime();
262 return Status::SUCCESS;
263 }
264 int32_t socket = CreateSocket();
265 if (socket <= 0) {
266 return Status::NETWORK_ERROR;
267 }
268 ZLOGI("Reuse Start, device:%{public}s session:%{public}s socket:%{public}d",
269 Anonymous::Change(device_.deviceId).c_str(), pipe_.pipeId.c_str(), socket);
270 int32_t status = Open(socket, QOS_REUSE, listener, false);
271 return status == SOFTBUS_OK ? Status::SUCCESS : Status::NETWORK_ERROR;
272 }
273
GetNetworkId() const274 std::string SoftBusClient::GetNetworkId() const
275 {
276 std::lock_guard<std::mutex> lock(networkIdMutex_);
277 return networkId_;
278 }
279
UpdateNetworkId(const std::string & networkId)280 void SoftBusClient::UpdateNetworkId(const std::string& networkId)
281 {
282 std::lock_guard<std::mutex> lock(networkIdMutex_);
283 networkId_ = networkId;
284 }
285 } // namespace OHOS::AppDistributedKv