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