• 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_obex_client.h"
17 
18 #include <codecvt>
19 #include "bt_def.h"
20 #include "log.h"
21 #include "log_util.h"
22 #include "opp_service.h"
23 
24 namespace OHOS {
25 namespace bluetooth {
OppSendFileBodyObject(const std::string & file)26 OppSendFileBodyObject::OppSendFileBodyObject(const std::string &file)
27 {
28     OpenFile(file);
29 }
30 
~OppSendFileBodyObject()31 OppSendFileBodyObject::~OppSendFileBodyObject()
32 {
33     try {
34         Close();
35     } catch(std::exception &e) {
36         LOG_ERROR("[OPP OBEX SERVER]%{public}s():Catch exception %{public}s", __FUNCTION__, e.what());
37     }
38 }
39 
OpenFile(const std::string & file)40 void OppSendFileBodyObject::OpenFile(const std::string &file)
41 {
42     ifs_.open(file, std::ios::in);
43     if (!ifs_.is_open()) {
44         HILOGE("[OPP OBEX CLIENT] file open failed");
45         return;
46     } else {
47         HILOGI("[OPP OBEX CLIENT] file=%{public}s  opened.", file.c_str());
48     }
49     ifs_.seekg(0, std::ios::end);
50     fileSize_ = static_cast<size_t>(ifs_.tellg());
51     ifs_.seekg(0, std::ios::beg);
52 }
53 
Read(uint8_t * buf,size_t bufLen)54 size_t OppSendFileBodyObject::Read(uint8_t *buf, size_t bufLen)
55 {
56     size_t readSize = bufLen;
57     size_t remainSize = fileSize_ - fileSendSize_;
58     if (remainSize < readSize) {
59         readSize = remainSize;
60     }
61     ifs_.read(reinterpret_cast<char*>(buf), readSize);
62     fileSendSize_ += readSize;
63     return readSize;
64 }
65 
Write(const uint8_t * buf,size_t bufLen)66 size_t OppSendFileBodyObject::Write(const uint8_t *buf, size_t bufLen)
67 {
68     return bufLen;
69 }
70 
GetFileSize() const71 size_t OppSendFileBodyObject::GetFileSize() const
72 {
73     return fileSize_;
74 }
75 
GetFileSendSize() const76 size_t OppSendFileBodyObject::GetFileSendSize() const
77 {
78     return fileSendSize_;
79 }
80 
Close()81 int OppSendFileBodyObject::Close()
82 {
83     ifs_.close();
84     return RET_NO_ERROR;
85 }
86 
OppObexClient(const ObexClientConfig & config,utility::Dispatcher & dispatcher)87 OppObexClient::OppObexClient(const ObexClientConfig &config, utility::Dispatcher &dispatcher)
88 {
89     observer_ = std::make_unique<OppObexObserver>(this);
90     client_ = std::make_unique<ObexClient>(config, *observer_, dispatcher);
91     if (config.isGoepL2capPSM_ && (config.scn_ != OPP_GOEP_L2CAP_PSM)) {
92         ObexClient::RegisterL2capLPsm(config.scn_);
93         lpsm_ = config.scn_;
94         isRegisterL2capLPsm_ = true;
95     }
96     if (config.isGoepL2capPSM_) {
97         isSupportSrm_ = true;
98     } else {
99         isSupportSrm_ = false;
100     }
101     address_ = RawAddress::ConvertToString(config.addr_.addr).GetAddress();
102     SendFileThread_ = std::make_unique<utility::Dispatcher>(OPP_SEND_FILE_THREAD_NAME);
103     SendFileThread_->Initialize();
104 }
105 
~OppObexClient()106 OppObexClient::~OppObexClient()
107 {
108     if (isBusy_) {
109         isBusy_ = false;
110         std::lock_guard<std::mutex> lock(mutexBusyChanged_);
111         cvWaitBusyChanged_.notify_all();
112     }
113     if (isRegisterL2capLPsm_) {
114         ObexClient::DeregisterL2capLPsm(lpsm_);
115         lpsm_ = 0;
116     }
117     if (SendFileThread_ != nullptr) {
118         SendFileThread_->Uninitialize();
119     }
120 }
121 
Connect(uint32_t fileCount) const122 int OppObexClient::Connect(uint32_t fileCount) const
123 {
124     HILOGI("[OPP OBEX CLIENT] start");
125     int ret = RET_BAD_STATUS;
126     if (observer_ == nullptr) {
127         HILOGE("[OPP OBEX CLIENT] end, observer_ is null");
128         return ret;
129     }
130     ObexConnectParams param = {.count = &fileCount};
131     ret = client_->Connect(param);
132 
133     HILOGI("[OPP OBEX CLIENT] end");
134     return ret;
135 }
136 
Disconnect(bool withObexReq) const137 int OppObexClient::Disconnect(bool withObexReq) const
138 {
139     HILOGI("[OPP OBEX CLIENT] start");
140     int ret = RET_BAD_STATUS;
141     if (client_ == nullptr) {
142         HILOGE("[OPP OBEX CLIENT] end, client_ is null");
143         return ret;
144     }
145     ret = client_->Disconnect(withObexReq);
146     HILOGI("[OPP OBEX CLIENT] end");
147     return ret;
148 }
149 
CancelSendFile()150 int OppObexClient::CancelSendFile()
151 {
152     HILOGI("[OPP OBEX CLIENT] start");
153     sendAbort_ = true;
154     HILOGI("[OPP OBEX CLIENT] end");
155     return RET_NO_ERROR;
156 }
157 
SendFile(IOppTransferInformation fileInfo)158 int OppObexClient::SendFile(IOppTransferInformation fileInfo)
159 {
160     HILOGI("[OPP OBEX CLIENT] start");
161     int ret = RET_BAD_STATUS;
162     if (client_ == nullptr) {
163         HILOGE("[OPP OBEX CLIENT] end, client_ is null");
164         return ret;
165     }
166     if (fileInfo.GetTotalBytes() <= 0) {
167         return RET_BAD_STATUS;
168     }
169     auto reqHeader = ObexHeader::CreateRequest(ObexOpeId::PUT);
170     if (connectionId_ != 0) {
171         reqHeader->AppendItemConnectionId(connectionId_);
172     }
173     reqHeader->AppendItemName(StringToU16string(fileInfo.GetFileName()));
174     reqHeader->AppendItemType(fileInfo.GetFileType());
175     reqHeader->AppendItemLength(fileInfo.GetTotalBytes());
176     if (isSupportSrm_) {
177         reqHeader->AppendItemSrm(true);
178     }
179     ret = client_->Put(*reqHeader);
180     status_ = OPP_OBEX_STATUS_WAITING_CONTINUE;
181 
182     fileObject_ = std::make_shared<OppSendFileBodyObject>(fileInfo.GetFilePath());
183     auto bodyHeader = ObexHeader::CreateRequest(ObexOpeId::PUT);
184     if (connectionId_ != 0) {
185         bodyHeader->AppendItemConnectionId(connectionId_);
186     }
187     uint16_t mtu = client_->GetClientSession().GetMaxPacketLength();
188     client_->GetClientSession().CreateSendObject(*bodyHeader, fileObject_, mtu);
189 
190     HILOGI("[OPP OBEX CLIENT] end");
191     return ret;
192 }
193 
SendFileBody()194 void OppObexClient::SendFileBody()
195 {
196     int ret = RET_BAD_STATUS;
197     if (client_ == nullptr) {
198         HILOGE("[OPP OBEX CLIENT] end, client_ is null");
199         OnTransferStateChangeFaild(OPP_TRANSFER_FAILED_PROTOCOL);
200         return;
201     }
202     if (fileObject_ == nullptr) {
203         HILOGE("[OPP OBEX CLIENT] end, fileObject_ is null");
204         OnTransferStateChangeFaild(OPP_TRANSFER_FAILED_PROTOCOL);
205         return;
206     }
207     auto &sendObject = client_->GetClientSession().GetSendObject();
208     if (sendObject == nullptr) {
209         HILOGE("[OPP OBEX CLIENT] end, sendObject is null");
210         OnTransferStateChangeFaild(OPP_TRANSFER_FAILED_PROTOCOL);
211         return;
212     }
213     while (!sendObject->IsDone()) {
214         if (!startSendFile_) {
215             return;
216         }
217         if (isBusy_) {
218             std::unique_lock<std::mutex> lock(mutexBusyChanged_);
219             cvWaitBusyChanged_.wait(lock, [this] { return !isBusy_; });
220         }
221         if (sendAbort_) {
222             client_->Abort();
223             client_->GetClientSession().FreeSendObject();
224             sendAbort_ = false;
225             OnTransferStateChangeFaild(OPP_TRANSFER_FAILED_CANCELED);
226             return;
227         }
228         auto sendReq = sendObject->GetNextReqHeader(false);
229         if (sendReq == nullptr) {
230             client_->GetClientSession().FreeSendObject();
231             OnTransferStateChangeFaild(OPP_TRANSFER_FAILED_PROTOCOL);
232             return;
233         }
234         ret = client_->Put(*sendReq);
235         if (ret != RET_NO_ERROR) {
236             client_->GetClientSession().FreeSendObject();
237             OnTransferStateChangeFaild(OPP_TRANSFER_FAILED_PROTOCOL);
238             return;
239         }
240         OppService::GetService()->OnTransferPositionChange(
241             address_, static_cast<OppSendFileBodyObject *>(fileObject_.get())->GetFileSendSize());
242         if (!sendObject->IsDone() && !isSupportSrm_) {
243             status_ = OPP_OBEX_STATUS_WAITING_CONTINUE;
244             return;
245         }
246     }
247     status_ = OPP_OBEX_STATUS_WAITING_END;
248     client_->GetClientSession().FreeSendObject();
249     fileObject_ = nullptr;
250 }
251 
SendOppDisconnected()252 void OppObexClient::SendOppDisconnected()
253 {
254     OppMessage event(OPP_DISCONNECTED_EVT);
255     event.dev_ = address_;
256     OppService::GetService()->PostEvent(event);
257     HILOGI("[OPP OBEX CLIENT] end");
258 }
259 
SendOppConnected()260 void OppObexClient::SendOppConnected()
261 {
262     OppMessage event(OPP_CONNECTED_EVT);
263     event.dev_ = address_;
264     OppService::GetService()->PostEvent(event);
265     HILOGI("[OPP OBEX CLIENT] end");
266 }
267 
OnTransferStateChangeFaild(int reason)268 void OppObexClient::OnTransferStateChangeFaild(int reason)
269 {
270     startSendFile_ = false;
271     OppService::GetService()->OnTransferStateChange(address_, OPP_TRANSFER_STATUS_FAILD, reason);
272 }
273 
OnTransportFailed(ObexClient & client,int errCd)274 void OppObexClient::OppObexObserver::OnTransportFailed(ObexClient &client, int errCd)
275 {
276     HILOGI("[OPP OBEX CLIENT] start");
277     if (oppObexClient_ == nullptr) {
278         HILOGE("[OPP OBEX CLIENT] oppObexClient_ is null");
279         return;
280     }
281     oppObexClient_->OnTransportFailed(client, errCd);
282 }
283 
OnTransportFailed(const ObexClient & client,int errCd)284 void OppObexClient::OnTransportFailed(const ObexClient &client, int errCd)
285 {
286     HILOGI("[OPP OBEX CLIENT] start");
287     std::string address = client.GetClientSession().GetRemoteAddr().GetAddress();
288     if (address_ != address) {
289         HILOGE("[OPP OBEX CLIENT] end, not current device");
290         return;
291     }
292     HILOGE("[OPP OBEX CLIENT]Transport failed with error %{public}d", errCd);
293     connectionId_ = 0;
294     SendOppDisconnected();
295     HILOGI("[OPP OBEX CLIENT] end");
296 }
297 
OnConnected(ObexClient & client,const ObexHeader & resp)298 void OppObexClient::OppObexObserver::OnConnected(ObexClient &client, const ObexHeader &resp)
299 {
300     HILOGI("[OPP OBEX CLIENT] start");
301     if (oppObexClient_ == nullptr) {
302         HILOGE("[OPP OBEX CLIENT] oppObexClient_ is null");
303         return;
304     }
305     oppObexClient_->OnConnected(client, resp);
306 }
307 
OnConnected(const ObexClient & client,const ObexHeader & resp)308 void OppObexClient::OnConnected(const ObexClient &client, const ObexHeader &resp)
309 {
310     HILOGI("[OPP OBEX CLIENT] start");
311     std::string address = client.GetClientSession().GetRemoteAddr().GetAddress();
312     if (address_ != address) {
313         HILOGE("[OPP OBEX CLIENT] end, not current device");
314         return;
315     }
316 
317     auto connectId = resp.GetItemConnectionId();
318     if (connectId != nullptr) {
319         connectionId_ = connectId->GetWord();
320     } else {
321         connectionId_ = 0;
322     }
323     SendOppConnected();
324     HILOGI("[OPP OBEX CLIENT] end");
325 }
326 
OnConnectFailed(ObexClient & client,const ObexHeader & resp)327 void OppObexClient::OppObexObserver::OnConnectFailed(ObexClient &client, const ObexHeader &resp)
328 {
329     HILOGI("[OPP OBEX CLIENT] start");
330     if (oppObexClient_ == nullptr) {
331         HILOGE("[OPP OBEX CLIENT] oppObexClient_ is null");
332         return;
333     }
334     oppObexClient_->OnConnectFailed(client);
335 }
336 
OnConnectFailed(const ObexClient & client)337 void OppObexClient::OnConnectFailed(const ObexClient &client)
338 {
339     HILOGI("[OPP OBEX CLIENT] start");
340     std::string address = client.GetClientSession().GetRemoteAddr().GetAddress();
341     if (address_ != address) {
342         HILOGE("[OPP OBEX CLIENT] end, not current device");
343         return;
344     }
345     connectionId_ = 0;
346     SendOppDisconnected();
347     HILOGI("[OPP OBEX CLIENT] end");
348 }
349 
OnDisconnected(ObexClient & client)350 void OppObexClient::OppObexObserver::OnDisconnected(ObexClient &client)
351 {
352     HILOGI("[OPP OBEX CLIENT] start");
353     if (oppObexClient_ == nullptr) {
354         HILOGE("[OPP OBEX CLIENT] oppObexClient_ is null");
355         return;
356     }
357     oppObexClient_->OnDisconnected(client);
358 }
359 
OnDisconnected(const ObexClient & client)360 void OppObexClient::OnDisconnected(const ObexClient &client)
361 {
362     HILOGI("[OPP OBEX CLIENT] start");
363     std::string address = client.GetClientSession().GetRemoteAddr().GetAddress();
364     if (address_ != address) {
365         HILOGE("[OPP OBEX CLIENT] end, not current device");
366         return;
367     }
368     connectionId_ = 0;
369     SendOppDisconnected();
370     HILOGI("[OPP OBEX CLIENT] end");
371 }
372 
OnActionCompleted(ObexClient & client,const ObexHeader & resp)373 void OppObexClient::OppObexObserver::OnActionCompleted(ObexClient &client, const ObexHeader &resp)
374 {
375     HILOGI("[OPP OBEX CLIENT] start");
376     if (oppObexClient_ == nullptr) {
377         HILOGE("[OPP OBEX CLIENT] oppObexClient_ is null");
378         return;
379     }
380     oppObexClient_->OnActionCompleted(client, resp);
381 }
382 
OnActionCompleted(const ObexClient & client,const ObexHeader & resp)383 void OppObexClient::OnActionCompleted(const ObexClient &client, const ObexHeader &resp)
384 {
385     HILOGI("[OPP OBEX CLIENT] start");
386     std::string address = client.GetClientSession().GetRemoteAddr().GetAddress();
387     if (address_ != address) {
388         HILOGE("[OPP OBEX CLIENT] end, not current device");
389         return;
390     }
391 
392     uint8_t respCode = resp.GetFieldCode();
393     if ((respCode == static_cast<uint8_t>(ObexRspCode::CONTINUE)) ||
394         (respCode == static_cast<uint8_t>(ObexRspCode::SUCCESS))) {
395         if (status_ == OPP_OBEX_STATUS_WAITING_END) {
396             status_ = OPP_OBEX_STATUS_IDLE;
397             OppService::GetService()->OnTransferStateChange(
398                 address_, OPP_TRANSFER_STATUS_SUCCESS, 0);
399         } else if (status_ == OPP_OBEX_STATUS_WAITING_CONTINUE) {
400             startSendFile_ = true;
401             status_ = OPP_OBEX_STATUS_IDLE;
402             if (isSupportSrm_ && !resp.HasHeader(ObexHeader::SRM)) {
403                 isSupportSrm_ = false;
404             }
405             SendFileThread_->PostTask(std::bind(&OppObexClient::SendFileBody, this));
406         }
407     } else if (respCode == static_cast<uint8_t>(ObexRspCode::FORBIDDEN)) {
408         OnTransferStateChangeFaild(OPP_TRANSFER_FAILED_FORBIDDEN);
409     } else if (respCode == static_cast<uint8_t>(ObexRspCode::NOT_ACCEPTABLE)) {
410         OnTransferStateChangeFaild(OPP_TRANSFER_FAILED_NOT_ACCEPTABLE);
411     } else if (respCode == static_cast<uint8_t>(ObexRspCode::UNSUPPORTED_MEDIA_TYPE)) {
412         OnTransferStateChangeFaild(OPP_TRANSFER_FAILED_UNSUPPORTED_TYPE);
413     } else {
414         OnTransferStateChangeFaild(OPP_TRANSFER_FAILED_CANCELED);
415     }
416 
417     HILOGI("[OPP OBEX CLIENT] end");
418 }
419 
OnBusy(ObexClient & client,bool isBusy)420 void OppObexClient::OppObexObserver::OnBusy(ObexClient &client, bool isBusy)
421 {
422     if (oppObexClient_ == nullptr) {
423         HILOGE("[OPP OBEX CLIENT] oppObexClient_ is null");
424         return;
425     }
426     oppObexClient_->OnBusy(client, isBusy);
427 }
428 
OnBusy(ObexClient & client,bool isBusy)429 void OppObexClient::OnBusy(ObexClient &client, bool isBusy)
430 {
431     auto &device = client.GetClientSession().GetRemoteAddr();
432     HILOGI("[OPP OBEX CLIENT] start, device=%{public}s", GET_ENCRYPT_ADDR(device));
433     isBusy_ = isBusy;
434     if (!isBusy_) {
435         std::lock_guard<std::mutex> lock(mutexBusyChanged_);
436         cvWaitBusyChanged_.notify_all();
437     }
438     HILOGI("[OPP OBEX CLIENT] end, isBusy=%{public}d", isBusy ? 1 : 0);
439 }
440 
StringToU16string(const std::string & str) const441 std::u16string OppObexClient::StringToU16string(const std::string &str) const
442 {
443     return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes(str);
444 }
445 }  // namespace bluetooth
446 }  // namespace OHOS