1 /*
2 * Copyright (c) 2023-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_handler.h"
17
18 #include <sys/stat.h>
19 #include <utility>
20
21 #include "all_connect/all_connect_manager.h"
22 #include "device_manager.h"
23 #include "dfs_daemon_event_dfx.h"
24 #include "dfs_error.h"
25 #include "dm_device_info.h"
26 #include "network/softbus/softbus_file_receive_listener.h"
27 #include "network/softbus/softbus_file_send_listener.h"
28 #include "network/softbus/softbus_session_listener.h"
29 #include "trans_mananger.h"
30 #include "utils_directory.h"
31 #include "utils_log.h"
32
33 #ifdef SUPPORT_SAME_ACCOUNT
34 #include "inner_socket.h"
35 #include "trans_type_enhanced.h"
36 #endif
37
38 namespace OHOS {
39 namespace Storage {
40 namespace DistributedFile {
41 using namespace OHOS::FileManagement;
42 const int32_t DFS_QOS_TYPE_MIN_BW = 90 * 1024 * 1024;
43 const int32_t DFS_QOS_TYPE_MAX_LATENCY = 10000;
44 const int32_t DFS_QOS_TYPE_MIN_LATENCY = 2000;
45 const int32_t INVALID_SESSION_ID = -1;
46 #ifdef SUPPORT_SAME_ACCOUNT
47 const uint32_t MAX_ONLINE_DEVICE_SIZE = 10000;
48 #endif
49 constexpr size_t MAX_SIZE = 500;
50 std::mutex SoftBusHandler::clientSessNameMapMutex_;
51 std::map<int32_t, std::string> SoftBusHandler::clientSessNameMap_;
52 std::mutex SoftBusHandler::serverIdMapMutex_;
53 std::map<std::string, int32_t> SoftBusHandler::serverIdMap_;
54 std::mutex SoftBusHandler::networkIdMapMutex_;
55 std::map<int32_t, std::string> SoftBusHandler::networkIdMap_;
OnSinkSessionOpened(int32_t sessionId,PeerSocketInfo info)56 void SoftBusHandler::OnSinkSessionOpened(int32_t sessionId, PeerSocketInfo info)
57 {
58 if (!SoftBusHandler::IsSameAccount(info.networkId)) {
59 std::lock_guard<std::mutex> lock(serverIdMapMutex_);
60 auto it = serverIdMap_.find(info.name);
61 if (it != serverIdMap_.end()) {
62 Shutdown(it->second);
63 serverIdMap_.erase(it);
64 LOGI("RemoveSessionServer success.");
65 }
66 Shutdown(sessionId);
67 return;
68 }
69 {
70 std::lock_guard<std::mutex> lock(SoftBusHandler::clientSessNameMapMutex_);
71 SoftBusHandler::clientSessNameMap_.insert(std::make_pair(sessionId, info.name));
72 }
73 {
74 std::lock_guard<std::mutex> lock(networkIdMapMutex_);
75 networkIdMap_.insert(std::make_pair(sessionId, info.networkId));
76 }
77
78 AllConnectManager::GetInstance().PublishServiceState(DfsConnectCode::COPY_FILE, info.networkId,
79 ServiceCollaborationManagerBussinessStatus::SCM_CONNECTED);
80 }
81
IsSameAccount(const std::string & networkId)82 bool SoftBusHandler::IsSameAccount(const std::string &networkId)
83 {
84 #ifdef SUPPORT_SAME_ACCOUNT
85 std::vector<DistributedHardware::DmDeviceInfo> deviceList;
86 DistributedHardware::DeviceManager::GetInstance().GetTrustedDeviceList(SERVICE_NAME, "", deviceList);
87 if (deviceList.size() == 0 || deviceList.size() > MAX_ONLINE_DEVICE_SIZE) {
88 LOGE("trust device list size is invalid, size=%zu", deviceList.size());
89 return false;
90 }
91 for (const auto &deviceInfo : deviceList) {
92 if (std::string(deviceInfo.networkId) == networkId) {
93 return (deviceInfo.authForm == DistributedHardware::DmAuthForm::IDENTICAL_ACCOUNT);
94 }
95 }
96 return false;
97 #else
98 return true;
99 #endif
100 }
101
GetSessionName(int32_t sessionId)102 std::string SoftBusHandler::GetSessionName(int32_t sessionId)
103 {
104 std::string sessionName = "";
105 std::lock_guard<std::mutex> lock(clientSessNameMapMutex_);
106 auto iter = clientSessNameMap_.find(sessionId);
107 if (iter != clientSessNameMap_.end()) {
108 sessionName = iter->second;
109 return sessionName;
110 }
111 LOGE("sessionName not registered");
112 return sessionName;
113 }
114
SoftBusHandler()115 SoftBusHandler::SoftBusHandler()
116 {
117 ISocketListener fileSendListener;
118 fileSendListener.OnBind = nullptr;
119 fileSendListener.OnShutdown = DistributedFile::SoftBusFileSendListener::OnSendFileShutdown;
120 fileSendListener.OnFile = DistributedFile::SoftBusFileSendListener::OnFile;
121 fileSendListener.OnBytes = nullptr;
122 fileSendListener.OnMessage = nullptr;
123 fileSendListener.OnQos = nullptr;
124 sessionListener_[DFS_CHANNLE_ROLE_SOURCE] = fileSendListener;
125
126 ISocketListener fileReceiveListener;
127 fileReceiveListener.OnBind = DistributedFile::SoftBusFileReceiveListener::OnCopyReceiveBind;
128 fileReceiveListener.OnShutdown = DistributedFile::SoftBusFileReceiveListener::OnReceiveFileShutdown;
129 fileReceiveListener.OnFile = DistributedFile::SoftBusFileReceiveListener::OnFile;
130 fileReceiveListener.OnBytes = nullptr;
131 fileReceiveListener.OnMessage = nullptr;
132 fileReceiveListener.OnQos = nullptr;
133 sessionListener_[DFS_CHANNLE_ROLE_SINK] = fileReceiveListener;
134 }
135
136 SoftBusHandler::~SoftBusHandler() = default;
137
GetInstance()138 SoftBusHandler &SoftBusHandler::GetInstance()
139 {
140 LOGI("SoftBusHandle::GetInstance");
141 static SoftBusHandler handle;
142 return handle;
143 }
144
CreateSessionServer(const std::string & packageName,const std::string & sessionName,DFS_CHANNEL_ROLE role,const std::string physicalPath)145 int32_t SoftBusHandler::CreateSessionServer(const std::string &packageName, const std::string &sessionName,
146 DFS_CHANNEL_ROLE role, const std::string physicalPath)
147 {
148 if (packageName.empty() || sessionName.empty() || physicalPath.empty()) {
149 LOGI("The parameter is empty");
150 return FileManagement::ERR_BAD_VALUE;
151 }
152 LOGI("CreateSessionServer Enter.");
153 SocketInfo serverInfo = {
154 .name = const_cast<char*>(sessionName.c_str()),
155 .pkgName = const_cast<char*>(packageName.c_str()),
156 .dataType = DATA_TYPE_FILE,
157 };
158 int32_t socketId = Socket(serverInfo);
159 if (socketId < E_OK) {
160 LOGE("Create Socket fail socketId, socketId = %{public}d", socketId);
161 RADAR_REPORT(RadarReporter::DFX_SET_DFS, RadarReporter::DFX_SET_BIZ_SCENE, RadarReporter::DFX_FAILED,
162 RadarReporter::BIZ_STATE, RadarReporter::DFX_END, RadarReporter::ERROR_CODE,
163 RadarReporter::CREAT_SOCKET_ERROR, RadarReporter::PACKAGE_NAME,
164 RadarReporter::dSoftBus + std::to_string(socketId));
165 return FileManagement::ERR_BAD_VALUE;
166 }
167 QosTV qos[] = {
168 {.qos = QOS_TYPE_MIN_BW, .value = DFS_QOS_TYPE_MIN_BW},
169 {.qos = QOS_TYPE_MAX_LATENCY, .value = DFS_QOS_TYPE_MAX_LATENCY},
170 {.qos = QOS_TYPE_MIN_LATENCY, .value = DFS_QOS_TYPE_MIN_LATENCY},
171 };
172
173 int32_t ret = Listen(socketId, qos, sizeof(qos) / sizeof(qos[0]), &sessionListener_[role]);
174 if (ret != E_OK) {
175 LOGE("Listen socket error for sessionName:%{public}s", sessionName.c_str());
176 Shutdown(socketId);
177 return FileManagement::ERR_BAD_VALUE;
178 }
179 {
180 std::lock_guard<std::mutex> lock(serverIdMapMutex_);
181 serverIdMap_.insert(std::make_pair(sessionName, socketId));
182 }
183 DistributedFile::SoftBusFileReceiveListener::SetRecvPath(physicalPath);
184 LOGI("CreateSessionServer success socketId = %{public}d", socketId);
185 return socketId;
186 }
187
OpenSession(const std::string & mySessionName,const std::string & peerSessionName,const std::string & peerDevId,int32_t & socketId)188 int32_t SoftBusHandler::OpenSession(const std::string &mySessionName, const std::string &peerSessionName,
189 const std::string &peerDevId, int32_t &socketId)
190 {
191 if (mySessionName.empty() || peerSessionName.empty() || peerDevId.empty()) {
192 LOGI("The parameter is empty");
193 return FileManagement::ERR_BAD_VALUE;
194 }
195 LOGI("OpenSession Enter peerDevId: %{public}s", Utils::GetAnonyString(peerDevId).c_str());
196 if (!IsSameAccount(peerDevId)) {
197 LOGI("The source and sink device is not same account, not support.");
198 return E_OPEN_SESSION;
199 }
200 QosTV qos[] = {
201 {.qos = QOS_TYPE_MIN_BW, .value = DFS_QOS_TYPE_MIN_BW},
202 {.qos = QOS_TYPE_MAX_LATENCY, .value = DFS_QOS_TYPE_MAX_LATENCY},
203 {.qos = QOS_TYPE_MIN_LATENCY, .value = DFS_QOS_TYPE_MIN_LATENCY},
204 };
205 if (!CreatSocketId(mySessionName, peerSessionName, peerDevId, socketId)) {
206 return FileManagement::ERR_BAD_VALUE;
207 }
208 int32_t ret = Bind(socketId, qos, sizeof(qos) / sizeof(qos[0]), &sessionListener_[DFS_CHANNLE_ROLE_SOURCE]);
209 if (ret != E_OK) {
210 LOGE("Bind SocketClient error");
211 Shutdown(socketId);
212 RadarDotsOpenSession("OpenSession", mySessionName, peerSessionName, ret, Utils::StageRes::STAGE_FAIL);
213 return ret;
214 }
215 {
216 std::lock_guard<std::mutex> lock(clientSessNameMapMutex_);
217 clientSessNameMap_.insert(std::make_pair(socketId, mySessionName));
218 }
219 {
220 std::lock_guard<std::mutex> lock(networkIdMapMutex_);
221 networkIdMap_.insert(std::make_pair(socketId, peerDevId));
222 }
223 RadarDotsOpenSession("OpenSession", mySessionName, peerSessionName, ret, Utils::StageRes::STAGE_SUCCESS);
224 LOGI("OpenSession success socketId = %{public}d", socketId);
225 return E_OK;
226 }
227
CreatSocketId(const std::string & mySessionName,const std::string & peerSessionName,const std::string & peerDevId,int32_t & socketId)228 bool SoftBusHandler::CreatSocketId(const std::string &mySessionName, const std::string &peerSessionName,
229 const std::string &peerDevId, int32_t &socketId)
230 {
231 SocketInfo clientInfo = {
232 .name = const_cast<char*>((mySessionName.c_str())),
233 .peerName = const_cast<char*>(peerSessionName.c_str()),
234 .peerNetworkId = const_cast<char*>(peerDevId.c_str()),
235 .pkgName = const_cast<char*>(SERVICE_NAME.c_str()),
236 .dataType = DATA_TYPE_FILE,
237 };
238 {
239 std::lock_guard<std::mutex> lock(socketMutex_);
240 socketId = Socket(clientInfo);
241 }
242 if (socketId < E_OK) {
243 LOGE("Create OpenSoftbusChannel Socket error");
244 return false;
245 }
246 return true;
247 }
248
SetSocketOpt(int32_t socketId,const char ** src,uint32_t srcLen)249 void SoftBusHandler::SetSocketOpt(int32_t socketId, const char **src, uint32_t srcLen)
250 {
251 #ifdef SUPPORT_SAME_ACCOUNT
252 uint64_t totalSize = 0;
253 for (uint32_t i = 0; i < srcLen; ++i) {
254 const char *file = src[i];
255 struct stat buf {};
256 if (stat(file, &buf) == -1) {
257 return;
258 }
259 totalSize += static_cast<uint64_t>(buf.st_size);
260 }
261
262 TransFlowInfo flowInfo;
263 flowInfo.sessionType = SHORT_DURATION_SESSION;
264 flowInfo.flowQosType = HIGH_THROUGHPUT;
265 flowInfo.flowSize = totalSize;
266 ::SetSocketOpt(socketId, OPT_LEVEL_SOFTBUS, (OptType)OPT_TYPE_FLOW_INFO, (void *)&flowInfo, sizeof(TransFlowInfo));
267 #endif
268 }
269
CopySendFile(int32_t socketId,const std::string & sessionName,const std::string & srcUri,const std::string & dstPath)270 int32_t SoftBusHandler::CopySendFile(int32_t socketId,
271 const std::string &sessionName,
272 const std::string &srcUri,
273 const std::string &dstPath)
274 {
275 LOGI("CopySendFile socketId = %{public}d", socketId);
276
277 std::string physicalPath = SoftBusSessionListener::GetRealPath(srcUri);
278 if (physicalPath.empty()) {
279 LOGE("GetRealPath failed");
280 return FileManagement::ERR_BAD_VALUE;
281 }
282 auto fileList = OHOS::Storage::DistributedFile::Utils::GetFilePath(physicalPath);
283 if (fileList.empty()) {
284 LOGE("GetFilePath failed or file is empty, path %{public}s", physicalPath.c_str());
285 return FileManagement::ERR_BAD_VALUE;
286 }
287 const char *src[MAX_SIZE] = {};
288 for (size_t i = 0; i < fileList.size() && fileList.size() < MAX_SIZE; i++) {
289 src[i] = fileList.at(i).c_str();
290 }
291
292 auto fileNameList = SoftBusSessionListener::GetFileName(fileList, physicalPath, dstPath);
293 if (fileNameList.empty()) {
294 LOGE("GetFileName failed, path %{public}s %{public}s", physicalPath.c_str(), dstPath.c_str());
295 return FileManagement::ERR_BAD_VALUE;
296 }
297 const char *dst[MAX_SIZE] = {};
298 for (size_t i = 0; i < fileNameList.size() && fileList.size() < MAX_SIZE; i++) {
299 dst[i] = fileNameList.at(i).c_str();
300 }
301
302 LOGI("Enter SendFile.");
303 SetSocketOpt(socketId, src, static_cast<uint32_t>(fileList.size()));
304 auto ret = ::SendFile(socketId, src, dst, static_cast<uint32_t>(fileList.size()));
305 if (ret != E_OK) {
306 LOGE("SendFile failed, sessionId = %{public}d", socketId);
307 RadarDotsSendFile("OpenSession", sessionName, sessionName, ret, Utils::StageRes::STAGE_FAIL);
308 return ret;
309 }
310 RadarDotsSendFile("OpenSession", sessionName, sessionName, ret, Utils::StageRes::STAGE_SUCCESS);
311 return E_OK;
312 }
313
ChangeOwnerIfNeeded(int32_t sessionId,const std::string sessionName)314 void SoftBusHandler::ChangeOwnerIfNeeded(int32_t sessionId, const std::string sessionName)
315 {
316 if (sessionName.empty()) {
317 LOGI("sessionName is empty");
318 return;
319 }
320 SoftBusSessionPool::SessionInfo sessionInfo {};
321 int32_t ret = SoftBusSessionPool::GetInstance().GetSessionInfo(sessionName, sessionInfo);
322 if (!ret) {
323 LOGE("GetSessionInfo failed");
324 return;
325 }
326 if (DistributedFile::Utils::ChangeOwnerRecursive(sessionInfo.dstPath, sessionInfo.uid, sessionInfo.uid) != 0) {
327 LOGE("ChangeOwnerRecursive failed");
328 }
329 }
330
CloseSession(int32_t sessionId,const std::string sessionName)331 void SoftBusHandler::CloseSession(int32_t sessionId, const std::string sessionName)
332 {
333 LOGI("CloseSession Enter socketId = %{public}d", sessionId);
334 if (sessionName.empty() || sessionId <= 0) {
335 LOGI("sessionName is empty");
336 return;
337 }
338 if (!serverIdMap_.empty()) {
339 std::lock_guard<std::mutex> lock(serverIdMapMutex_);
340 auto it = serverIdMap_.find(sessionName);
341 if (it != serverIdMap_.end()) {
342 int32_t serverId = it->second;
343 serverIdMap_.erase(it);
344 Shutdown(serverId);
345 LOGI("RemoveSessionServer success.");
346 }
347 }
348 if (!clientSessNameMap_.empty()) {
349 std::lock_guard<std::mutex> lock(clientSessNameMapMutex_);
350 auto it = clientSessNameMap_.find(sessionId);
351 if (it != clientSessNameMap_.end()) {
352 clientSessNameMap_.erase(it->first);
353 }
354 }
355 {
356 std::lock_guard<std::mutex> lock(socketMutex_);
357 Shutdown(sessionId);
358 }
359 RemoveNetworkId(sessionId);
360 SoftBusSessionPool::GetInstance().DeleteSessionInfo(sessionName);
361 }
362
CloseSessionWithSessionName(const std::string sessionName)363 void SoftBusHandler::CloseSessionWithSessionName(const std::string sessionName)
364 {
365 LOGI("CloseSessionWithSessionName Enter.");
366 if (sessionName.empty()) {
367 LOGI("sessionName is empty");
368 return;
369 }
370 int32_t sessionId = INVALID_SESSION_ID;
371 if (!clientSessNameMap_.empty()) {
372 std::lock_guard<std::mutex> lock(clientSessNameMapMutex_);
373 for (auto it : SoftBusHandler::clientSessNameMap_) {
374 if (it.second == sessionName) {
375 sessionId = it.first;
376 clientSessNameMap_.erase(it.first);
377 break;
378 }
379 }
380 }
381 TransManager::GetInstance().NotifyFileFailed(sessionName, E_DFS_CANCEL_SUCCESS);
382 TransManager::GetInstance().DeleteTransTask(sessionName);
383 CloseSession(sessionId, sessionName);
384 }
RemoveNetworkId(int32_t socketId)385 void SoftBusHandler::RemoveNetworkId(int32_t socketId)
386 {
387 LOGI("RemoveNetworkId begin");
388 std::lock_guard<std::mutex> lock(networkIdMapMutex_);
389 auto it = networkIdMap_.find(socketId);
390 if (it == networkIdMap_.end()) {
391 LOGE("socketId not find, socket is %{public}d", socketId);
392 return;
393 }
394 std::string peerNetworkId = it->second;
395 networkIdMap_.erase(it->first);
396 for (auto &item : networkIdMap_) {
397 if (item.second == peerNetworkId) {
398 return;
399 }
400 }
401 AllConnectManager::GetInstance().PublishServiceState(DfsConnectCode::COPY_FILE, peerNetworkId,
402 ServiceCollaborationManagerBussinessStatus::SCM_IDLE);
403 }
404
GetsocketIdFromPeerNetworkId(const std::string & peerNetworkId)405 std::vector<int32_t> SoftBusHandler::GetsocketIdFromPeerNetworkId(const std::string &peerNetworkId)
406 {
407 if (peerNetworkId.empty()) {
408 LOGE("peerNetworkId is empty");
409 return {};
410 }
411 std::vector<int32_t> socketIdList;
412 std::lock_guard<std::mutex> lock(networkIdMapMutex_);
413 for (auto item : networkIdMap_) {
414 if (item.second == peerNetworkId) {
415 socketIdList.emplace_back(item.first);
416 }
417 }
418
419 return socketIdList;
420 }
421
IsService(std::string & sessionName)422 bool SoftBusHandler::IsService(std::string &sessionName)
423 {
424 std::lock_guard<std::mutex> lock(serverIdMapMutex_);
425 auto it = serverIdMap_.find(sessionName);
426 if (it == serverIdMap_.end()) {
427 return false;
428 }
429 return true;
430 }
431
CopyOnStop(const std::string & peerNetworkId)432 void SoftBusHandler::CopyOnStop(const std::string &peerNetworkId)
433 {
434 auto socketIdList = GetsocketIdFromPeerNetworkId(peerNetworkId);
435
436 for (auto socketId : socketIdList) {
437 std::string sessionName = GetSessionName(socketId);
438 if (sessionName.empty()) {
439 LOGE("sessionName is empty");
440 continue;
441 }
442
443 if (IsService(sessionName)) {
444 TransManager::GetInstance().NotifyFileFailed(sessionName, E_DFS_CANCEL_SUCCESS);
445 TransManager::GetInstance().DeleteTransTask(sessionName);
446 }
447
448 CloseSession(socketId, sessionName);
449 }
450 }
451 } // namespace DistributedFile
452 } // namespace Storage
453 } // namespace OHOS