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