1 /*
2 * Copyright (C) 2021-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 "obex_client.h"
17 #include <cstring>
18 #include <iostream>
19 #include "buffer.h"
20 #include "log.h"
21 #include "obex_socket_transport.h"
22 #include "obex_utils.h"
23 #include "transport/transport_l2cap.h"
24
25 namespace OHOS {
26 namespace bluetooth {
ObexClientTransportObserver(ObexClient & obexClient)27 ObexClient::ObexClientTransportObserver::ObexClientTransportObserver(ObexClient &obexClient) : obexClient_(obexClient)
28 {}
29
OnTransportConnected(ObexTransport & transport)30 void ObexClient::ObexClientTransportObserver::OnTransportConnected(ObexTransport &transport)
31 {
32 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
33 OBEX_LOG_INFO("ClientId: %{public}s", obexClient_.clientId_.c_str());
34 if (!transport.IsConnected()) {
35 obexClient_.clientObserver_.OnTransportFailed(obexClient_, -1);
36 return;
37 }
38 obexClient_.clientState_ = ObexClientState::TRANSPORT_CONNECTED;
39 if (obexClient_.isSupportReliableSession_ && obexClient_.reliableSessionReqHeader_ != nullptr) {
40 obexClient_.SendRequest(*obexClient_.reliableSessionReqHeader_);
41 } else if (obexClient_.connectReqHeader_ != nullptr) {
42 obexClient_.SendConnectRequest(*obexClient_.connectReqHeader_);
43 }
44 }
45
OnTransportDisconnected(ObexTransport & transport)46 void ObexClient::ObexClientTransportObserver::OnTransportDisconnected(ObexTransport &transport)
47 {
48 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
49 OBEX_LOG_INFO("ClientId: %{public}s", obexClient_.GetClientId().c_str());
50
51 obexClient_.clientState_ = ObexClientState::TRANSPORT_DISCONNECTED;
52 obexClient_.isObexConnected_ = false;
53 obexClient_.connectReqHeader_ = nullptr;
54 obexClient_.clientObserver_.OnDisconnected(obexClient_);
55 }
56
OnTransportDataBusy(ObexTransport & transport,uint8_t isBusy)57 void ObexClient::ObexClientTransportObserver::OnTransportDataBusy(ObexTransport &transport, uint8_t isBusy)
58 {
59 OBEX_LOG_INFO("Call %{public}s, isBusy %{public}d", __PRETTY_FUNCTION__, isBusy);
60 OBEX_LOG_INFO("ClientId: %{public}s", obexClient_.GetClientId().c_str());
61 obexClient_.HandleTransportDataBusy(isBusy);
62 }
63
OnTransportDataAvailable(ObexTransport & transport,ObexPacket & obexPacket)64 void ObexClient::ObexClientTransportObserver::OnTransportDataAvailable(
65 ObexTransport &transport, ObexPacket &obexPacket)
66 {
67 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
68 OBEX_LOG_INFO("ClientId: %{public}s", obexClient_.GetClientId().c_str());
69 obexClient_.isProcessing_ = false;
70 auto resp = GetObexHeaderFromPacket(obexPacket);
71 if (!resp) {
72 return;
73 }
74 obexClient_.clientSession_->SetLastRespCd(resp->GetFieldCode());
75 OBEX_LOG_DEBUG("lastOpeId : %02X", obexClient_.clientSession_->GetLastOpeId());
76 switch (obexClient_.clientSession_->GetLastOpeId()) {
77 case static_cast<uint8_t>(ObexOpeId::CONNECT):
78 HandleDataAvailableConnect(*resp);
79 break;
80 case static_cast<uint8_t>(ObexOpeId::DISCONNECT):
81 HandleDataAvailableDisconnect(*resp);
82 break;
83 case static_cast<uint8_t>(ObexOpeId::PUT):
84 case static_cast<uint8_t>(ObexOpeId::PUT_FINAL):
85 HandleDataAvailablePut(*resp);
86 break;
87 case static_cast<uint8_t>(ObexOpeId::GET):
88 case static_cast<uint8_t>(ObexOpeId::GET_FINAL):
89 HandleDataAvailableGet(*resp);
90 break;
91 case static_cast<uint8_t>(ObexOpeId::SETPATH):
92 HandleDataAvailableSetPath(*resp);
93 break;
94 case static_cast<uint8_t>(ObexOpeId::SESSION):
95 HandleDataAvailableSession(*resp);
96 break;
97 case static_cast<uint8_t>(ObexOpeId::ABORT):
98 HandleDataAvailableAbort(*resp);
99 break;
100 case static_cast<uint8_t>(ObexOpeId::ACTION):
101 HandleDataAvailableAction(*resp);
102 break;
103 default:
104 break;
105 }
106 }
107
HandleDataAvailableAction(const ObexHeader & resp)108 void ObexClient::ObexClientTransportObserver::HandleDataAvailableAction(const ObexHeader &resp)
109 {
110 obexClient_.clientObserver_.OnActionCompleted(obexClient_, resp);
111 }
112
HandleDataAvailableAbort(const ObexHeader & resp)113 void ObexClient::ObexClientTransportObserver::HandleDataAvailableAbort(const ObexHeader &resp)
114 {
115 if (resp.GetFieldCode() == static_cast<uint8_t>(ObexRspCode::CONTINUE)) {
116 // Skip unfinished get/put contniue packet
117 OBEX_LOG_DEBUG("abort request is sended, therefore skip unfinished get/put contniue packet");
118 return;
119 }
120 obexClient_.AbortDataAvailable(resp);
121 }
122
HandleDataAvailableSession(const ObexHeader & resp)123 void ObexClient::ObexClientTransportObserver::HandleDataAvailableSession(const ObexHeader &resp)
124 {
125 if (resp.GetFieldCode() == static_cast<uint8_t>(ObexRspCode::SUCCESS)) {
126 auto sessionParams = resp.GetItemSessionParams();
127 // sessionParams is not exists? do disconnect
128 if (sessionParams == nullptr) {
129 obexClient_.Disconnect();
130 return;
131 }
132 obexClient_.isReliableSessionCreated_ = true;
133 obexClient_.clientState_ = ObexClientState::RELIABLE_SESSION_CREATED;
134 // will support in the future: COPY Session param to ClientSession
135 obexClient_.SendConnectRequest(*obexClient_.connectReqHeader_);
136 } else {
137 obexClient_.clientObserver_.OnActionCompleted(obexClient_, resp);
138 }
139 }
140
HandleDataAvailableSetPath(const ObexHeader & resp)141 void ObexClient::ObexClientTransportObserver::HandleDataAvailableSetPath(const ObexHeader &resp)
142 {
143 obexClient_.SetPathDataAvailable(resp);
144 }
145
HandleDataAvailablePut(const ObexHeader & resp)146 void ObexClient::ObexClientTransportObserver::HandleDataAvailablePut(const ObexHeader &resp)
147 {
148 obexClient_.PutDataAvailable(resp);
149 }
150
HandleDataAvailableGet(const ObexHeader & resp)151 void ObexClient::ObexClientTransportObserver::HandleDataAvailableGet(const ObexHeader &resp)
152 {
153 obexClient_.GetDataAvailable(resp);
154 }
155
HandleDataAvailableDisconnect(const ObexHeader & resp)156 void ObexClient::ObexClientTransportObserver::HandleDataAvailableDisconnect(const ObexHeader &resp)
157 {
158 obexClient_.clientObserver_.OnActionCompleted(obexClient_, resp);
159 obexClient_.clientState_ = ObexClientState::OBEX_DISCONNECTED;
160 obexClient_.isObexConnected_ = false;
161 obexClient_.connectReqHeader_ = nullptr;
162 obexClient_.clientTransport_->Disconnect();
163 }
164
HandleDataAvailableConnect(const ObexHeader & resp)165 void ObexClient::ObexClientTransportObserver::HandleDataAvailableConnect(const ObexHeader &resp)
166 {
167 if (resp.GetFieldCode() == static_cast<uint8_t>(ObexRspCode::SUCCESS)) {
168 obexClient_.clientState_ = ObexClientState::OBEX_CONNECTED;
169 // set connected and mtu
170 obexClient_.isObexConnected_ = true;
171 uint16_t serverMaxPktLen = *resp.GetFieldMaxPacketLength();
172 if (serverMaxPktLen > OBEX_MINIMUM_MTU && serverMaxPktLen < obexClient_.clientSession_->GetMaxPacketLength()) {
173 obexClient_.clientSession_->SetMaxPacketLength(serverMaxPktLen);
174 OBEX_LOG_DEBUG("MTU Reset to:%{public}d", serverMaxPktLen);
175 }
176 // connect id
177 auto connectId = resp.GetItemConnectionId();
178 if (connectId != nullptr) {
179 obexClient_.clientSession_->SetConnectId(connectId->GetWord());
180 }
181 obexClient_.clientObserver_.OnConnected(obexClient_, resp);
182 } else {
183 obexClient_.clientObserver_.OnConnectFailed(obexClient_, resp);
184 }
185 }
186
OnTransportError(ObexTransport & transport,int errCd)187 void ObexClient::ObexClientTransportObserver::OnTransportError(ObexTransport &transport, int errCd)
188 {
189 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
190 OBEX_LOG_ERROR("ClientId: %{public}s, errCd: %{public}d", obexClient_.GetClientId().c_str(), errCd);
191 obexClient_.clientObserver_.OnTransportFailed(obexClient_, errCd);
192 }
193
GetObexHeaderFromPacket(ObexPacket & obexPacket)194 std::unique_ptr<bluetooth::ObexHeader> ObexClient::ObexClientTransportObserver::GetObexHeaderFromPacket(
195 ObexPacket &obexPacket)
196 {
197 uint8_t *packetBuf = obexPacket.GetBuffer();
198 size_t packetBufSize = obexPacket.GetSize();
199 if (packetBufSize < ObexHeader::MIN_PACKET_LENGTH) {
200 OBEX_LOG_ERROR("dataSize[%{public}zu] < min[%{public}d]", packetBufSize, ObexHeader::MIN_PACKET_LENGTH);
201 return nullptr;
202 }
203 uint16_t packetLength = ObexUtils::GetBufData16(&packetBuf[0], 1);
204 if (packetLength != packetBufSize) {
205 OBEX_LOG_ERROR("packetLength[%{public}hu] != packetBufSize[%{public}zu]", packetLength, packetBufSize);
206 return nullptr;
207 }
208 std::unique_ptr<bluetooth::ObexHeader> resp;
209
210 if (obexClient_.clientSession_->GetLastOpeId() == static_cast<uint8_t>(ObexOpeId::CONNECT)) {
211 resp = ObexHeader::ParseResponse(packetBuf, packetLength, true);
212 } else {
213 resp = ObexHeader::ParseResponse(packetBuf, packetLength, false);
214 }
215 if (resp == nullptr) {
216 OBEX_LOG_ERROR("ParseResponse failure");
217 return nullptr;
218 }
219 return resp;
220 }
221
ObexClient(const ObexClientConfig & config,ObexClientObserver & observer,utility::Dispatcher & dispatcher)222 ObexClient::ObexClient(const ObexClientConfig &config, ObexClientObserver &observer, utility::Dispatcher &dispatcher)
223 : clientObserver_(observer), dispatcher_(dispatcher)
224 {
225 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
226 isObexConnected_ = false;
227 transportObserver_ = std::make_unique<ObexClientTransportObserver>(*this);
228 ObexClientSocketTransport::Option option;
229 option.addr_ = config.addr_;
230 option.scn_ = config.scn_;
231 option.mtu_ = config.mtu_;
232 option.lpsm_ = config.lpsm_;
233
234 option.isGoepL2capPSM_ = config.isGoepL2capPSM_;
235 clientTransport_ = std::make_unique<ObexClientSocketTransport>(option, *transportObserver_, dispatcher);
236 isSupportSrm_ = config.isSupportSrm_; // srm mode
237 isSupportReliableSession_ = config.isSupportReliableSession_;
238 clientSession_ = std::make_unique<ObexClientSession>(RawAddress::ConvertToString(config.addr_.addr));
239 clientSession_->SetMaxPacketLength(config.mtu_);
240 clientSession_->SetServiceUUID(config.serviceUUID_);
241 clientSession_->FreeSendObject();
242 connectReqHeader_ = nullptr;
243 clientState_ = ObexClientState::INIT;
244 }
245
246 // send obex request
SendRequest(const ObexHeader & req)247 int ObexClient::SendRequest(const ObexHeader &req)
248 {
249 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
250 OBEX_LOG_INFO("ClientId: %{public}s", GetClientId().c_str());
251 if (req.GetFieldCode() == static_cast<uint8_t>(ObexOpeId::SESSION)) {
252 auto sessionParams = req.GetItemSessionParams();
253 if (sessionParams == nullptr) {
254 OBEX_LOG_ERROR("Request of session is invalid!");
255 return -1;
256 }
257 const TlvTriplet *tlv = sessionParams->GetTlvtriplet(ObexSessionParameters::SESSION_OPCODE);
258 if (tlv == nullptr) {
259 OBEX_LOG_ERROR("Request of session is invalid!");
260 return -1;
261 }
262 if (!CheckBeforeSession(tlv->GetVal()[0])) {
263 return -1;
264 }
265 } else {
266 if (!CheckBeforeRequest(req.GetFieldCode())) {
267 return -1;
268 }
269 }
270
271 if (req.GetFieldPacketLength() > clientSession_->GetMaxPacketLength()) {
272 OBEX_LOG_ERROR(
273 "Request packet length[%{public}d] > mtu[%{public}d].", req.GetFieldPacketLength(), clientSession_->GetMaxPacketLength());
274 return -1;
275 }
276 auto obexPacket = req.Build();
277 bool srmEnable = false;
278 if (req.HasHeader(ObexHeader::SRM)) {
279 srmEnable = req.GetItemSrm();
280 }
281 if ((req.GetFieldCode() == static_cast<uint8_t>(ObexOpeId::PUT)) &&
282 !srmEnable) {
283 isProcessing_ = false;
284 } else {
285 isProcessing_ = true;
286 }
287 bool ret = clientTransport_->Write(obexPacket->GetPacket());
288 if (!ret) {
289 OBEX_LOG_ERROR("SendRequest Fail!");
290 isProcessing_ = false;
291 return -1;
292 }
293 OBEX_LOG_DEBUG("Client Set lastOpeId: 0x%02X", req.GetFieldCode());
294
295 clientSession_->SetLastOpeId(req.GetFieldCode());
296 clientSession_->SetLastReqHeader(req);
297
298 return 0;
299 }
300
301 // send obex connect request
Connect()302 int ObexClient::Connect()
303 {
304 ObexConnectParams connectParams;
305 return Connect(connectParams);
306 }
307
308 // send obex connect request with params
Connect(ObexConnectParams & connectParams)309 int ObexClient::Connect(ObexConnectParams &connectParams)
310 {
311 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
312 OBEX_LOG_INFO("ClientId: %{public}s", GetClientId().c_str());
313 if (!CheckBeforeRequest(static_cast<uint8_t>(ObexOpeId::CONNECT))) {
314 return -1;
315 }
316 std::unique_ptr<ObexHeader> header = ObexHeader::CreateRequest(ObexOpeId::CONNECT);
317 const BtUuid &serviceUUID = clientSession_->GetServiceUUID();
318 if (serviceUUID.uuid128[0] != 0x00) {
319 header->AppendItemTarget(&serviceUUID.uuid128[0], sizeof(serviceUUID.uuid128));
320 }
321 if (connectParams.appParams_ != nullptr) {
322 header->AppendItemAppParams(*connectParams.appParams_);
323 }
324 if (connectParams.authChallenges_ != nullptr) {
325 header->AppendItemAuthChallenges(*connectParams.authChallenges_);
326 }
327 if (connectParams.authResponses_ != nullptr) {
328 header->AppendItemAuthResponse(*connectParams.authResponses_);
329 }
330 if (connectParams.count != nullptr) {
331 header->AppendItemCount(*connectParams.count);
332 }
333 // create transport before obex connect
334 if (!clientTransport_->IsConnected()) {
335 connectReqHeader_ = std::move(header);
336 return clientTransport_->Connect();
337 }
338 return SendConnectRequest(*header);
339 }
340
341 // send obex disconnect request
Disconnect(bool withObexReq)342 int ObexClient::Disconnect(bool withObexReq)
343 {
344 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
345 OBEX_LOG_INFO("ClientId: %{public}s", GetClientId().c_str());
346 if (withObexReq) {
347 if (!CheckBeforeRequest(static_cast<uint8_t>(ObexOpeId::DISCONNECT))) {
348 return -1;
349 }
350 auto req = ObexHeader::CreateRequest(ObexOpeId::DISCONNECT);
351 if (isReliableSessionCreated_) {
352 req->AppendItemSessionSeqNum(clientSession_->GetReliableSession()->sessionSequenceNumber_++);
353 }
354 uint32_t connectId = clientSession_->GetConnectId();
355 if (connectId != 0x00) {
356 req->AppendItemConnectionId(connectId);
357 }
358 return SendRequest(*req);
359 }
360 return clientTransport_->Disconnect();
361 }
362
363 // send obex abort request
Abort()364 int ObexClient::Abort()
365 {
366 dispatcher_.PostTask(std::bind(&ObexClient::ProcessAbort, this));
367 return 0;
368 }
369
ProcessAbort()370 int ObexClient::ProcessAbort()
371 {
372 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
373 OBEX_LOG_INFO("ClientId: %{public}s", GetClientId().c_str());
374 if (isWaitingSendAbort_ || isAbortSended_) {
375 OBEX_LOG_ERROR("Abort is processing!");
376 return -1;
377 }
378 isAbortSended_ = false;
379 if (isProcessing_) {
380 isAbortSended_ = false;
381 switch (clientSession_->GetLastOpeId()) {
382 case static_cast<uint8_t>(ObexOpeId::PUT):
383 case static_cast<uint8_t>(ObexOpeId::PUT_FINAL):
384 case static_cast<uint8_t>(ObexOpeId::GET):
385 case static_cast<uint8_t>(ObexOpeId::GET_FINAL):
386 isWaitingSendAbort_ = true;
387 break;
388 default:
389 isWaitingSendAbort_ = false;
390 break;
391 }
392 return 0;
393 }
394 return SendAbortRequest();
395 }
396
SendAbortRequest()397 int ObexClient::SendAbortRequest()
398 {
399 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
400 OBEX_LOG_INFO("ClientId: %{public}s", GetClientId().c_str());
401 if (!CheckBeforeRequest(static_cast<uint8_t>(ObexOpeId::ABORT))) {
402 return -1;
403 }
404 auto req = ObexHeader::CreateRequest(ObexOpeId::ABORT);
405 uint32_t connectId = clientSession_->GetConnectId();
406 if (connectId != 0x00) {
407 req->AppendItemConnectionId(connectId);
408 }
409 isWaitingSendAbort_ = false;
410 isAbortSended_ = true;
411 return SendRequest(*req);
412 }
413
414 // send obex put request
Put(const ObexHeader & req)415 int ObexClient::Put(const ObexHeader &req)
416 {
417 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
418 OBEX_LOG_INFO("ClientId: %{public}s", GetClientId().c_str());
419 if (!CheckBeforeRequest(req.GetFieldCode())) {
420 return -1;
421 }
422 if (req.GetFieldCode() != static_cast<uint8_t>(ObexOpeId::PUT) &&
423 req.GetFieldCode() != static_cast<uint8_t>(ObexOpeId::PUT_FINAL)) {
424 OBEX_LOG_ERROR("Opcode is wrong.");
425 return -1;
426 }
427 return SendRequest(req);
428 }
429
430 // send obex get request
Get(const ObexHeader & req)431 int ObexClient::Get(const ObexHeader &req)
432 {
433 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
434 OBEX_LOG_INFO("ClientId: %{public}s", GetClientId().c_str());
435 if (!CheckBeforeRequest(req.GetFieldCode())) {
436 return -1;
437 }
438 if (req.GetFieldCode() != static_cast<uint8_t>(ObexOpeId::GET) &&
439 req.GetFieldCode() != static_cast<uint8_t>(ObexOpeId::GET_FINAL)) {
440 OBEX_LOG_ERROR("Opcode is wrong.");
441 return -1;
442 }
443 return SendRequest(req);
444 }
445
446 // send obex set_path request
SetPath(uint8_t flag,const std::u16string & path)447 int ObexClient::SetPath(uint8_t flag, const std::u16string &path)
448 {
449 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
450 OBEX_LOG_INFO("ClientId: %{public}s", GetClientId().c_str());
451 if (!CheckBeforeRequest(static_cast<uint8_t>(ObexOpeId::SETPATH))) {
452 return -1;
453 }
454 if (path.find(u"/") != std::u16string::npos) {
455 OBEX_LOG_ERROR("The path shall not include any path information!");
456 return -1;
457 }
458 auto req = ObexHeader::CreateRequest(ObexOpeId::SETPATH);
459 req->SetFieldFlags(flag);
460 uint32_t connectId = clientSession_->GetConnectId();
461 if (connectId != 0x00) {
462 req->AppendItemConnectionId(connectId);
463 }
464 if (path.length() > 0) {
465 req->AppendItemName(path);
466 }
467 return SendRequest(*req);
468 }
469
470 // send obex action request
Copy(const std::u16string & srcName,const std::u16string & destName)471 int ObexClient::Copy(const std::u16string &srcName, const std::u16string &destName)
472 {
473 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
474 OBEX_LOG_INFO("ClientId: %{public}s", GetClientId().c_str());
475 // will support in the future
476 return 0;
477 }
478
Move(const std::u16string & srcName,const std::u16string & destName)479 int ObexClient::Move(const std::u16string &srcName, const std::u16string &destName)
480 {
481 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
482 OBEX_LOG_INFO("ClientId: %{public}s", GetClientId().c_str());
483 // will support in the future
484 return 0;
485 }
486
SetPermissions(const std::u16string & name,const uint32_t permissions)487 int ObexClient::SetPermissions(const std::u16string &name, const uint32_t permissions)
488 {
489 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
490 OBEX_LOG_INFO("ClientId: %{public}s", GetClientId().c_str());
491 // will support in the future
492 return 0;
493 }
494
495 // send obex session request
496 // This command must include a Session-Parameters header containing the Session Opcode, Device Address and Nonce
497 // fields. Optionally, a Timeout field can be included.
CreateSession()498 int ObexClient::CreateSession()
499 {
500 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
501 // will support in the future
502 return CreateSession(OBEX_SESSION_MAX_TIMEOUT_SEC);
503 }
504
CreateSession(uint32_t timeoutSec)505 int ObexClient::CreateSession(uint32_t timeoutSec)
506 {
507 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
508 return 0;
509 }
510
511 // This command must include a Session-Parameters header containing the Session Opcode field.
512 // Optionally, a Timeout field can be included.
SuspendSession()513 int ObexClient::SuspendSession()
514 {
515 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
516 return 0;
517 }
518
519 // This command must include a Session-Parameters header containing the Session Opcode, Device Address, Nonce,
520 // and Session ID and fields. Optionally, a Timeout field can be included.
ResumeSession()521 int ObexClient::ResumeSession()
522 {
523 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
524 return 0;
525 }
526
527 // This command must include a Session-Parameters header containing the Session Opcode and Session ID fields.
CloseSession()528 int ObexClient::CloseSession()
529 {
530 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
531 return 0;
532 }
533
534 // This command must include a Session-Parameters header containing the Session Opcode field.
535 // Optionally, a Timeout field can be included.
SetSessionTimeout(uint32_t timeoutSec)536 int ObexClient::SetSessionTimeout(uint32_t timeoutSec)
537 {
538 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
539 return 0;
540 }
541
CheckBeforeSession(uint8_t sessionOpcode)542 bool ObexClient::CheckBeforeSession(uint8_t sessionOpcode)
543 {
544 return true;
545 }
546
CheckBeforeRequest(uint8_t opeId) const547 bool ObexClient::CheckBeforeRequest(uint8_t opeId) const
548 {
549 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
550 if (isProcessing_) {
551 OBEX_LOG_ERROR("Another operation is being processed, please try again later.");
552 return false;
553 }
554 bool checkConnect = true;
555 bool needConnected = true;
556 switch (opeId) {
557 case static_cast<uint8_t>(ObexOpeId::CONNECT):
558 needConnected = false;
559 break;
560 case static_cast<uint8_t>(ObexOpeId::SESSION):
561 checkConnect = false; // Session's connect check is in CheckBeforeSession
562 break;
563 case static_cast<uint8_t>(ObexOpeId::DISCONNECT):
564 if (!isObexConnected_) {
565 OBEX_LOG_ERROR("Already Disconnected from the server.");
566 return false;
567 }
568 break;
569 default:
570 break;
571 }
572 if (checkConnect) {
573 if (needConnected && !isObexConnected_) {
574 OBEX_LOG_ERROR(
575 "Please connect first. Before obex connected, only SESSION(Create) and CONNECT Operation can "
576 "be called.");
577 return false;
578 }
579 if (!needConnected && isObexConnected_) {
580 OBEX_LOG_ERROR("Already connected to server.");
581 return false;
582 }
583 }
584 return true;
585 }
586
PutDataAvailable(const ObexHeader & resp)587 void ObexClient::PutDataAvailable(const ObexHeader &resp)
588 {
589 if (isWaitingSendAbort_) {
590 isProcessing_ = false;
591 SendAbortRequest();
592 return;
593 }
594 SetBusy(false);
595 clientObserver_.OnActionCompleted(*this, resp);
596 }
597
GetDataAvailable(const ObexHeader & resp)598 void ObexClient::GetDataAvailable(const ObexHeader &resp)
599 {
600 if (isWaitingSendAbort_) {
601 isProcessing_ = false;
602 SendAbortRequest();
603 return;
604 }
605 SetBusy(false);
606 clientObserver_.OnActionCompleted(*this, resp);
607 }
608
SetPathDataAvailable(const ObexHeader & resp)609 void ObexClient::SetPathDataAvailable(const ObexHeader &resp)
610 {
611 clientObserver_.OnActionCompleted(*this, resp);
612 }
613
AbortDataAvailable(const ObexHeader & resp)614 void ObexClient::AbortDataAvailable(const ObexHeader &resp)
615 {
616 isWaitingSendAbort_ = false;
617 isAbortSended_ = false;
618 SetBusy(false);
619 clientObserver_.OnActionCompleted(*this, resp);
620 }
621
HandleTransportDataBusy(uint8_t isBusy)622 void ObexClient::HandleTransportDataBusy(uint8_t isBusy)
623 {
624 OBEX_LOG_INFO("Call %{public}s, isBusy %{public}d", __PRETTY_FUNCTION__, isBusy);
625 clientObserver_.OnBusy(*this, isBusy);
626 }
627
SendConnectRequest(ObexHeader & header)628 int ObexClient::SendConnectRequest(ObexHeader &header)
629 {
630 int minPacketSize = std::min(clientTransport_->GetMaxSendPacketSize(),
631 clientTransport_->GetMaxReceivePacketSize());
632 minPacketSize = std::min(minPacketSize, (int)clientSession_->GetMaxPacketLength());
633 if (minPacketSize > OBEX_MAXIMUM_MTU) {
634 minPacketSize = OBEX_MAXIMUM_MTU;
635 } else if (minPacketSize < OBEX_MINIMUM_MTU) {
636 minPacketSize = OBEX_MINIMUM_MTU;
637 }
638 header.SetFieldMaxPacketLength(minPacketSize);
639 clientSession_->SetMaxPacketLength(minPacketSize);
640 OBEX_LOG_DEBUG("SendConnect with mtu:%{public}d", minPacketSize);
641 return SendRequest(header);
642 }
643
GetClientSession() const644 ObexClientSession &ObexClient::GetClientSession() const
645 {
646 return *clientSession_;
647 }
648
GetClientId()649 const std::string &ObexClient::GetClientId()
650 {
651 if (clientId_.empty()) {
652 clientId_ = (clientTransport_ == nullptr) ? "" : clientTransport_->GetTransportKey();
653 }
654 return clientId_;
655 }
656
RegisterL2capLPsm(uint16_t lpsm)657 int ObexClient::RegisterL2capLPsm(uint16_t lpsm)
658 {
659 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
660 OBEX_LOG_INFO("RegisterL2capLPsm: 0x%04X", lpsm);
661 return L2capTransport::RegisterClientPsm(lpsm);
662 }
663
DeregisterL2capLPsm(uint16_t lpsm)664 void ObexClient::DeregisterL2capLPsm(uint16_t lpsm)
665 {
666 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
667 OBEX_LOG_INFO("DeregisterL2capLPsm: 0x%04X", lpsm);
668 L2capTransport::DeregisterClientPsm(lpsm);
669 }
670
SetBusy(bool isBusy)671 void ObexClient::SetBusy(bool isBusy)
672 {
673 if (clientSession_->IsBusy() != isBusy) {
674 clientSession_->SetBusy(isBusy);
675 OBEX_LOG_INFO("[%{public}s] ObexBusy=%{public}d", GetClientId().c_str(), isBusy);
676 clientObserver_.OnBusy(*this, isBusy);
677 }
678 }
679
OnBusy(ObexClient & client,bool isBusy)680 void ObexClientObserver::OnBusy(ObexClient &client, bool isBusy)
681 {
682 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
683 }
684 } // namespace bluetooth
685 } // namespace OHOS
686