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