1 /*
2 * Copyright (c) 2021-2024 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 #include "network/softbus/softbus_agent.h"
17
18 #include <sstream>
19
20 #include "device_manager.h"
21 #include "dfs_daemon_event_dfx.h"
22 #include "dfs_error.h"
23 #include "dfsu_exception.h"
24 #include "dm_device_info.h"
25 #include "ipc_skeleton.h"
26 #include "ipc/i_daemon.h"
27 #include "network/softbus/softbus_session_dispatcher.h"
28 #include "network/softbus/softbus_session_name.h"
29 #include "network/softbus/softbus_session.h"
30 #include "softbus_error_code.h"
31 #include "utils_directory.h"
32 #include "utils_log.h"
33
34 namespace OHOS {
35 namespace Storage {
36 namespace DistributedFile {
37 namespace {
38 constexpr int MAX_RETRY_COUNT = 7;
39 }
40 using namespace std;
41 const int32_t DFS_QOS_TYPE_MIN_BW = 90 * 1024 * 1024;
42 const int32_t DFS_QOS_TYPE_MAX_LATENCY = 10000;
43 const int32_t DFS_QOS_TYPE_MIN_LATENCY = 2000;
44 #ifdef SUPPORT_SAME_ACCOUNT
45 const uint32_t MAX_ONLINE_DEVICE_SIZE = 10000;
46 #endif
SoftbusAgent(weak_ptr<MountPoint> mountPoint)47 SoftbusAgent::SoftbusAgent(weak_ptr<MountPoint> mountPoint) : NetworkAgentTemplate(mountPoint)
48 {
49 auto spt = mountPoint.lock();
50 if (spt == nullptr) {
51 LOGE("mountPoint is not exist! bad weak_ptr");
52 sessionName_ = "";
53 return;
54 }
55
56 string path = spt->GetMountArgument().GetFullDst();
57 SoftbusSessionName sessionName(path);
58 sessionName_ = sessionName.ToString();
59 }
60
IsSameAccount(const std::string & networkId)61 bool SoftbusAgent::IsSameAccount(const std::string &networkId)
62 {
63 #ifdef SUPPORT_SAME_ACCOUNT
64 std::vector<DistributedHardware::DmDeviceInfo> deviceList;
65 DistributedHardware::DeviceManager::GetInstance().GetTrustedDeviceList(IDaemon::SERVICE_NAME, "", deviceList);
66 if (deviceList.size() == 0 || deviceList.size() > MAX_ONLINE_DEVICE_SIZE) {
67 LOGE("trust device list size is invalid, size=%zu", deviceList.size());
68 return false;
69 }
70 for (const auto &deviceInfo : deviceList) {
71 if (std::string(deviceInfo.networkId) == networkId) {
72 return (deviceInfo.authForm == DistributedHardware::DmAuthForm::IDENTICAL_ACCOUNT);
73 }
74 }
75 return false;
76 #else
77 return true;
78 #endif
79 }
80
JudgeNetworkTypeIsWifi(const DeviceInfo & info)81 int32_t SoftbusAgent::JudgeNetworkTypeIsWifi(const DeviceInfo &info)
82 {
83 int32_t networkType;
84 auto &deviceManager = DistributedHardware::DeviceManager::GetInstance();
85 int errCode = deviceManager.GetNetworkTypeByNetworkId(IDaemon::SERVICE_NAME, info.GetCid(), networkType);
86 if (errCode) {
87 LOGE("failed to get network type by network id errCode = %{public}d", errCode);
88 return FileManagement::ERR_BAD_VALUE;
89 }
90 if (!(static_cast<uint32_t>(networkType) & (1 << DistributedHardware::BIT_NETWORK_TYPE_WIFI))) {
91 LOGI("not wifi network networkType = %{public}d == %{public}d", networkType,
92 1 << DistributedHardware::BIT_NETWORK_TYPE_WIFI);
93 return FileManagement::ERR_BAD_VALUE;
94 }
95 return FileManagement::ERR_OK;
96 }
97
JoinDomain()98 void SoftbusAgent::JoinDomain()
99 {
100 LOGI("JoinDomain Enter.");
101 ISocketListener sessionListener = {
102 .OnBind = SoftbusSessionDispatcher::OnSessionOpened,
103 .OnShutdown = SoftbusSessionDispatcher::OnSessionClosed,
104 .OnBytes = nullptr,
105 .OnMessage = nullptr,
106 .OnStream = nullptr,
107 };
108
109 SoftbusSessionDispatcher::RegisterSessionListener(sessionName_, shared_from_this());
110 SocketInfo serverInfo = {
111 .name = const_cast<char*>(sessionName_.c_str()),
112 .pkgName = const_cast<char*>(IDaemon::SERVICE_NAME.c_str()),
113 .dataType = DATA_TYPE_BYTES,
114 };
115 int32_t socketId = Socket(serverInfo);
116 if (socketId < 0) {
117 LOGE("Create Socket fail socketId, socketId = %{public}d", socketId);
118 return;
119 }
120 QosTV qos[] = {
121 {.qos = QOS_TYPE_MIN_BW, .value = DFS_QOS_TYPE_MIN_BW},
122 {.qos = QOS_TYPE_MAX_LATENCY, .value = DFS_QOS_TYPE_MAX_LATENCY},
123 {.qos = QOS_TYPE_MIN_LATENCY, .value = DFS_QOS_TYPE_MIN_LATENCY},
124 };
125
126 int32_t ret = Listen(socketId, qos, sizeof(qos) / sizeof(qos[0]), &sessionListener);
127 if (ret != FileManagement::E_OK) {
128 Shutdown(socketId);
129 stringstream ss;
130 ss << "Failed to CreateSessionServer, errno:" << ret;
131 LOGE("%{public}s, sessionName:%{public}s", ss.str().c_str(), sessionName_.c_str());
132 throw runtime_error(ss.str());
133 }
134 {
135 std::lock_guard<std::mutex> lock(serverIdMapMutex_);
136 serverIdMap_.insert(std::make_pair(sessionName_, socketId));
137 }
138 LOGI("Succeed to JoinDomain, busName:%{public}s", sessionName_.c_str());
139 }
140
QuitDomain()141 void SoftbusAgent::QuitDomain()
142 {
143 std::lock_guard<std::mutex> lock(serverIdMapMutex_);
144 if (!serverIdMap_.empty()) {
145 for (auto it = serverIdMap_.begin(); it != serverIdMap_.end(); it++) {
146 if ((it->first).find(sessionName_) != std::string::npos) {
147 int32_t serverId = serverIdMap_[sessionName_];
148 Shutdown(serverId);
149 LOGI("RemoveSessionServer success.");
150 }
151 }
152 }
153 SoftbusSessionDispatcher::UnregisterSessionListener(sessionName_.c_str());
154 LOGI("Succeed to QuitDomain, busName:%{public}s", sessionName_.c_str());
155 }
156
StopTopHalf()157 void SoftbusAgent::StopTopHalf()
158 {
159 QuitDomain();
160 }
161
StopBottomHalf()162 void SoftbusAgent::StopBottomHalf() {}
163
OpenSession(const DeviceInfo & info,const uint8_t & linkType)164 int32_t SoftbusAgent::OpenSession(const DeviceInfo &info, const uint8_t &linkType)
165 {
166 LOGI("Start to OpenSession, cid:%{public}s, linkType:%{public}d",
167 Utils::GetAnonyString(info.GetCid()).c_str(), linkType);
168 if (!IsSameAccount(info.GetCid())) {
169 LOGI("The source and sink device is not same account, not support.");
170 return FileManagement::E_INVAL_ARG;
171 }
172 ISocketListener sessionListener = {
173 .OnBind = SoftbusSessionDispatcher::OnSessionOpened,
174 .OnShutdown = SoftbusSessionDispatcher::OnSessionClosed,
175 .OnBytes = nullptr,
176 .OnMessage = nullptr,
177 .OnStream = nullptr,
178 };
179 QosTV qos[] = {
180 {.qos = QOS_TYPE_MIN_BW, .value = DFS_QOS_TYPE_MIN_BW},
181 {.qos = QOS_TYPE_MAX_LATENCY, .value = DFS_QOS_TYPE_MAX_LATENCY},
182 {.qos = QOS_TYPE_MIN_LATENCY, .value = DFS_QOS_TYPE_MIN_LATENCY},
183 };
184 SocketInfo clientInfo = {
185 .name = const_cast<char*>((sessionName_.c_str())),
186 .peerName = const_cast<char*>(sessionName_.c_str()),
187 .peerNetworkId = const_cast<char*>(info.GetCid().c_str()),
188 .pkgName = const_cast<char*>(IDaemon::SERVICE_NAME.c_str()),
189 .dataType = DATA_TYPE_BYTES,
190 };
191 int32_t socketId = Socket(clientInfo);
192 if (socketId < FileManagement::E_OK) {
193 LOGE("Create OpenSoftbusChannel Socket error");
194 return FileManagement::E_CONTEXT;
195 }
196 int32_t ret = Bind(socketId, qos, sizeof(qos) / sizeof(qos[0]), &sessionListener);
197 if (ret != FileManagement::E_OK) {
198 LOGE("Bind SocketClient error");
199 RADAR_REPORT(RadarReporter::DFX_SET_DFS, RadarReporter::DFX_BUILD__LINK, RadarReporter::DFX_FAILED,
200 RadarReporter::BIZ_STATE, RadarReporter::DFX_END, RadarReporter::ERROR_CODE,
201 RadarReporter::BIND_SOCKET_ERROR, RadarReporter::PACKAGE_NAME, RadarReporter::dSoftBus + to_string(ret));
202 Shutdown(socketId);
203 return FileManagement::E_CONTEXT;
204 }
205 OccupySession(socketId, linkType);
206 PeerSocketInfo peerSocketInfo = {
207 .name = const_cast<char*>(sessionName_.c_str()),
208 .networkId = const_cast<char*>(info.GetCid().c_str()),
209 };
210 SoftbusSessionDispatcher::OnSessionOpened(socketId, peerSocketInfo);
211 LOGI("Success to OpenSession, socketId:%{public}d, linkType:%{public}d, cid:%{public}s",
212 socketId, linkType, Utils::GetAnonyString(info.GetCid()).c_str());
213 return FileManagement::E_OK;
214 }
215
OpenApSession(const DeviceInfo & info,const uint8_t & linkType)216 void SoftbusAgent::OpenApSession(const DeviceInfo &info, const uint8_t &linkType)
217 {
218 LOGI("Start to OpenApSession, cid:%{public}s, linkType:%{public}d",
219 Utils::GetAnonyString(info.GetCid()).c_str(), linkType);
220 if (!IsSameAccount(info.GetCid())) {
221 LOGI("The source and sink device is not same account, not support.");
222 return;
223 }
224 if (JudgeNetworkTypeIsWifi(info)) {
225 LOGI("networktype is not wifi");
226 return;
227 }
228 ISocketListener sessionListener = {
229 .OnBind = SoftbusSessionDispatcher::OnSessionOpened,
230 .OnShutdown = SoftbusSessionDispatcher::OnSessionClosed,
231 .OnBytes = nullptr,
232 .OnMessage = nullptr,
233 .OnStream = nullptr,
234 };
235 SocketInfo clientInfo = {
236 .name = const_cast<char*>((sessionName_.c_str())),
237 .peerName = const_cast<char*>(sessionName_.c_str()),
238 .peerNetworkId = const_cast<char*>(info.GetCid().c_str()),
239 .pkgName = const_cast<char*>(IDaemon::SERVICE_NAME.c_str()),
240 .dataType = DATA_TYPE_BYTES,
241 };
242 int32_t socketId = Socket(clientInfo);
243 if (socketId < FileManagement::E_OK) {
244 LOGE("Create OpenApSoftbusChannel Socket error");
245 return;
246 }
247 int32_t ret = DfsBind(socketId, &sessionListener);
248 if (ret == SOFTBUS_TRANS_SOCKET_IN_USE) {
249 LOGI("Bind Socket in use cid:%{public}s", Utils::GetAnonyString(info.GetCid()).c_str());
250 return;
251 }
252 if (ret != FileManagement::E_OK) {
253 LOGE("Bind SocketClient error cid:%{public}s", Utils::GetAnonyString(info.GetCid()).c_str());
254 Shutdown(socketId);
255 return;
256 }
257 OccupySession(socketId, linkType);
258 PeerSocketInfo peerSocketInfo = {
259 .name = const_cast<char*>(sessionName_.c_str()),
260 .networkId = const_cast<char*>(info.GetCid().c_str()),
261 };
262 SoftbusSessionDispatcher::OnSessionOpened(socketId, peerSocketInfo);
263 LOGI("Success to OpenApSession, socketId:%{public}d, linkType:%{public}d, cid:%{public}s",
264 socketId, linkType, Utils::GetAnonyString(info.GetCid()).c_str());
265 }
266
CloseSession(shared_ptr<BaseSession> session)267 void SoftbusAgent::CloseSession(shared_ptr<BaseSession> session)
268 {
269 if (session == nullptr) {
270 LOGE("Failed to close session, error:invalid session");
271 return;
272 }
273 session->Release();
274 }
275
IsContinueRetry(const string & cid)276 bool SoftbusAgent::IsContinueRetry(const string &cid)
277 {
278 auto retriedTimesMap = OpenSessionRetriedTimesMap_.find(cid);
279 if (retriedTimesMap != OpenSessionRetriedTimesMap_.end()) {
280 if (retriedTimesMap->second >= MAX_RETRY_COUNT) {
281 return false;
282 }
283 } else {
284 OpenSessionRetriedTimesMap_[cid] = 0;
285 }
286 OpenSessionRetriedTimesMap_[cid]++;
287 return true;
288 }
289
OnSessionOpened(const int32_t sessionId,PeerSocketInfo info)290 void SoftbusAgent::OnSessionOpened(const int32_t sessionId, PeerSocketInfo info)
291 {
292 LOGI("OnSessionOpened sessionId = %{public}d", sessionId);
293 std::string peerDeviceId = info.networkId;
294 auto session = make_shared<SoftbusSession>(sessionId, peerDeviceId);
295 auto cid = session->GetCid();
296
297 DeviceInfo deviceInfo;
298 deviceInfo.SetCid(cid);
299 auto retriedTimesMap = OpenSessionRetriedTimesMap_.find(cid);
300 if (retriedTimesMap != OpenSessionRetriedTimesMap_.end()) {
301 OpenSessionRetriedTimesMap_.erase(cid);
302 }
303 session->DisableSessionListener();
304 if (FindSession(sessionId)) {
305 std::string client = "Client";
306 AcceptSession(session, client);
307 } else {
308 std::string client = "Server";
309 AcceptSession(session, client);
310 }
311
312 if (!FindSession(sessionId)) {
313 OccupySession(sessionId, 0);
314 }
315 }
316
OnSessionClosed(int32_t sessionId,const std::string peerDeviceId)317 void SoftbusAgent::OnSessionClosed(int32_t sessionId, const std::string peerDeviceId)
318 {
319 LOGI("OnSessionClosed Enter.");
320 Shutdown(sessionId);
321 }
322 } // namespace DistributedFile
323 } // namespace Storage
324 } // namespace OHOS
325