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