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