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