1 /*
2 * Copyright (C) 2022 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 "opp_transfer.h"
17
18 #include <fstream>
19 #include "interface_adapter_manager.h"
20 #include "interface_adapter_classic.h"
21 #include "log.h"
22 #include "opp_message.h"
23 #include "opp_service.h"
24
25 namespace OHOS {
26 namespace bluetooth {
27 int OppTransfer::currentTransferId_ = 0;
28
OppTransfer(const std::string & address,const std::vector<std::string> filePaths,const std::vector<std::string> mimeTypes,int direction)29 OppTransfer::OppTransfer(const std::string &address, const std::vector<std::string> filePaths,
30 const std::vector<std::string> mimeTypes, int direction)
31 {
32 HILOGI("[OPP TRANSFER] start");
33 incomingConnectTimer_ = std::make_unique<utility::Timer>(
34 std::bind(&bluetooth::OppTransfer::IncomingConnectTimeout, this));
35 incomingFileTimer_ = std::make_unique<utility::Timer>(
36 std::bind(&bluetooth::OppTransfer::IncomingFileTimeout, this));
37 time(&timeStamp_);
38 IAdapterClassic *adapterClassic = (IAdapterClassic *)(IAdapterManager::GetInstance()->
39 GetAdapter(ADAPTER_BREDR));
40 if (adapterClassic != nullptr) {
41 deviceName_ = adapterClassic->GetDeviceName(address);
42 }
43 auto filePathItr = filePaths.begin();
44 auto mimeTypeItr = mimeTypes.begin();
45 for (; (filePathItr != filePaths.end() && (mimeTypeItr != mimeTypes.end()));
46 ++filePathItr, ++mimeTypeItr) {
47 IOppTransferInformation transferInfo;
48 transferInfo.SetId(currentTransferId_++);
49 if (currentTransferId_ >= INT_MAX) {
50 currentTransferId_ = 0;
51 }
52 transferInfo.SetFileName(GetFileNameFromPath(*filePathItr));
53 transferInfo.SetFilePath(*filePathItr);
54 transferInfo.SetFileType(*mimeTypeItr);
55 transferInfo.SetDeviceName(deviceName_);
56 transferInfo.SetDeviceAddress(address);
57 transferInfo.SetDirection(direction);
58 transferInfo.SetStatus(OPP_TRANSFER_STATUS_PENDING);
59 transferInfo.SetTimeStamp(static_cast<uint64_t>(timeStamp_));
60 transferInfo.SetTotalBytes(static_cast<uint64_t>(GetFileLength(*filePathItr)));
61 if (transferInfo.GetTotalBytes() > 0) {
62 fileList_.push(transferInfo);
63 }
64 }
65 direction_ = direction;
66 address_ = address;
67 }
68
~OppTransfer()69 OppTransfer::~OppTransfer()
70 {
71 isConnected_ = false;
72 OnTransferStateChangeFaild(OPP_TRANSFER_FAILED_PROTOCOL);
73 }
74
GetFileNumber() const75 int OppTransfer::GetFileNumber() const
76 {
77 return fileList_.size();
78 }
79
GetFileNameFromPath(std::string filePath) const80 std::string OppTransfer::GetFileNameFromPath(std::string filePath) const
81 {
82 std::string fileName;
83 size_t pos = filePath.find_last_of(u'/');
84 if (pos != std::string::npos) {
85 fileName = filePath.substr(pos + 1);
86 }
87 return fileName;
88 }
89
GetFileLength(std::string filePath) const90 size_t OppTransfer::GetFileLength(std::string filePath) const
91 {
92 std::ifstream ifs;
93 ifs.open(filePath, std::ios::in);
94 if (!ifs.is_open()) {
95 HILOGE("[OPP TRANSFER] file open failed");
96 return 0;
97 }
98 ifs.seekg(0, std::ios::end);
99 size_t fileSize = static_cast<size_t>(ifs.tellg());
100 ifs.seekg(0, std::ios::beg);
101 ifs.close();
102 HILOGI("[OPP TRANSFER] File size is %{public}zu", fileSize);
103 return fileSize;
104 }
105
ConnectObex(const ObexClientConfig & config,utility::Dispatcher & dispatcher)106 int OppTransfer::ConnectObex(const ObexClientConfig &config, utility::Dispatcher &dispatcher)
107 {
108 HILOGI("[OPP TRANSFER] Enter");
109
110 if (direction_ == OPP_TRANSFER_DIRECTION_INBOND) {
111 HILOGE("[OPP TRANSFER] is inbond,no need send connect request");
112 return RET_BAD_STATUS;
113 }
114 if (fileList_.empty()) {
115 HILOGE("[OPP TRANSFER] file list is empty");
116 return RET_BAD_STATUS;
117 }
118
119 obexClient_ = std::make_unique<OppObexClient>(config, dispatcher);
120 return obexClient_->Connect(fileList_.size());
121 }
122
DisconnectObex() const123 int OppTransfer::DisconnectObex() const
124 {
125 HILOGI("[OPP TRANSFER] Enter");
126 if (direction_ == OPP_TRANSFER_DIRECTION_INBOND) {
127 HILOGE("[OPP TRANSFER] is inbond,send disconnect request in OppService");
128 return RET_BAD_STATUS;
129 }
130
131 if (obexClient_ == nullptr) {
132 return RET_BAD_STATUS;
133 }
134 return obexClient_->Disconnect(true);
135 }
136
CancelTransfer()137 int OppTransfer::CancelTransfer()
138 {
139 HILOGI("[OPP TRANSFER] Enter");
140 if (direction_ == OPP_TRANSFER_DIRECTION_INBOND) {
141 if (obexSession_ != nullptr) {
142 int ret = obexSession_->SendSimpleResponse(ObexRspCode::BAD_REQUEST);
143 OnTransferStateChangeFaild(OPP_TRANSFER_FAILED_CANCELED);
144 return ret;
145 } else {
146 HILOGE("[OPP TRANSFER]obexSession is null");
147 return RET_BAD_STATUS;
148 }
149 } else if (direction_ == OPP_TRANSFER_DIRECTION_OUTBOND) {
150 if (obexClient_ == nullptr) {
151 return RET_BAD_STATUS;
152 }
153 return obexClient_->CancelSendFile();
154 }
155 HILOGE("[OPP TRANSFER] unknow direction");
156 return RET_BAD_STATUS;
157 }
158
OnReceiveIncomingConnect(ObexServerSession & session,uint32_t connectId)159 void OppTransfer::OnReceiveIncomingConnect(ObexServerSession &session, uint32_t connectId)
160 {
161 HILOGI("[OPP TRANSFER] Enter");
162 if (direction_ != OPP_TRANSFER_DIRECTION_INBOND) {
163 HILOGE("[OPP TRANSFER] is outbond");
164 return;
165 }
166 obexSession_ = &session;
167 connectId_ = connectId;
168 incomingConnectTimer_->Start(INCOMING_CONNECT_TIMEOUT_MS);
169 }
170
OnReceiveIncomingFile(IOppTransferInformation info)171 void OppTransfer::OnReceiveIncomingFile(IOppTransferInformation info)
172 {
173 HILOGI("[OPP TRANSFER] Enter");
174 if (direction_ != OPP_TRANSFER_DIRECTION_INBOND) {
175 HILOGE("[OPP TRANSFER] is outbond");
176 return;
177 }
178 if (!fileList_.empty()) {
179 HILOGE("[OPP TRANSFER] file list not empty");
180 SetIncomingFileConfirmation(false);
181 return;
182 }
183
184 info.SetId(currentTransferId_++);
185 if (currentTransferId_ >= INT_MAX) {
186 currentTransferId_ = 0;
187 }
188 info.SetTimeStamp(static_cast<uint64_t>(timeStamp_));
189 info.SetDeviceName(deviceName_);
190 info.SetDeviceAddress(address_);
191 info.SetDirection(direction_);
192 info.SetStatus(OPP_TRANSFER_STATUS_PENDING);
193 fileList_.push(info);
194
195 if (confirm_ == OPP_TRANSFER_CONFIRM_PENDING) {
196 incomingFileTimer_->Start(INCOMING_FILE_TIMEOUT_MS);
197 OppService::GetService()->NotifyReceiveIncomingFile(fileList_.front());
198 } else if (confirm_ == OPP_TRANSFER_CONFIRM_ACCEPT) {
199 SetIncomingFileConfirmation(true);
200 } else if (confirm_ == OPP_TRANSFER_CONFIRM_REJECT) {
201 SetIncomingFileConfirmation(false);
202 } else {
203 HILOGE("[OPP TRANSFER] unknow confirm");
204 SetIncomingFileConfirmation(false);
205 }
206 }
207
AcceptConnect()208 int OppTransfer::AcceptConnect()
209 {
210 if (direction_ != OPP_TRANSFER_DIRECTION_INBOND) {
211 HILOGE("[OPP TRANSFER] is outbond");
212 return RET_BAD_STATUS;
213 }
214 int ret = RET_BAD_STATUS;
215 incomingConnectTimer_->Stop();
216 if (obexSession_ != nullptr) {
217 OppMessage event(OPP_CONNECTED_EVT);
218 event.dev_ = address_;
219 OppService::GetService()->PostEvent(event);
220
221 auto header = ObexHeader::CreateResponse(ObexRspCode::SUCCESS, true);
222 header->AppendItemConnectionId(connectId_);
223 ret = obexSession_->SendResponse(*header);
224 } else {
225 HILOGE("[OPP TRANSFER] obexSession is null");
226 }
227 if (ret != RET_NO_ERROR) {
228 OppService::GetService()->OnObexDisconnected(address_);
229 }
230 return ret;
231 }
232
StartTransfer()233 int OppTransfer::StartTransfer()
234 {
235 HILOGI("[OPP TRANSFER] Enter");
236
237 if (direction_ == OPP_TRANSFER_DIRECTION_OUTBOND) {
238 if (fileList_.empty()) {
239 HILOGE("[OPP TRANSFER] file list is null");
240 return RET_BAD_STATUS;
241 }
242 isConnected_ = true;
243 if (obexClient_ == nullptr) {
244 return RET_BAD_STATUS;
245 }
246 OnTransferStateChangeRunning();
247 return obexClient_->SendFile(fileList_.front());
248 } else if (direction_ == OPP_TRANSFER_DIRECTION_INBOND) {
249 isConnected_ = true;
250 return RET_NO_ERROR;
251 } else {
252 HILOGE("[OPP TRANSFER] unknow direction");
253 }
254
255 return RET_BAD_STATUS;
256 }
257
SetIncomingFileConfirmation(bool accept)258 int OppTransfer::SetIncomingFileConfirmation(bool accept)
259 {
260 HILOGI("[OPP TRANSFER] Enter");
261 int ret = RET_BAD_STATUS;
262 if (direction_ != OPP_TRANSFER_DIRECTION_INBOND) {
263 return RET_BAD_STATUS;
264 }
265 if (accept) {
266 confirm_ = OPP_TRANSFER_CONFIRM_ACCEPT;
267 } else {
268 confirm_ = OPP_TRANSFER_CONFIRM_REJECT;
269 }
270 incomingFileTimer_->Stop();
271 if (obexSession_ != nullptr) {
272 ObexRspCode rspCode = ObexRspCode::FORBIDDEN;
273 if (accept) {
274 rspCode = ObexRspCode::CONTINUE;
275 OnTransferStateChangeRunning();
276 } else {
277 OnTransferStateChangeFaild(OPP_TRANSFER_FAILED_CANCELED);
278 }
279 auto respHeader = ObexHeader::CreateResponse(rspCode);
280 respHeader->AppendItemConnectionId(connectId_);
281 std::unique_ptr<ObexServerReceivedObject> &receivedObject = obexSession_->GetReceivedObject();
282 if ((receivedObject != nullptr) && receivedObject->IsSrmEnable()) {
283 respHeader->AppendItemSrm(true);
284 }
285 ret = obexSession_->SendResponse(*respHeader);
286 }
287 if (ret != RET_NO_ERROR) {
288 OnTransferStateChangeFaild(OPP_TRANSFER_FAILED_CANCELED);
289 }
290 return ret;
291 }
292
GetCurrentTransferInformation()293 IOppTransferInformation OppTransfer::GetCurrentTransferInformation()
294 {
295 if (curretTransferInfo_ == nullptr) {
296 IOppTransferInformation ret;
297 return ret;
298 }
299 return *curretTransferInfo_;
300 }
301
IncomingConnectTimeout()302 void OppTransfer::IncomingConnectTimeout()
303 {
304 if (obexSession_ == nullptr) {
305 HILOGE("[OPP TRANSFER] obexSession_ is null");
306 return;
307 }
308 auto header = ObexHeader::CreateResponse(ObexRspCode::SERVICE_UNAVAILABLE, true);
309 obexSession_->SendResponse(*header);
310 obexSession_->Disconnect();
311 OppService::GetService()->OnObexDisconnected(address_);
312 }
313
IncomingFileTimeout()314 void OppTransfer::IncomingFileTimeout()
315 {
316 if (obexSession_ == nullptr) {
317 HILOGE("[OPP TRANSFER] obexSession_ is null");
318 return;
319 }
320 auto respHeader = ObexHeader::CreateResponse(ObexRspCode::FORBIDDEN);
321 respHeader->AppendItemConnectionId(connectId_);
322 std::unique_ptr<ObexServerReceivedObject> &receivedObject = obexSession_->GetReceivedObject();
323 if ((receivedObject != nullptr) && receivedObject->IsSrmEnable()) {
324 respHeader->AppendItemSrm(true);
325 }
326 obexSession_->SendResponse(*respHeader);
327 OnTransferStateChangeFaild(OPP_TRANSFER_FAILED_CANCELED);
328 }
329
GetDeviceAddress()330 std::string OppTransfer::GetDeviceAddress()
331 {
332 return address_;
333 }
334
GetDirection() const335 int OppTransfer::GetDirection() const
336 {
337 return direction_;
338 }
339
OnObexDisconnected()340 void OppTransfer::OnObexDisconnected()
341 {
342 isConnected_ = false;
343 obexSession_ = nullptr;
344 connectId_ = 0;
345 OnTransferStateChangeFaild(OPP_TRANSFER_FAILED_CONNECTION_FAILED);
346 }
347
OnTransferStateChange(int state,int reason)348 void OppTransfer::OnTransferStateChange(int state, int reason)
349 {
350 HILOGI("[OPP TRANSFER] Enter");
351
352 if (state == OPP_TRANSFER_STATUS_RUNNING) {
353 OnTransferStateChangeRunning();
354 } else if (state == OPP_TRANSFER_STATUS_SUCCESS) {
355 OnTransferStateChangeSuccess();
356 } else if (state == OPP_TRANSFER_STATUS_FAILD) {
357 OnTransferStateChangeFaild(reason);
358 } else {
359 HILOGE("[OPP TRANSFER] error state=%{public}d", state);
360 }
361 }
362
OnTransferStateChangeRunning()363 void OppTransfer::OnTransferStateChangeRunning()
364 {
365 if (!isConnected_) {
366 HILOGE("[OPP TRANSFER]obex is not connected");
367 return;
368 }
369 if (fileList_.empty()) {
370 HILOGE("[OPP TRANSFER] file list is empty");
371 return;
372 }
373 curretTransferInfo_ = std::make_unique<IOppTransferInformation>(fileList_.front());
374 curretTransferInfo_->SetStatus(OPP_TRANSFER_STATUS_RUNNING);
375 OppService::GetService()->NotifyTransferStateChanged(*curretTransferInfo_);
376 }
377
OnTransferStateChangeSuccess()378 void OppTransfer::OnTransferStateChangeSuccess()
379 {
380 if (!isConnected_) {
381 HILOGE("[OPP TRANSFER] obex is not connected");
382 return;
383 }
384 if (curretTransferInfo_ == nullptr) {
385 HILOGE("[OPP TRANSFER] curretTransferInfo_ is null");
386 return;
387 }
388 if (fileList_.empty()) {
389 HILOGE("[OPP TRANSFER] file list is empty");
390 return;
391 }
392 curretTransferInfo_->SetStatus(OPP_TRANSFER_STATUS_SUCCESS);
393 OppService::GetService()->NotifyTransferStateChanged(*curretTransferInfo_);
394 curretTransferInfo_ = nullptr;
395 fileList_.pop();
396 if (direction_ == OPP_TRANSFER_DIRECTION_OUTBOND) {
397 if (fileList_.empty()) {
398 OppMessage event(OPP_DISCONNECT_REQ_EVT);
399 event.dev_ = address_;
400 OppService::GetService()->PostEvent(event);
401 } else {
402 if (obexClient_ == nullptr) {
403 HILOGE("[OPP TRANSFER] obexClient_ is null");
404 OnTransferStateChangeFaild(OPP_TRANSFER_FAILED_PROTOCOL);
405 return;
406 }
407 OnTransferStateChangeRunning();
408 if (obexClient_->SendFile(fileList_.front()) != RET_NO_ERROR) {
409 HILOGE("[OPP TRANSFER] send file error");
410 OnTransferStateChangeFaild(OPP_TRANSFER_FAILED_PROTOCOL);
411 return;
412 }
413 }
414 }
415 }
416
OnTransferStateChangeFaild(int reason)417 void OppTransfer::OnTransferStateChangeFaild(int reason)
418 {
419 if (curretTransferInfo_ != nullptr) {
420 curretTransferInfo_->SetStatus(OPP_TRANSFER_STATUS_FAILD);
421 curretTransferInfo_->SetFailedReason(reason);
422 OppService::GetService()->NotifyTransferStateChanged(*curretTransferInfo_);
423 curretTransferInfo_ = nullptr;
424 if (!fileList_.empty()) {
425 fileList_.pop();
426 }
427 }
428 while (!fileList_.empty()) {
429 IOppTransferInformation transferInfo = fileList_.front();
430 transferInfo.SetStatus(OPP_TRANSFER_STATUS_FAILD);
431 transferInfo.SetFailedReason(reason);
432 OppService::GetService()->NotifyTransferStateChanged(transferInfo);
433 fileList_.pop();
434 }
435 if ((direction_ == OPP_TRANSFER_DIRECTION_OUTBOND) && isConnected_) {
436 OppMessage event(OPP_DISCONNECT_REQ_EVT);
437 event.dev_ = address_;
438 OppService::GetService()->PostEvent(event);
439 }
440 }
441
OnTransferPositionChange(size_t position) const442 void OppTransfer::OnTransferPositionChange(size_t position) const
443 {
444 HILOGI("[OPP TRANSFER] Enter");
445
446 if (curretTransferInfo_ == nullptr) {
447 HILOGE("[OPP TRANSFER] curretTransferInfo_ is null");
448 return;
449 }
450 if (fileList_.empty()) {
451 HILOGE("[OPP TRANSFER] file list is empty");
452 return;
453 }
454 curretTransferInfo_->SetCurrentBytes(static_cast<uint64_t>(position));
455 OppService::GetService()->NotifyTransferStateChanged(*curretTransferInfo_);
456 }
457 } // namespace bluetooth
458 } // namespace OHOS