• 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     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