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].",
274 req.GetFieldPacketLength(), clientSession_->GetMaxPacketLength());
275 return -1;
276 }
277 auto obexPacket = req.Build();
278 bool srmEnable = false;
279 if (req.HasHeader(ObexHeader::SRM)) {
280 srmEnable = req.GetItemSrm();
281 }
282 if ((req.GetFieldCode() == static_cast<uint8_t>(ObexOpeId::PUT)) &&
283 !srmEnable) {
284 isProcessing_ = false;
285 } else {
286 isProcessing_ = true;
287 }
288 bool ret = clientTransport_->Write(obexPacket->GetPacket());
289 if (!ret) {
290 OBEX_LOG_ERROR("SendRequest Fail!");
291 isProcessing_ = false;
292 return -1;
293 }
294 OBEX_LOG_DEBUG("Client Set lastOpeId: 0x%02X", req.GetFieldCode());
295
296 clientSession_->SetLastOpeId(req.GetFieldCode());
297 clientSession_->SetLastReqHeader(req);
298
299 return 0;
300 }
301
302 // send obex connect request
Connect()303 int ObexClient::Connect()
304 {
305 ObexConnectParams connectParams;
306 return Connect(connectParams);
307 }
308
309 // send obex connect request with params
Connect(ObexConnectParams & connectParams)310 int ObexClient::Connect(ObexConnectParams &connectParams)
311 {
312 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
313 OBEX_LOG_INFO("ClientId: %{public}s", GetClientId().c_str());
314 if (!CheckBeforeRequest(static_cast<uint8_t>(ObexOpeId::CONNECT))) {
315 return -1;
316 }
317 std::unique_ptr<ObexHeader> header = ObexHeader::CreateRequest(ObexOpeId::CONNECT);
318 const BtUuid &serviceUUID = clientSession_->GetServiceUUID();
319 if (serviceUUID.uuid128[0] != 0x00) {
320 header->AppendItemTarget(&serviceUUID.uuid128[0], sizeof(serviceUUID.uuid128));
321 }
322 if (connectParams.appParams_ != nullptr) {
323 header->AppendItemAppParams(*connectParams.appParams_);
324 }
325 if (connectParams.authChallenges_ != nullptr) {
326 header->AppendItemAuthChallenges(*connectParams.authChallenges_);
327 }
328 if (connectParams.authResponses_ != nullptr) {
329 header->AppendItemAuthResponse(*connectParams.authResponses_);
330 }
331 if (connectParams.count != nullptr) {
332 header->AppendItemCount(*connectParams.count);
333 }
334 // create transport before obex connect
335 if (!clientTransport_->IsConnected()) {
336 connectReqHeader_ = std::move(header);
337 return clientTransport_->Connect();
338 }
339 return SendConnectRequest(*header);
340 }
341
342 // send obex disconnect request
Disconnect(bool withObexReq)343 int ObexClient::Disconnect(bool withObexReq)
344 {
345 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
346 OBEX_LOG_INFO("ClientId: %{public}s", GetClientId().c_str());
347 if (withObexReq) {
348 if (!CheckBeforeRequest(static_cast<uint8_t>(ObexOpeId::DISCONNECT))) {
349 return -1;
350 }
351 auto req = ObexHeader::CreateRequest(ObexOpeId::DISCONNECT);
352 if (isReliableSessionCreated_) {
353 req->AppendItemSessionSeqNum(clientSession_->GetReliableSession()->sessionSequenceNumber_++);
354 }
355 uint32_t connectId = clientSession_->GetConnectId();
356 if (connectId != 0x00) {
357 req->AppendItemConnectionId(connectId);
358 }
359 return SendRequest(*req);
360 }
361 return clientTransport_->Disconnect();
362 }
363
364 // send obex abort request
Abort()365 int ObexClient::Abort()
366 {
367 dispatcher_.PostTask(std::bind(&ObexClient::ProcessAbort, this));
368 return 0;
369 }
370
ProcessAbort()371 int ObexClient::ProcessAbort()
372 {
373 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
374 OBEX_LOG_INFO("ClientId: %{public}s", GetClientId().c_str());
375 if (isWaitingSendAbort_ || isAbortSended_) {
376 OBEX_LOG_ERROR("Abort is processing!");
377 return -1;
378 }
379 isAbortSended_ = false;
380 if (isProcessing_) {
381 isAbortSended_ = false;
382 switch (clientSession_->GetLastOpeId()) {
383 case static_cast<uint8_t>(ObexOpeId::PUT):
384 case static_cast<uint8_t>(ObexOpeId::PUT_FINAL):
385 case static_cast<uint8_t>(ObexOpeId::GET):
386 case static_cast<uint8_t>(ObexOpeId::GET_FINAL):
387 isWaitingSendAbort_ = true;
388 break;
389 default:
390 isWaitingSendAbort_ = false;
391 break;
392 }
393 return 0;
394 }
395 return SendAbortRequest();
396 }
397
SendAbortRequest()398 int ObexClient::SendAbortRequest()
399 {
400 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
401 OBEX_LOG_INFO("ClientId: %{public}s", GetClientId().c_str());
402 if (!CheckBeforeRequest(static_cast<uint8_t>(ObexOpeId::ABORT))) {
403 return -1;
404 }
405 auto req = ObexHeader::CreateRequest(ObexOpeId::ABORT);
406 uint32_t connectId = clientSession_->GetConnectId();
407 if (connectId != 0x00) {
408 req->AppendItemConnectionId(connectId);
409 }
410 isWaitingSendAbort_ = false;
411 isAbortSended_ = true;
412 return SendRequest(*req);
413 }
414
415 // send obex put request
Put(const ObexHeader & req)416 int ObexClient::Put(const ObexHeader &req)
417 {
418 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
419 OBEX_LOG_INFO("ClientId: %{public}s", GetClientId().c_str());
420 if (!CheckBeforeRequest(req.GetFieldCode())) {
421 return -1;
422 }
423 if (req.GetFieldCode() != static_cast<uint8_t>(ObexOpeId::PUT) &&
424 req.GetFieldCode() != static_cast<uint8_t>(ObexOpeId::PUT_FINAL)) {
425 OBEX_LOG_ERROR("Opcode is wrong.");
426 return -1;
427 }
428 return SendRequest(req);
429 }
430
431 // send obex get request
Get(const ObexHeader & req)432 int ObexClient::Get(const ObexHeader &req)
433 {
434 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
435 OBEX_LOG_INFO("ClientId: %{public}s", GetClientId().c_str());
436 if (!CheckBeforeRequest(req.GetFieldCode())) {
437 return -1;
438 }
439 if (req.GetFieldCode() != static_cast<uint8_t>(ObexOpeId::GET) &&
440 req.GetFieldCode() != static_cast<uint8_t>(ObexOpeId::GET_FINAL)) {
441 OBEX_LOG_ERROR("Opcode is wrong.");
442 return -1;
443 }
444 return SendRequest(req);
445 }
446
447 // send obex set_path request
SetPath(uint8_t flag,const std::u16string & path)448 int ObexClient::SetPath(uint8_t flag, const std::u16string &path)
449 {
450 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
451 OBEX_LOG_INFO("ClientId: %{public}s", GetClientId().c_str());
452 if (!CheckBeforeRequest(static_cast<uint8_t>(ObexOpeId::SETPATH))) {
453 return -1;
454 }
455 if (path.find(u"/") != std::u16string::npos) {
456 OBEX_LOG_ERROR("The path shall not include any path information!");
457 return -1;
458 }
459 auto req = ObexHeader::CreateRequest(ObexOpeId::SETPATH);
460 req->SetFieldFlags(flag);
461 uint32_t connectId = clientSession_->GetConnectId();
462 if (connectId != 0x00) {
463 req->AppendItemConnectionId(connectId);
464 }
465 if (path.length() > 0) {
466 req->AppendItemName(path);
467 }
468 return SendRequest(*req);
469 }
470
471 // send obex action request
Copy(const std::u16string & srcName,const std::u16string & destName)472 int ObexClient::Copy(const std::u16string &srcName, const std::u16string &destName)
473 {
474 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
475 OBEX_LOG_INFO("ClientId: %{public}s", GetClientId().c_str());
476 // will support in the future
477 return 0;
478 }
479
Move(const std::u16string & srcName,const std::u16string & destName)480 int ObexClient::Move(const std::u16string &srcName, const std::u16string &destName)
481 {
482 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
483 OBEX_LOG_INFO("ClientId: %{public}s", GetClientId().c_str());
484 // will support in the future
485 return 0;
486 }
487
SetPermissions(const std::u16string & name,const uint32_t permissions)488 int ObexClient::SetPermissions(const std::u16string &name, const uint32_t permissions)
489 {
490 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
491 OBEX_LOG_INFO("ClientId: %{public}s", GetClientId().c_str());
492 // will support in the future
493 return 0;
494 }
495
496 // send obex session request
497 // This command must include a Session-Parameters header containing the Session Opcode, Device Address and Nonce
498 // fields. Optionally, a Timeout field can be included.
CreateSession()499 int ObexClient::CreateSession()
500 {
501 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
502 // will support in the future
503 return CreateSession(OBEX_SESSION_MAX_TIMEOUT_SEC);
504 }
505
CreateSession(uint32_t timeoutSec)506 int ObexClient::CreateSession(uint32_t timeoutSec)
507 {
508 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
509 return 0;
510 }
511
512 // This command must include a Session-Parameters header containing the Session Opcode field.
513 // Optionally, a Timeout field can be included.
SuspendSession()514 int ObexClient::SuspendSession()
515 {
516 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
517 return 0;
518 }
519
520 // This command must include a Session-Parameters header containing the Session Opcode, Device Address, Nonce,
521 // and Session ID and fields. Optionally, a Timeout field can be included.
ResumeSession()522 int ObexClient::ResumeSession()
523 {
524 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
525 return 0;
526 }
527
528 // This command must include a Session-Parameters header containing the Session Opcode and Session ID fields.
CloseSession()529 int ObexClient::CloseSession()
530 {
531 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
532 return 0;
533 }
534
535 // This command must include a Session-Parameters header containing the Session Opcode field.
536 // Optionally, a Timeout field can be included.
SetSessionTimeout(uint32_t timeoutSec)537 int ObexClient::SetSessionTimeout(uint32_t timeoutSec)
538 {
539 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
540 return 0;
541 }
542
CheckBeforeSession(uint8_t sessionOpcode)543 bool ObexClient::CheckBeforeSession(uint8_t sessionOpcode)
544 {
545 return true;
546 }
547
CheckBeforeRequest(uint8_t opeId) const548 bool ObexClient::CheckBeforeRequest(uint8_t opeId) const
549 {
550 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
551 if (isProcessing_) {
552 OBEX_LOG_ERROR("Another operation is being processed, please try again later.");
553 return false;
554 }
555 bool checkConnect = true;
556 bool needConnected = true;
557 switch (opeId) {
558 case static_cast<uint8_t>(ObexOpeId::CONNECT):
559 needConnected = false;
560 break;
561 case static_cast<uint8_t>(ObexOpeId::SESSION):
562 checkConnect = false; // Session's connect check is in CheckBeforeSession
563 break;
564 case static_cast<uint8_t>(ObexOpeId::DISCONNECT):
565 if (!isObexConnected_) {
566 OBEX_LOG_ERROR("Already Disconnected from the server.");
567 return false;
568 }
569 break;
570 default:
571 break;
572 }
573 if (checkConnect) {
574 if (needConnected && !isObexConnected_) {
575 OBEX_LOG_ERROR(
576 "Please connect first. Before obex connected, only SESSION(Create) and CONNECT Operation can "
577 "be called.");
578 return false;
579 }
580 if (!needConnected && isObexConnected_) {
581 OBEX_LOG_ERROR("Already connected to server.");
582 return false;
583 }
584 }
585 return true;
586 }
587
PutDataAvailable(const ObexHeader & resp)588 void ObexClient::PutDataAvailable(const ObexHeader &resp)
589 {
590 if (isWaitingSendAbort_) {
591 isProcessing_ = false;
592 SendAbortRequest();
593 return;
594 }
595 SetBusy(false);
596 clientObserver_.OnActionCompleted(*this, resp);
597 }
598
GetDataAvailable(const ObexHeader & resp)599 void ObexClient::GetDataAvailable(const ObexHeader &resp)
600 {
601 if (isWaitingSendAbort_) {
602 isProcessing_ = false;
603 SendAbortRequest();
604 return;
605 }
606 SetBusy(false);
607 clientObserver_.OnActionCompleted(*this, resp);
608 }
609
SetPathDataAvailable(const ObexHeader & resp)610 void ObexClient::SetPathDataAvailable(const ObexHeader &resp)
611 {
612 clientObserver_.OnActionCompleted(*this, resp);
613 }
614
AbortDataAvailable(const ObexHeader & resp)615 void ObexClient::AbortDataAvailable(const ObexHeader &resp)
616 {
617 isWaitingSendAbort_ = false;
618 isAbortSended_ = false;
619 SetBusy(false);
620 clientObserver_.OnActionCompleted(*this, resp);
621 }
622
HandleTransportDataBusy(uint8_t isBusy)623 void ObexClient::HandleTransportDataBusy(uint8_t isBusy)
624 {
625 OBEX_LOG_INFO("Call %{public}s, isBusy %{public}d", __PRETTY_FUNCTION__, isBusy);
626 clientObserver_.OnBusy(*this, isBusy);
627 }
628
SendConnectRequest(ObexHeader & header)629 int ObexClient::SendConnectRequest(ObexHeader &header)
630 {
631 int minPacketSize = std::min(clientTransport_->GetMaxSendPacketSize(),
632 clientTransport_->GetMaxReceivePacketSize());
633 minPacketSize = std::min(minPacketSize, (int)clientSession_->GetMaxPacketLength());
634 if (minPacketSize > OBEX_MAXIMUM_MTU) {
635 minPacketSize = OBEX_MAXIMUM_MTU;
636 } else if (minPacketSize < OBEX_MINIMUM_MTU) {
637 minPacketSize = OBEX_MINIMUM_MTU;
638 }
639 header.SetFieldMaxPacketLength(minPacketSize);
640 clientSession_->SetMaxPacketLength(minPacketSize);
641 OBEX_LOG_DEBUG("SendConnect with mtu:%{public}d", minPacketSize);
642 return SendRequest(header);
643 }
644
GetClientSession() const645 ObexClientSession &ObexClient::GetClientSession() const
646 {
647 return *clientSession_;
648 }
649
GetClientId()650 const std::string &ObexClient::GetClientId()
651 {
652 if (clientId_.empty()) {
653 clientId_ = (clientTransport_ == nullptr) ? "" : clientTransport_->GetTransportKey();
654 }
655 return clientId_;
656 }
657
RegisterL2capLPsm(uint16_t lpsm)658 int ObexClient::RegisterL2capLPsm(uint16_t lpsm)
659 {
660 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
661 OBEX_LOG_INFO("RegisterL2capLPsm: 0x%04X", lpsm);
662 return L2capTransport::RegisterClientPsm(lpsm);
663 }
664
DeregisterL2capLPsm(uint16_t lpsm)665 void ObexClient::DeregisterL2capLPsm(uint16_t lpsm)
666 {
667 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
668 OBEX_LOG_INFO("DeregisterL2capLPsm: 0x%04X", lpsm);
669 L2capTransport::DeregisterClientPsm(lpsm);
670 }
671
SetBusy(bool isBusy)672 void ObexClient::SetBusy(bool isBusy)
673 {
674 if (clientSession_->IsBusy() != isBusy) {
675 clientSession_->SetBusy(isBusy);
676 OBEX_LOG_INFO("[%{public}s] ObexBusy=%{public}d", GetClientId().c_str(), isBusy);
677 clientObserver_.OnBusy(*this, isBusy);
678 }
679 }
680
OnBusy(ObexClient & client,bool isBusy)681 void ObexClientObserver::OnBusy(ObexClient &client, bool isBusy)
682 {
683 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
684 }
685 } // namespace bluetooth
686 } // namespace OHOS
687