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