• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "communicator_context.h"
18 #include "device_manager_adapter.h"
19 #include "kvstore_utils.h"
20 #include "log_print.h"
21 #include "softbus_error_code.h"
22 #include "softbus_client.h"
23 
24 namespace OHOS::AppDistributedKv {
25 using namespace OHOS::DistributedKv;
26 using DmAdapter = OHOS::DistributedData::DeviceManagerAdapter;
27 using Context = DistributedData::CommunicatorContext;
SoftBusClient(const PipeInfo & pipeInfo,const DeviceId & deviceId,const std::function<int32_t (int32_t)> & getConnStatus)28 SoftBusClient::SoftBusClient(const PipeInfo &pipeInfo, const DeviceId &deviceId,
29     const std::function<int32_t(int32_t)> &getConnStatus)
30     : pipe_(pipeInfo), device_(deviceId), getConnStatus_(getConnStatus)
31 {
32     mtu_ = DEFAULT_MTU_SIZE;
33 }
34 
~SoftBusClient()35 SoftBusClient::~SoftBusClient()
36 {
37     if (connId_ > 0) {
38         CloseSession(connId_);
39     }
40 }
41 
operator ==(int32_t connId) const42 bool SoftBusClient::operator==(int32_t connId) const
43 {
44     return connId_ == connId;
45 }
46 
operator ==(const std::string & deviceId) const47 bool SoftBusClient::operator==(const std::string &deviceId) const
48 {
49     return device_.deviceId == deviceId;
50 }
51 
RestoreDefaultValue()52 void SoftBusClient::RestoreDefaultValue()
53 {
54     connId_ = INVALID_CONNECT_ID;
55     status_ = ConnectStatus::DISCONNECT;
56     routeType_ = RouteType::INVALID_ROUTE_TYPE;
57     strategy_ = Strategy::DEFAULT;
58     mtu_ = DEFAULT_MTU_SIZE;
59 }
60 
GetMtuSize() const61 uint32_t SoftBusClient::GetMtuSize() const
62 {
63     ZLOGD("get mtu size connId:%{public}d mtu:%{public}d", connId_, mtu_);
64     return mtu_;
65 }
66 
Send(const DataInfo & dataInfo,uint32_t totalLength)67 Status SoftBusClient::Send(const DataInfo &dataInfo, uint32_t totalLength)
68 {
69     std::lock_guard<std::mutex> lock(mutex_);
70     auto result = OpenConnect(totalLength);
71     if (result != Status::SUCCESS) {
72         return result;
73     }
74 
75     ZLOGD("send data connId:%{public}d, data size:%{public}u, total length:%{public}u.",
76         connId_, dataInfo.length, totalLength);
77     int32_t ret = SendBytes(connId_, dataInfo.data, dataInfo.length);
78     if (ret != SOFTBUS_OK) {
79         ZLOGE("send data to connId%{public}d failed, ret:%{public}d.", connId_, ret);
80         return Status::ERROR;
81     }
82 
83     if (routeType_ == RouteType::WIFI_P2P) {
84         UpdateP2pFinishTime(connId_, dataInfo.length);
85     }
86     return Status::SUCCESS;
87 }
88 
OpenConnect(uint32_t totalLength)89 Status SoftBusClient::OpenConnect(uint32_t totalLength)
90 {
91     strategy_ = CommunicationStrategy::GetInstance().GetStrategy(device_.deviceId);
92     if (status_ == ConnectStatus::CONNECT_OK) {
93         status_ = ConnectStatus::DISCONNECT;
94         auto result = SwitchChannel(totalLength);
95         if (result == Status::SUCCESS) {
96             status_ = ConnectStatus::CONNECT_OK;
97         }
98         return result;
99     }
100 
101     auto result = CreateChannel(totalLength);
102     if (result != Status::SUCCESS) {
103         return result;
104     }
105     status_ = ConnectStatus::CONNECT_OK;
106     return Status::SUCCESS;
107 }
108 
SwitchChannel(uint32_t totalLength)109 Status SoftBusClient::SwitchChannel(uint32_t totalLength)
110 {
111     if (strategy_ == Strategy::BUTT) {
112         return Status::NETWORK_ERROR;
113     }
114 
115     if (strategy_ == Strategy::ON_LINE_SELECT_CHANNEL) {
116         return Status::SUCCESS;
117     }
118 
119     if (routeType_ == RouteType::WIFI_STA) {
120         return Status::SUCCESS;
121     }
122 
123     if (routeType_ == RouteType::BT_BLE || routeType_ == RouteType::BT_BR) {
124         if (totalLength < P2P_SIZE_THRESHOLD) {
125             return Status::SUCCESS;
126         }
127 
128         ZLOGD("switch %{public}s,session:%{public}s,connId:%{public}d,routeType:%{public}d to wifi or p2p.",
129             KvStoreUtils::ToBeAnonymous(device_.deviceId).c_str(), pipe_.pipeId.c_str(), connId_, routeType_);
130         RestoreDefaultValue();
131         return Open(GetSessionAttribute(true));
132     }
133 
134     if (routeType_ == RouteType::WIFI_P2P) {
135         if (totalLength > P2P_SIZE_THRESHOLD * SWITCH_DELAY_FACTOR) {
136             return Status::SUCCESS;
137         }
138 
139         ZLOGD("switch %{public}s,session:%{public}s,connId:%{public}d,routeType:%{public}d to ble or br.",
140             KvStoreUtils::ToBeAnonymous(device_.deviceId).c_str(), pipe_.pipeId.c_str(), connId_, routeType_);
141         {
142             std::lock_guard<std::mutex> lock(taskMutex_);
143             if (closeP2pTaskId_ == ExecutorPool::INVALID_TASK_ID) {
144                 closeP2pTaskId_ = Context::getInstance().
145                                   GetThreadPool()->Execute(std::bind(&SoftBusClient::CloseP2pSessions, this));
146             }
147         }
148         RestoreDefaultValue();
149         return Open(GetSessionAttribute(false));
150     }
151 
152     return Status::NETWORK_ERROR;
153 }
154 
CreateChannel(uint32_t totalLength)155 Status SoftBusClient::CreateChannel(uint32_t totalLength)
156 {
157     if (strategy_ == Strategy::BUTT) {
158         return Status::NETWORK_ERROR;
159     }
160 
161     if (strategy_ == Strategy::ON_LINE_SELECT_CHANNEL) {
162         return Open(GetSessionAttribute(true));
163     }
164 
165     if (totalLength < P2P_SIZE_THRESHOLD) {
166         return Open(GetSessionAttribute(false));
167     }
168     return Open(GetSessionAttribute(true));
169 }
170 
Open(SessionAttribute attr)171 Status SoftBusClient::Open(SessionAttribute attr)
172 {
173     int id = OpenSession(pipe_.pipeId.c_str(), pipe_.pipeId.c_str(),
174                          DmAdapter::GetInstance().ToNetworkID(device_.deviceId).c_str(), "GROUP_ID", &attr);
175     ZLOGI("open %{public}s,session:%{public}s,connId:%{public}d,linkNum:%{public}d,strategy:%{public}d",
176           KvStoreUtils::ToBeAnonymous(device_.deviceId).c_str(), pipe_.pipeId.c_str(), id, attr.linkTypeNum, strategy_);
177     if (id < 0) {
178         ZLOGW("Open %{public}s, type:%{public}d failed, connId:%{public}d",
179               pipe_.pipeId.c_str(), attr.dataType, id);
180         return Status::NETWORK_ERROR;
181     }
182 
183     connId_ = id;
184     int state = getConnStatus_(connId_);
185     ZLOGI("waited for notification, state:%{public}d connId:%{public}d", state, id);
186     if (state != SOFTBUS_OK) {
187         ZLOGE("open callback result error");
188         return Status::NETWORK_ERROR;
189     }
190 
191     int32_t routeType = RouteType::INVALID_ROUTE_TYPE;
192     auto ret = GetSessionOption(connId_, SESSION_OPTION_LINK_TYPE, &routeType, sizeof(routeType));
193     if (ret != SOFTBUS_OK) {
194         ZLOGE("get routeType failed, session:%{public}s, connId:%{public}d", pipe_.pipeId.c_str(), connId_);
195         return Status::NETWORK_ERROR;
196     }
197     routeType_ = routeType;
198 
199     UpdateMtuSize();
200     ZLOGI("open %{public}s, session:%{public}s success, connId:%{public}d, routeType:%{public}d",
201         KvStoreUtils::ToBeAnonymous(device_.deviceId).c_str(), pipe_.pipeId.c_str(), connId_, routeType_);
202     return Status::SUCCESS;
203 }
204 
GetSessionAttribute(bool isP2p)205 SessionAttribute SoftBusClient::GetSessionAttribute(bool isP2p)
206 {
207     SessionAttribute attr;
208     attr.dataType = TYPE_BYTES;
209     // If the dataType is BYTES, the default strategy is wifi_5G > wifi_2.4G > BR, without P2P;
210     if (!isP2p) {
211         return attr;
212     }
213 
214     int index = 0;
215     attr.linkType[index++] = LINK_TYPE_WIFI_WLAN_5G;
216     attr.linkType[index++] = LINK_TYPE_WIFI_WLAN_2G;
217     attr.linkType[index++] = LINK_TYPE_WIFI_P2P;
218     attr.linkType[index++] = LINK_TYPE_BR;
219     attr.linkTypeNum = index;
220     return attr;
221 }
222 
UpdateMtuSize()223 void SoftBusClient::UpdateMtuSize()
224 {
225     uint32_t mtu = 0;
226     auto result = GetSessionOption(connId_, SESSION_OPTION_MAX_SENDBYTES_SIZE, &mtu, sizeof(mtu));
227     if (result != SOFTBUS_OK) {
228         return;
229     }
230     mtu_ = mtu;
231 }
232 
AfterStrategyUpdate(Strategy strategy)233 void SoftBusClient::AfterStrategyUpdate(Strategy strategy)
234 {
235     std::lock_guard<std::mutex> lock(mutex_);
236     if (strategy != strategy_ && connId_ > 0) {
237         ZLOGI("close connId:%{public}d,strategy current:%{public}d, new:%{public}d", connId_, strategy_, strategy);
238         CloseSession(connId_);
239         RestoreDefaultValue();
240     }
241 }
242 
CloseP2pSessions()243 void SoftBusClient::CloseP2pSessions()
244 {
245     Time now = std::chrono::steady_clock::now();
246     Time nextClose = std::chrono::steady_clock::time_point::max();
247     p2pFinishTime_.EraseIf([&now, &nextClose](const int32_t &connId, Time &finishTime) -> bool {
248         if (finishTime + P2P_CLOSE_DELAY <= now) {
249             ZLOGD("close timeout p2p connId:%{public}d", connId);
250             CloseSession(connId);
251             return true;
252         }
253 
254         if (finishTime + P2P_CLOSE_DELAY < nextClose) {
255             nextClose = finishTime + P2P_CLOSE_DELAY;
256         }
257         return false;
258     });
259 
260     std::lock_guard<std::mutex> lock(taskMutex_);
261     if (!p2pFinishTime_.Empty()) {
262         closeP2pTaskId_ = Context::getInstance().GetThreadPool()->Schedule(nextClose - now,
263             std::bind(&SoftBusClient::CloseP2pSessions, this));
264     } else {
265         closeP2pTaskId_ = ExecutorPool::INVALID_TASK_ID;
266     }
267 }
268 
UpdateP2pFinishTime(int32_t connId,uint32_t dataLength)269 void SoftBusClient::UpdateP2pFinishTime(int32_t connId, uint32_t dataLength)
270 {
271     Time now = std::chrono::steady_clock::now();
272     auto delay = std::chrono::microseconds(dataLength / P2P_TRANSFER_PER_MICROSECOND);
273     p2pFinishTime_.Compute(connId, [&now, &delay](const auto &id, auto &finishTime) -> bool {
274         if (finishTime < now) {
275             finishTime = now + delay;
276         } else {
277             finishTime += delay;
278         }
279         return true;
280     });
281 }
282 }