• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 "softbus_agent.h"
17 
18 #include <fcntl.h>
19 #include <mutex>
20 #include <unistd.h>
21 
22 #include "device_manager_agent.h"
23 #include "dfsu_exception.h"
24 #include "distributedfile_service.h"
25 #include "i_distributedfile_service.h"
26 #include "iservice_registry.h"
27 #include "session.h"
28 #include "softbus_dispatcher.h"
29 #include "system_ability_definition.h"
30 #include "utils_directory.h"
31 #include "utils_log.h"
32 
33 namespace OHOS {
34 namespace Storage {
35 namespace DistributedFile {
36 namespace {
37     constexpr int32_t SOFTBUS_OK = 0;
38     constexpr int32_t DEVICE_ID_SIZE_MAX = 65;
39     constexpr int32_t IS_CLIENT = 1;
40     const std::string DEFAULT_ROOT_PATH = "/data/service/el2/100/hmdfs/non_account/data/";
41 }
42 
SoftbusAgent()43 SoftbusAgent::SoftbusAgent() {}
44 
~SoftbusAgent()45 SoftbusAgent::~SoftbusAgent()
46 {
47     StopInstance();
48 }
49 
StartInstance()50 void SoftbusAgent::StartInstance()
51 {
52     RegisterSessionListener();
53     RegisterFileListener();
54 }
55 
StopInstance()56 void SoftbusAgent::StopInstance()
57 {
58     {
59         std::unique_lock<std::mutex> lock(sessionMapMux_);
60         for (auto iter = cidToSessionID_.begin(); iter != cidToSessionID_.end();) {
61             CloseSession(iter->first);
62             iter = cidToSessionID_.erase(iter);
63         }
64     }
65     getSessionCV_.notify_all();
66     UnRegisterSessionListener();
67 }
68 
OnDeviceOnline(const std::string & cid)69 void SoftbusAgent::OnDeviceOnline(const std::string &cid)
70 {
71 }
72 
SendFile(const std::string & cid,const char * sFileList[],const char * dFileList[],uint32_t fileCnt)73 int SoftbusAgent::SendFile(const std::string &cid, const char *sFileList[], const char *dFileList[], uint32_t fileCnt)
74 {
75     // first check whether the sessionId available
76     auto alreadyOnliceDev = DeviceManagerAgent::GetInstance()->getOnlineDevs();
77     if (alreadyOnliceDev.find(cid) == alreadyOnliceDev.end()) {
78         LOGE("cid:%{public}s has not been online yet, sendfile maybe will fail, try", cid.c_str());
79     }
80     int sessionId = -1;
81     {
82         std::unique_lock<std::mutex> lock(sessionMapMux_);
83         if (cidToSessionID_.find(cid) != cidToSessionID_.end() &&
84             cidToSessionID_[cid].empty() == false) { // to avoid list is empty
85             sessionId = cidToSessionID_[cid].front();
86         }
87     }
88 
89     // build socket synchronously
90     if (sessionId == -1) {
91         OpenSession(cid);
92         // wait for get sessionId
93         LOGD("openSession, wait");
94         std::unique_lock<std::mutex> lock(getSessionCVMut_);
95         getSessionCV_.wait(lock, [this, cid]() { return !cidToSessionID_[cid].empty(); });
96         LOGD("openSession success, wakeup");
97         if (cidToSessionID_[cid].empty()) { // wakeup check
98             LOGE("there is no sessionId of cid:%{public}s", cid.c_str());
99             return -1;
100         }
101         sessionId = cidToSessionID_[cid].front();
102     }
103 
104     int ret = ::SendFile(sessionId, sFileList, dFileList, fileCnt);
105     if (ret != 0) {
106         return -1;
107     }
108     return 0;
109 }
110 
OpenSession(const std::string & cid)111 void SoftbusAgent::OpenSession(const std::string &cid)
112 {
113     SessionAttribute attr;
114     attr.dataType = TYPE_FILE; // files use UDP, CHANNEL_TYPE_UDP
115     int sessionId = ::OpenSession(sessionName_.c_str(), sessionName_.c_str(), cid.c_str(), "DFS_wifiGroup", &attr);
116     if (sessionId < 0) {
117         return;
118     }
119 }
120 
OnSessionOpened(const int sessionId,const int result)121 void SoftbusAgent::OnSessionOpened(const int sessionId, const int result)
122 {
123     if (result != 0) {
124         LOGE("open failed, result:%{public}d", result);
125         return;
126     }
127     std::string cid = GetPeerDevId(sessionId);
128     if (cid == "") {
129         LOGE("get peer device id failed");
130         return;
131     }
132 
133     // client session priority use, so insert list head
134     {
135         std::unique_lock<std::mutex> lock(sessionMapMux_);
136         if (::GetSessionSide(sessionId) == IS_CLIENT) {
137             cidToSessionID_[cid].push_back(sessionId);
138         }
139     }
140 
141     getSessionCV_.notify_one();
142 
143     if (notifyCallback_ == nullptr) {
144         LOGE("OnSessionOpened Nofify pointer is empty");
145         return;
146     }
147     notifyCallback_->SessionOpened(cid);
148 }
149 
OnSendFileFinished(const int sessionId,const std::string firstFile)150 void SoftbusAgent::OnSendFileFinished(const int sessionId, const std::string firstFile)
151 {
152     if (notifyCallback_ == nullptr) {
153         LOGE("OnSendFileFinished Nofify pointer is empty");
154         return;
155     }
156     std::string cid = GetPeerDevId(sessionId);
157     notifyCallback_->SendFinished(cid, firstFile);
158 }
159 
OnFileTransError(const int sessionId)160 void SoftbusAgent::OnFileTransError(const int sessionId)
161 {
162     if (notifyCallback_ == nullptr) {
163         LOGE("OnFileTransError Nofify pointer is empty");
164         return;
165     }
166     std::string cid = GetPeerDevId(sessionId);
167     if (::GetSessionSide(sessionId) == IS_CLIENT) {
168         notifyCallback_->SendError(cid);
169     } else {
170         notifyCallback_->ReceiveError(cid);
171     }
172 }
173 
OnReceiveFileFinished(const int sessionId,const std::string files,int fileCnt)174 void SoftbusAgent::OnReceiveFileFinished(const int sessionId, const std::string files, int fileCnt)
175 {
176     if (notifyCallback_ == nullptr) {
177         LOGE("OnReceiveFileFinished Nofify pointer is empty");
178         return;
179     }
180     std::string cid = GetPeerDevId(sessionId);
181     if (cid.empty()) {
182         auto alreadyOnliceDev = DeviceManagerAgent::GetInstance()->getOnlineDevs();
183         LOGI("IsDeviceOnline size, %{public}d", alreadyOnliceDev.size());
184         for (std::string item : alreadyOnliceDev) {
185             LOGI("IsDeviceOnline item, %{public}s", item.c_str());
186             cid = item;
187         }
188     }
189 
190     std::string desFileName = DEFAULT_ROOT_PATH + files;
191     int32_t fd = open(desFileName.c_str(), O_RDONLY);
192     if (fd <= 0) {
193         LOGE("NapiWriteFile open recive distributedfile %{public}d, %{public}s, %{public}d",
194             fd, desFileName.c_str(), errno);
195         return;
196     }
197     notifyCallback_->WriteFile(fd, files);
198     notifyCallback_->ReceiveFinished(cid, files, fileCnt);
199 }
200 
OnSessionClosed(int sessionId)201 void SoftbusAgent::OnSessionClosed(int sessionId)
202 {
203     std::string cid = GetPeerDevId(sessionId);
204     if (cid == "") {
205         LOGE("get peer device id failed");
206         return;
207     }
208     {
209         std::unique_lock<std::mutex> lock(sessionMapMux_);
210         if (cidToSessionID_.find(cid) != cidToSessionID_.end()) {
211             cidToSessionID_[cid].remove(sessionId);
212         }
213     }
214 
215     if (notifyCallback_ == nullptr) {
216         LOGE("OnSessionClosed Nofify pointer is empty");
217         return;
218     }
219     notifyCallback_->SessionClosed(cid);
220 }
221 
GetPeerDevId(const int sessionId)222 std::string SoftbusAgent::GetPeerDevId(const int sessionId)
223 {
224     std::string cid;
225     char peerDevId[DEVICE_ID_SIZE_MAX] = { '\0' };
226     int ret = ::GetPeerDeviceId(sessionId, peerDevId, sizeof(peerDevId));
227     if (ret != SOFTBUS_OK) {
228         LOGE("get my peer device id failed, errno:%{public}d, sessionId:%{public}d", ret, sessionId);
229         cid = "";
230     } else {
231         cid = std::string(peerDevId);
232     }
233 
234     return cid;
235 }
236 
CloseSession(const std::string & cid)237 void SoftbusAgent::CloseSession(const std::string &cid)
238 {
239     if (cidToSessionID_.find(cid) == cidToSessionID_.end()) {
240         LOGE("not find this dev-cid:%{public}s", cid.c_str());
241         return;
242     }
243     for (auto sessionId : cidToSessionID_[cid]) {
244         ::CloseSession(sessionId);
245     }
246     LOGD("Close Session done, cid:%{public}s", cid.c_str());
247 }
248 
OnDeviceOffline(const std::string & cid)249 void SoftbusAgent::OnDeviceOffline(const std::string &cid)
250 {
251     CloseSession(cid);
252     {
253         std::unique_lock<std::mutex> lock(sessionMapMux_);
254         cidToSessionID_.erase(cid);
255     }
256 }
257 
RegisterSessionListener()258 void SoftbusAgent::RegisterSessionListener()
259 {
260     ISessionListener sessionListener = {
261         .OnSessionOpened = SoftbusDispatcher::OnSessionOpened,
262         .OnSessionClosed = SoftbusDispatcher::OnSessionClosed,
263     };
264     int ret = ::CreateSessionServer(DistributedFileService::pkgName_.c_str(), sessionName_.c_str(), &sessionListener);
265     if (ret != 0) {
266         std::stringstream ss;
267         ss << "Failed to CreateSessionServer, errno:" << ret;
268         LOGE("%{public}s, sessionName:%{public}s", ss.str().c_str(), sessionName_.c_str());
269         return throw std::runtime_error(ss.str());
270     }
271     LOGD("Succeed to CreateSessionServer, pkgName %{public}s, sbusName:%{public}s",
272         DistributedFileService::pkgName_.c_str(), sessionName_.c_str());
273 }
274 
RegisterFileListener()275 void SoftbusAgent::RegisterFileListener()
276 {
277     IFileSendListener fileSendListener = {
278         .OnSendFileFinished = SoftbusDispatcher::OnSendFileFinished,
279         .OnFileTransError = SoftbusDispatcher::OnFileTransError,
280     };
281     std::string pkgName = DistributedFileService::pkgName_;
282     int ret = ::SetFileSendListener(pkgName.c_str(), sessionName_.c_str(), &fileSendListener);
283     if (ret != 0) {
284         std::stringstream ss;
285         ss << "Failed to SetFileSendListener, errno:" << ret;
286         LOGE("%{public}s, sessionName:%{public}s", ss.str().c_str(), sessionName_.c_str());
287         throw std::runtime_error(ss.str());
288     }
289     LOGD("Succeed to SetFileSendListener, pkgName %{public}s, sbusName:%{public}s", pkgName.c_str(),
290          sessionName_.c_str());
291 
292     IFileReceiveListener fileRecvListener = {
293         .OnReceiveFileFinished = SoftbusDispatcher::OnReceiveFileFinished,
294         .OnFileTransError = SoftbusDispatcher::OnFileTransError,
295     };
296     ret = ::SetFileReceiveListener(pkgName.c_str(), sessionName_.c_str(), &fileRecvListener,
297         DEFAULT_ROOT_PATH.c_str());
298     if (ret != 0) {
299         std::stringstream ss;
300         ss << "Failed to SetFileReceiveListener, errno:" << ret;
301         LOGE("%{public}s, sessionName:%{public}s", ss.str().c_str(), sessionName_.c_str());
302         throw std::runtime_error(ss.str());
303     }
304     LOGD("Succeed to SetFileReceiveListener, pkgName %{public}s, sbusName:%{public}s", pkgName.c_str(),
305          sessionName_.c_str());
306 }
307 
UnRegisterSessionListener()308 void SoftbusAgent::UnRegisterSessionListener()
309 {
310     int ret = ::RemoveSessionServer(DistributedFileService::pkgName_.c_str(), sessionName_.c_str());
311     if (ret != 0) {
312         std::stringstream ss;
313         ss << "Failed to RemoveSessionServer, errno:" << ret;
314         LOGE("%{public}s", ss.str().c_str());
315         throw std::runtime_error(ss.str());
316     }
317     LOGD("RemoveSessionServer success!");
318 }
319 
SetTransCallback(sptr<IFileTransferCallback> & callback)320 void SoftbusAgent::SetTransCallback(sptr<IFileTransferCallback> &callback)
321 {
322     notifyCallback_ = callback;
323 }
324 
RemoveTransCallbak()325 void SoftbusAgent::RemoveTransCallbak()
326 {
327     notifyCallback_ = nullptr;
328 }
329 } // namespace DistributedFile
330 } // namespace Storage
331 } // namespace OHOS