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 "pbap_pse_state_machine.h"
17 #include <cstring>
18 #include <numeric>
19 #include "../obex/obex_utils.h"
20 #include "interface_profile_pbap_pse.h"
21 #include "log.h"
22 #include "log_util.h"
23 #include "pbap_pse_app_params.h"
24 #include "pbap_pse_def.h"
25 #include "pbap_pse_obex_server.h"
26 #include "pbap_pse_service.h"
27 #include "pbap_pse_vcard_manager.h"
28 #include "power_manager.h"
29 #include "raw_address.h"
30 #include "securec.h"
31
32 namespace OHOS {
33 namespace bluetooth {
PseWaitingForConnect(const std::string & name,PbapPseStateMachine & stm)34 PseWaitingForConnect::PseWaitingForConnect(const std::string &name, PbapPseStateMachine &stm)
35 : State(name, stm), stm_(stm)
36 {}
37
Entry()38 void PseWaitingForConnect::Entry()
39 {
40 PBAP_PSE_LOG_INFO("%{public}s", __PRETTY_FUNCTION__);
41 }
42
Exit()43 void PseWaitingForConnect::Exit()
44 {
45 PBAP_PSE_LOG_INFO("%{public}s", __PRETTY_FUNCTION__);
46 }
47
Dispatch(const utility::Message & msg)48 bool PseWaitingForConnect::Dispatch(const utility::Message &msg)
49 {
50 PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
51 bool ret = true;
52 switch (msg.what_) {
53 case PSE_DEVICE_CONNECT_INCOMING:
54 Transition(PbapPseStateMachine::PSE_CONNECTING_STATE);
55 stm_.ProcessMessage(msg);
56 break;
57 default:
58 PBAP_PSE_LOG_ERROR("NOT SUPPORT MSGID %{public}d", msg.what_);
59 ret = false;
60 break;
61 }
62 PBAP_PSE_LOG_INFO("%{public}s end, ret = %{public}d", __PRETTY_FUNCTION__, ret);
63 return ret;
64 }
65
PseConnecting(const std::string & name,PbapPseStateMachine & stm,BaseObserverList<IPbapPseObserver> & observerMgrList,std::function<uint32_t ()> & getNextConnectIdFun)66 PseConnecting::PseConnecting(const std::string &name, PbapPseStateMachine &stm,
67 BaseObserverList<IPbapPseObserver> &observerMgrList, std::function<uint32_t()> &getNextConnectIdFun)
68 : State(name, stm), stm_(stm), observerMgrList_(observerMgrList), getNextConnectIdFun_(getNextConnectIdFun)
69 {}
70
Entry()71 void PseConnecting::Entry()
72 {
73 PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
74 auto &device = stm_.GetDevice();
75 observerMgrList_.ForEach([device](IPbapPseObserver &observer) {
76 observer.OnServiceConnectionStateChanged(device, static_cast<int>(BTConnectState::CONNECTING));
77 });
78 PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
79 }
80
Exit()81 void PseConnecting::Exit()
82 {
83 PBAP_PSE_LOG_INFO("%{public}s", __PRETTY_FUNCTION__);
84 stm_.StopTimer();
85 }
86
Dispatch(const utility::Message & msg)87 bool PseConnecting::Dispatch(const utility::Message &msg)
88 {
89 PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
90 bool ret = true;
91 switch (msg.what_) {
92 case PSE_DEVICE_CONNECT_INCOMING:
93 // No need to delete
94 incomeConnect_ = static_cast<ObexIncomingConnect *>(msg.arg2_);
95 break;
96 case PSE_INCOMING_ACCEPT:
97 AcceptConnection();
98 break;
99 case PSE_INCOMING_REJECT:
100 RejectConnection();
101 break;
102 case PSE_WAITING_CONNECTED_TO_DISCONNECT:
103 waitingDisconnect_ = true;
104 break;
105 case PSE_REQ_OBEX_CONNECT:
106 // No need to delete
107 CheckConnectReq(*static_cast<PbapPseObexMessage *>(msg.arg2_));
108 break;
109 case PSE_PASSWORD_INPUT:
110 // No need to delete
111 PasswordInput(*static_cast<PbapPsePasswordInputMsg *>(msg.arg2_));
112 break;
113 case PSE_DEVICE_DISCONNECTED: // OnIncomingDisconnected
114 Transition(PbapPseStateMachine::PSE_DISCONNECTING_STATE);
115 Transition(PbapPseStateMachine::PSE_DISCONNECTED_STATE);
116 break;
117 default:
118 PBAP_PSE_LOG_ERROR("NOT SUPPORT MSGID %{public}d", msg.what_);
119 ret = false;
120 break;
121 }
122 PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
123 return ret;
124 }
125
AcceptConnection()126 void PseConnecting::AcceptConnection()
127 {
128 if (incomeConnect_ != nullptr) {
129 PBAP_PSE_LOG_INFO("%{public}s AcceptConnection", __PRETTY_FUNCTION__);
130 stm_.StopTimer();
131 incomeConnect_->AcceptConnection();
132 stm_.GetStmInfo().accepted_ = true;
133 incomeConnect_ = nullptr;
134 } else {
135 HILOGI("%{public}s incomeConnect is null, maybe accepted or rejected.",
136 GetEncryptAddr(stm_.GetDevice().GetAddress()).c_str());
137 }
138 }
139
RejectConnection()140 void PseConnecting::RejectConnection()
141 {
142 if (incomeConnect_ != nullptr) {
143 HILOGI("%{public}s RejectConnection", GetEncryptAddr(stm_.GetDevice().GetAddress()).c_str());
144 stm_.StopTimer();
145 Transition(PbapPseStateMachine::PSE_DISCONNECTING_STATE);
146 incomeConnect_->RejectConnection();
147 incomeConnect_ = nullptr;
148 Transition(PbapPseStateMachine::PSE_DISCONNECTED_STATE);
149 } else {
150 HILOGI("%{public}s incomeConnect is null, maybe accepted or rejected.",
151 GetEncryptAddr(stm_.GetDevice().GetAddress()).c_str());
152 }
153 }
154
CheckConnectHeader(const ObexHeader & req) const155 bool PseConnecting::CheckConnectHeader(const ObexHeader &req) const
156 {
157 auto target = req.GetItemTarget();
158 if (target == nullptr) {
159 PBAP_PSE_LOG_ERROR("Target doesn't exist");
160 return false;
161 }
162 if (target->GetHeaderDataSize() != PBAP_SERVICE_UUID_LEN) {
163 PBAP_PSE_LOG_ERROR("Wrong Target size %u", target->GetHeaderDataSize());
164 return false;
165 }
166 if (memcmp(target->GetBytes().get(), PBAP_SERVICE_UUID, PBAP_SERVICE_UUID_LEN) != 0) {
167 PBAP_PSE_LOG_ERROR("Wrong TargetId:%{public}s",
168 ObexUtils::ToDebugString(target->GetBytes().get(), PBAP_SERVICE_UUID_LEN).c_str());
169 return false;
170 }
171 return true;
172 }
173
ToDisconnect(ObexRspCode rspCode)174 void PseConnecting::ToDisconnect(ObexRspCode rspCode)
175 {
176 auto obexSession = stm_.GetStmInfo().obexSession_;
177 if (obexSession != nullptr) {
178 Transition(PbapPseStateMachine::PSE_DISCONNECTING_STATE);
179 auto header = ObexHeader::CreateResponse(rspCode, true);
180 obexSession->SendResponse(*header);
181 obexSession->Disconnect();
182 } else {
183 Transition(PbapPseStateMachine::PSE_DISCONNECTED_STATE);
184 }
185 }
186
SendSuccessResponse(const std::string & userId,const std::string & pwd)187 void PseConnecting::SendSuccessResponse(const std::string &userId, const std::string &pwd)
188 {
189 auto header = ObexHeader::CreateResponse(ObexRspCode::SUCCESS, true);
190 auto &stmInfo = stm_.GetStmInfo();
191 stmInfo.connectId_ = getNextConnectIdFun_();
192
193 // set connection id
194 header->AppendItemConnectionId(stmInfo.connectId_);
195 // set who
196 header->AppendItemWho(PBAP_SERVICE_UUID, PBAP_SERVICE_UUID_LEN);
197
198 if (authChallenge_) {
199 // Authenticate Response
200 // Carries the digest-response string. This is the response to the challenge from the Client.
201 ObexDigestResponse response;
202 std::vector<uint8_t> requestDigest = ObexUtils::MakeRequestDigest(authNonce_.data(), authNonce_.size(), pwd);
203 response.AppendRequestDigest(requestDigest.data(), requestDigest.size());
204 if (authNeedUser_ && userId.size() > 0) {
205 response.AppendUserId(reinterpret_cast<const uint8_t *>(userId.c_str()), userId.size());
206 }
207 response.AppendNonce(authNonce_.data(), authNonce_.size());
208 header->AppendItemAuthResponse(response);
209 }
210 // send response to client
211 stmInfo.obexSession_->SendResponse(*header);
212 Transition(PbapPseStateMachine::PSE_CONNECTED_STATE);
213 }
214
CheckConnectReq(const PbapPseObexMessage & obexMsg)215 void PseConnecting::CheckConnectReq(const PbapPseObexMessage &obexMsg)
216 {
217 PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
218 const ObexHeader &req = obexMsg.GetObexHeader();
219 stm_.GetStmInfo().obexSession_ = &obexMsg.GetObexSession();
220 if (waitingDisconnect_) {
221 ToDisconnect(ObexRspCode::SERVICE_UNAVAILABLE);
222 return;
223 }
224 if (!CheckConnectHeader(req)) {
225 ToDisconnect();
226 return;
227 }
228
229 auto appParamsTlv = req.GetItemAppParams();
230 if (appParamsTlv != nullptr && appParamsTlv->GetTlvParamters()) {
231 PbapPseAppParams pbapAppParams;
232 pbapAppParams.Init(*appParamsTlv->GetTlvParamters());
233 if (pbapAppParams.GetPbapSupportedFeatures()) {
234 stm_.GetStmInfo().pceFeatures_ = *pbapAppParams.GetPbapSupportedFeatures();
235 PBAP_PSE_LOG_INFO("Set PbapPceSupportedFeatures to %x", *pbapAppParams.GetPbapSupportedFeatures());
236 }
237 }
238
239 auto authChallenges = req.GetItemAuthChallenges();
240 if (authChallenges == nullptr) {
241 SendSuccessResponse();
242 return;
243 }
244
245 // support for legacy PBAP devices
246 CheckAuthChallenges(req, *authChallenges);
247 PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
248 }
249
CheckAuthChallenges(const ObexHeader & req,const ObexOptionalTlvHeader & authChallenges)250 void PseConnecting::CheckAuthChallenges(const ObexHeader &req, const ObexOptionalTlvHeader &authChallenges)
251 {
252 // support for legacy PBAP devices
253 // PBAP_v1.2.3-6.3 Implementations conforming to this specification shall not send the first OBEX
254 // authentication request. It is solely supported for backwards compatibility with legacy PBAP devices.
255 // create auth Response use challenge
256 // note: ignore AuthResponse from client. because our server don't auth the client.
257 auto digestChallenge = static_cast<ObexDigestChallenge *>(authChallenges.GetTlvParamters().get());
258 auto nonceTlv = digestChallenge->GetNonce();
259 if (!nonceTlv) { // nonce is require, but no find
260 ToDisconnect();
261 return;
262 }
263 authChallenge_ = true;
264 authNonce_.clear();
265 authDescription_.clear();
266 authFullAccess_ = true;
267 authNeedUser_ = false;
268 auto targetHr = req.GetItemTarget();
269 auto targetBytes = targetHr->GetBytes();
270 authNonce_.insert(authNonce_.end(), nonceTlv->GetVal(), nonceTlv->GetVal() + nonceTlv->GetLen());
271 auto optionsTlv = digestChallenge->GetOptions();
272 if (optionsTlv) {
273 uint8_t option = optionsTlv->GetVal()[0];
274 // When set, the User Id must be sent in the authenticate response.
275 if ((option & 0x01) != 0) {
276 authNeedUser_ = true;
277 }
278 // Access mode: Read Only when set, otherwise Full access is permitted.
279 if ((option & 0x02) != 0) {
280 authFullAccess_ = false;
281 }
282 }
283 auto realmTlv = digestChallenge->GetRealm();
284 if (realmTlv) {
285 if (realmTlv->GetLen() > 0) {
286 authUserCharset_ = realmTlv->GetVal()[0];
287 if (realmTlv->GetLen() > 1) {
288 authDescription_.insert(
289 authDescription_.end(), realmTlv->GetVal() + 1, realmTlv->GetVal() + realmTlv->GetLen());
290 }
291 }
292 }
293 auto &device = stm_.GetDevice();
294 auto &authDescription = authDescription_;
295 auto &authUserCharset = authUserCharset_;
296 auto &authFullAccess = authFullAccess_;
297 observerMgrList_.ForEach([device, authDescription, authUserCharset, authFullAccess](IPbapPseObserver &observer) {
298 observer.OnServicePasswordRequired(device, authDescription, authUserCharset, authFullAccess);
299 });
300 }
301
PasswordInput(const PbapPsePasswordInputMsg & pwdInputMsg)302 void PseConnecting::PasswordInput(const PbapPsePasswordInputMsg &pwdInputMsg)
303 {
304 if (waitingDisconnect_) {
305 ToDisconnect(ObexRspCode::SERVICE_UNAVAILABLE);
306 return;
307 }
308 PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
309 if (!authChallenge_) {
310 return;
311 }
312 if (pwdInputMsg.GetPassword().size() == 0) {
313 return;
314 }
315
316 SendSuccessResponse(pwdInputMsg.GetUserId(), pwdInputMsg.GetPassword());
317 PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
318 }
319
PseConnected(const std::string & name,PbapPseStateMachine & stm,BaseObserverList<IPbapPseObserver> & observerMgrList)320 PseConnected::PseConnected(
321 const std::string &name, PbapPseStateMachine &stm, BaseObserverList<IPbapPseObserver> &observerMgrList)
322 : State(name, stm), stm_(stm), observerMgrList_(observerMgrList)
323 {}
324
Entry()325 void PseConnected::Entry()
326 {
327 PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
328 auto &device = stm_.GetDevice();
329 IPowerManager::GetInstance().StatusUpdate(RequestStatus::CONNECT_ON, PROFILE_NAME_PBAP_PSE, device);
330 observerMgrList_.ForEach([device](IPbapPseObserver &observer) {
331 observer.OnServiceConnectionStateChanged(device, static_cast<int>(BTConnectState::CONNECTED));
332 });
333 PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
334 }
335
Exit()336 void PseConnected::Exit()
337 {
338 PBAP_PSE_LOG_INFO("%{public}s", __PRETTY_FUNCTION__);
339 }
340
Dispatch(const utility::Message & msg)341 bool PseConnected::Dispatch(const utility::Message &msg)
342 {
343 PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
344 bool ret = true;
345 switch (msg.what_) {
346 case PSE_REQ_OBEX_DISCONNECT:
347 Transition(PbapPseStateMachine::PSE_DISCONNECTING_STATE);
348 // No need to delete
349 DisconnectObex(*static_cast<PbapPseObexMessage *>(msg.arg2_));
350 break;
351 case PSE_DEVICE_DISCONNECTED:
352 Transition(PbapPseStateMachine::PSE_DISCONNECTING_STATE);
353 Transition(PbapPseStateMachine::PSE_DISCONNECTED_STATE);
354 break;
355 case PSE_API_DISCONNECT:
356 if (stm_.GetStmInfo().obexSession_ != nullptr) {
357 Transition(PbapPseStateMachine::PSE_DISCONNECTING_STATE);
358 int retVal = stm_.GetStmInfo().obexSession_->Disconnect();
359 if (retVal != 0) {
360 PBAP_PSE_LOG_ERROR("Obex Disconnect fail ret=%{public}d", retVal);
361 }
362 }
363 break;
364 case PSE_REQ_OBEX_GET:
365 // No need to delete
366 stm_.SetBusy(true);
367 HandleGetRequest(*static_cast<PbapPseObexMessage *>(msg.arg2_));
368 stm_.SetBusy(false);
369 break;
370 case PSE_REQ_OBEX_SETPATH:
371 // No need to delete
372 stm_.SetBusy(true);
373 HandleSetPathRequest(*static_cast<PbapPseObexMessage *>(msg.arg2_));
374 stm_.SetBusy(false);
375 break;
376 default:
377 PBAP_PSE_LOG_ERROR("NOT SUPPORT MSGID %{public}d", msg.what_);
378 ret = false;
379 break;
380 }
381 PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
382 return ret;
383 }
384
HandleGetRequest(const PbapPseObexMessage & obexMsg)385 void PseConnected::HandleGetRequest(const PbapPseObexMessage &obexMsg)
386 {
387 PBAP_PSE_LOG_INFO("%{public}s", __PRETTY_FUNCTION__);
388 const ObexHeader &req = obexMsg.GetObexHeader();
389 ObexServerSession &obexSession = obexMsg.GetObexSession();
390 auto typeItem = req.GetItemType();
391 if (typeItem == nullptr) {
392 PBAP_PSE_LOG_ERROR("PullPhoneBook: type can't be null!");
393 obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
394 return;
395 }
396 std::string type = typeItem->GetString();
397 if (PBAP_PSE_TYPE_PB == type) { // type for PullPhoneBook function
398 PullPhoneBook(obexSession, req);
399 } else if (PBAP_PSE_TYPE_LISTING == type) { // type for PullvCardListing function
400 PullvCardListing(obexSession, req);
401 } else if (PBAP_PSE_TYPE_VCARD == type) { // type for PullvCardEntry Function
402 PullvCardEntry(obexSession, req);
403 } else {
404 PBAP_PSE_LOG_ERROR("PullPhoneBook: type [%{public}s] is unknow.", type.c_str());
405 obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
406 }
407 }
408
HandleSetPathRequest(const PbapPseObexMessage & obexMsg)409 void PseConnected::HandleSetPathRequest(const PbapPseObexMessage &obexMsg)
410 {
411 PBAP_PSE_LOG_INFO("%{public}s", __PRETTY_FUNCTION__);
412 const ObexHeader &req = obexMsg.GetObexHeader();
413 const ObexServerSession &obexSession = obexMsg.GetObexSession();
414 uint8_t flags = *req.GetFieldFlags();
415 PBAP_PSE_LOG_DEBUG("SetPath flags is %x", flags);
416 bool backup = false;
417 bool create = true;
418 if ((flags & OBEX_SETPATH_BACKUP) != 0) {
419 backup = true;
420 }
421 if ((flags & OBEX_SETPATH_NOCREATE) != 0) {
422 create = false;
423 }
424 if (create) {
425 PBAP_PSE_LOG_ERROR("path create is forbidden!");
426 obexSession.SendSimpleResponse(ObexRspCode::FORBIDDEN);
427 return;
428 }
429 std::vector<std::u16string> tmpPaths = currentPath_;
430 if (backup) {
431 if (currentPath_.size() > 0) {
432 tmpPaths.pop_back();
433 }
434 } else {
435 std::u16string name = u"";
436 auto nameItem = req.GetItemName();
437 if (nameItem != nullptr) {
438 name = nameItem->GetUnicodeText();
439 }
440 if (name.size() == 0) {
441 tmpPaths.clear();
442 } else {
443 tmpPaths.push_back(name);
444 }
445 }
446 std::u16string tmpFullPath = GetFullPath(tmpPaths);
447 if (!PbapPseVcardManager::CheckPhoneBookPath(tmpFullPath)) {
448 PBAP_PSE_LOG_ERROR("path isn't allowed! %{public}s", ObexUtils::UnicodeToUtf8(tmpFullPath).c_str());
449 obexSession.SendResponse(*ObexHeader::CreateResponse(ObexRspCode::NOT_FOUND));
450 return;
451 }
452 currentPath_ = tmpPaths;
453 std::u16string path16 = GetCurrentPath();
454 std::string path = ObexUtils::UnicodeToUtf8(path16);
455 PBAP_PSE_LOG_DEBUG("CurrentPath is change to %{public}s", path.c_str());
456 obexSession.SendResponse(*ObexHeader::CreateResponse(ObexRspCode::SUCCESS));
457 }
458
SendPhoneBookResponse(ObexServerSession & obexSession,const ObexHeader & req,const PbapPseVcardManager::PhoneBookResult & pbResult,const PbapPsePhoneBookResOpt & opt) const459 void PseConnected::SendPhoneBookResponse(ObexServerSession &obexSession, const ObexHeader &req,
460 const PbapPseVcardManager::PhoneBookResult &pbResult, const PbapPsePhoneBookResOpt &opt) const
461 {
462 PbapPseAppParams respAppParams;
463 if (opt.phonebookSize_) {
464 uint16_t phoneBookSize = pbResult.phoneBookSize_;
465 respAppParams.SetPhonebookSize(phoneBookSize);
466 }
467 if (opt.newMissedCall_) {
468 respAppParams.SetNewMissedCalls(pbResult.newMissedCallsSize_);
469 }
470 // the “Folder Version Counters” PSE and PCE feature bits are set
471 if (opt.folderVer_) {
472 respAppParams.SetPrimaryFolderVersion(pbResult.primaryFolderVersion_);
473 respAppParams.SetSecondaryFolderVersion(pbResult.secondaryFolderVersion_);
474 }
475 // the “Database Version” PSE and PCE feature bits are set
476 if (opt.dbIdentifier_) {
477 respAppParams.SetDatabaseIdentifier(pbResult.databaseIdentifier_);
478 }
479 auto resp = ObexHeader::CreateResponse(ObexRspCode::SUCCESS);
480 respAppParams.AddToObexHeader(*resp);
481 std::shared_ptr<ObexArrayBodyObject> bodyObject = nullptr;
482 // ADD BODY
483 if (!pbResult.phoneBookSizeOnly_ && pbResult.result_.size() > 0) {
484 PBAP_PSE_LOG_DEBUG("pbResult.result_.size() = %{public}zu", pbResult.result_.size());
485 bodyObject = std::make_shared<ObexArrayBodyObject>(pbResult.result_.data(), pbResult.result_.size());
486 }
487 obexSession.SendGetResponse(req, *resp, bodyObject);
488 }
489
PullPhoneBook(ObexServerSession & obexSession,const ObexHeader & req) const490 void PseConnected::PullPhoneBook(ObexServerSession &obexSession, const ObexHeader &req) const
491 {
492 PBAP_PSE_LOG_INFO("%{public}s ", __PRETTY_FUNCTION__);
493 auto nameItem = req.GetItemName();
494 if (nameItem == nullptr) {
495 PBAP_PSE_LOG_ERROR("PullPhoneBook: name can't be null!");
496 obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
497 return;
498 }
499 std::u16string nameWithFolder = nameItem->GetUnicodeText();
500 if (!IsVCardName(nameWithFolder)) {
501 PBAP_PSE_LOG_ERROR("PullPhoneBook: name must endwith [.vcf]");
502 obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
503 return;
504 }
505
506 auto appParamsItem = req.GetItemAppParams();
507 PbapPseAppParams pbapAppParams;
508 if (appParamsItem != nullptr && appParamsItem->GetTlvParamters()) {
509 bool result = pbapAppParams.Init(*appParamsItem->GetTlvParamters());
510 if (!result) {
511 obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
512 return;
513 }
514 }
515 PbapPseVcardManager::PhoneBookResult pbResult;
516 PbapPseVcardManager::PullPhoneBook(nameWithFolder, pbapAppParams, GetSupportedFeatures(), pbResult);
517 if (pbResult.rspCode_ != ObexRspCode::SUCCESS) {
518 obexSession.SendSimpleResponse(pbResult.rspCode_);
519 return;
520 }
521
522 PbapPsePhoneBookResOpt opts;
523 (void)memset_s(&opts, sizeof(PbapPsePhoneBookResOpt), 0, sizeof(PbapPsePhoneBookResOpt));
524 opts.phonebookSize_ = pbResult.phoneBookSizeOnly_;
525 opts.newMissedCall_ = pbResult.newMissedCalls_;
526 opts.dbIdentifier_ = PbapPseVcardManager::IsSupportedDbVer(GetSupportedFeatures());
527 opts.folderVer_ = PbapPseVcardManager::IsSupportedFolderVer(GetSupportedFeatures());
528
529 SendPhoneBookResponse(obexSession, req, pbResult, opts);
530 }
531
PullvCardListing(ObexServerSession & obexSession,const ObexHeader & req) const532 void PseConnected::PullvCardListing(ObexServerSession &obexSession, const ObexHeader &req) const
533 {
534 PBAP_PSE_LOG_INFO("%{public}s ", __PRETTY_FUNCTION__);
535 auto nameItem = req.GetItemName();
536 if (nameItem == nullptr) {
537 PBAP_PSE_LOG_ERROR("PullvCardListing: name can't be null!");
538 obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
539 return;
540 }
541 std::u16string folderName = nameItem->GetUnicodeText();
542 if (folderName.find(u"/") != std::u16string::npos || folderName.find(u".") != std::u16string::npos) {
543 PBAP_PSE_LOG_ERROR("PullvCardListing: The name shall not include any path/file information!");
544 obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
545 return;
546 }
547 auto appParamsItem = req.GetItemAppParams();
548 PbapPseAppParams pbapAppParams;
549 if (appParamsItem != nullptr && appParamsItem->GetTlvParamters()) {
550 bool result = pbapAppParams.Init(*appParamsItem->GetTlvParamters());
551 if (!result) {
552 obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
553 return;
554 }
555 }
556 PbapPseVcardManager::PhoneBookResult pbResult;
557 PbapPseVcardManager::PullvCardListing(
558 GetCurrentPath(), folderName, pbapAppParams, GetSupportedFeatures(), pbResult);
559 if (pbResult.rspCode_ != ObexRspCode::SUCCESS) {
560 obexSession.SendResponse(*ObexHeader::CreateResponse(pbResult.rspCode_));
561 return;
562 }
563
564 PbapPsePhoneBookResOpt opts;
565 (void)memset_s(&opts, sizeof(PbapPsePhoneBookResOpt), 0, sizeof(PbapPsePhoneBookResOpt));
566 opts.phonebookSize_ = pbResult.phoneBookSizeOnly_;
567 opts.newMissedCall_ = pbResult.newMissedCalls_;
568 opts.dbIdentifier_ = PbapPseVcardManager::IsSupportedDbVer(GetSupportedFeatures());
569 opts.folderVer_ = PbapPseVcardManager::IsSupportedFolderVer(GetSupportedFeatures());
570
571 SendPhoneBookResponse(obexSession, req, pbResult, opts);
572 }
573
CheckvCardEntryId(std::u16string & entryId) const574 bool PseConnected::CheckvCardEntryId(std::u16string &entryId) const
575 {
576 if (entryId.find(u"/") != std::u16string::npos) {
577 PBAP_PSE_LOG_ERROR("PullvCardEntry: The name shall not include any path information!");
578 return false;
579 }
580 if (!IsVCardName(entryId) && entryId.find(PBAP_PSE_X_BT_UID_PREFIX) != 0) {
581 PBAP_PSE_LOG_ERROR("PullvCardEntry: name must endwith [.vcf] or startWith [X-BT-UID:]");
582 return false;
583 }
584
585 if (entryId.find(PBAP_PSE_X_BT_UID_PREFIX) == 0) {
586 if (entryId.size() == PBAP_PSE_X_BT_UID_PREFIX.size()) {
587 PBAP_PSE_LOG_ERROR("PullvCardEntry: X-BT-UID is empty!");
588 return false;
589 }
590 } else {
591 if (entryId.size() == PBAP_PSE_VCARD_SUFFIX.size() ||
592 entryId.size() > (PBAP_PSE_VCARD_SUFFIX.size() + PBAP_PSE_HANDLE_MAX_LENGTH)) {
593 PBAP_PSE_LOG_ERROR("PullvCardEntry: vcf size is invalid!");
594 return false;
595 }
596 std::u16string hdlId = entryId.substr(0, entryId.size() - PBAP_PSE_VCARD_SUFFIX.size());
597 if (!PbapPseVcardManager::CheckVcardHandleId(hdlId)) {
598 PBAP_PSE_LOG_ERROR("PullvCardEntry: vcf is invalid! %{public}s", ObexUtils::UnicodeToUtf8(entryId).c_str());
599 return false;
600 }
601 }
602 return true;
603 }
604
PullvCardEntry(ObexServerSession & obexSession,const ObexHeader & req) const605 void PseConnected::PullvCardEntry(ObexServerSession &obexSession, const ObexHeader &req) const
606 {
607 PBAP_PSE_LOG_INFO("%{public}s ", __PRETTY_FUNCTION__);
608 auto nameItem = req.GetItemName();
609 if (nameItem == nullptr) {
610 PBAP_PSE_LOG_ERROR("PullvCardEntry: name can't be null!");
611 obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
612 return;
613 }
614 std::u16string entryId = nameItem->GetUnicodeText();
615 if (!CheckvCardEntryId(entryId)) {
616 obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
617 return;
618 }
619 auto appParamsItem = req.GetItemAppParams();
620 PbapPseAppParams pbapAppParams;
621 if (appParamsItem != nullptr && appParamsItem->GetTlvParamters()) {
622 bool result = pbapAppParams.Init(*appParamsItem->GetTlvParamters());
623 if (!result) {
624 obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
625 return;
626 }
627 }
628 PbapPseVcardManager::PhoneBookResult pbResult;
629 PbapPseVcardManager::PullvCardEntry(GetCurrentPath(), entryId, pbapAppParams, GetSupportedFeatures(), pbResult);
630 if (pbResult.rspCode_ != ObexRspCode::SUCCESS) {
631 obexSession.SendSimpleResponse(pbResult.rspCode_);
632 return;
633 }
634
635 PbapPsePhoneBookResOpt opts;
636 (void)memset_s(&opts, sizeof(PbapPsePhoneBookResOpt), 0, sizeof(PbapPsePhoneBookResOpt));
637 opts.phonebookSize_ = false;
638 opts.newMissedCall_ = false;
639 opts.dbIdentifier_ = PbapPseVcardManager::IsSupportedDbVer(GetSupportedFeatures());
640 opts.folderVer_ = false;
641
642 SendPhoneBookResponse(obexSession, req, pbResult, opts);
643 }
644
IsVCardName(std::u16string & name) const645 bool PseConnected::IsVCardName(std::u16string &name) const
646 {
647 return name.size() >= PBAP_PSE_VCARD_SUFFIX.size() &&
648 name.find(PBAP_PSE_VCARD_SUFFIX, name.size() - PBAP_PSE_VCARD_SUFFIX.size()) != std::u16string::npos;
649 }
650
GetCurrentPath() const651 std::u16string PseConnected::GetCurrentPath() const
652 {
653 return GetFullPath(currentPath_);
654 }
655
GetFullPath(const std::vector<std::u16string> & paths) const656 std::u16string PseConnected::GetFullPath(const std::vector<std::u16string> &paths) const
657 {
658 std::u16string currentPath = std::accumulate(paths.begin(), paths.end(), std::u16string(u""),
659 [](std::u16string strRet, std::u16string str)->std::u16string {
660 return strRet + u"/" + str;
661 });
662
663 return currentPath;
664 }
665
GetSupportedFeatures() const666 uint32_t PseConnected::GetSupportedFeatures() const
667 {
668 return stm_.GetStmInfo().pceFeatures_ & PBAP_PSE_SUPPORTED_FEATURES;
669 }
670
DisconnectObex(const PbapPseObexMessage & obexMsg) const671 void PseConnected::DisconnectObex(const PbapPseObexMessage &obexMsg) const
672 {
673 PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
674 ObexServerSession &obexSession = obexMsg.GetObexSession();
675 obexSession.SendSimpleResponse(ObexRspCode::SUCCESS);
676 obexSession.Disconnect();
677 PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
678 }
679
PseDisConnected(const std::string & name,PbapPseStateMachine & stm,BaseObserverList<IPbapPseObserver> & observerMgrList)680 PseDisConnected::PseDisConnected(
681 const std::string &name, PbapPseStateMachine &stm, BaseObserverList<IPbapPseObserver> &observerMgrList)
682 : State(name, stm), stm_(stm), observerMgrList_(observerMgrList)
683 {}
684
Entry()685 void PseDisConnected::Entry()
686 {
687 PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
688 auto &device = stm_.GetDevice();
689 IPowerManager::GetInstance().StatusUpdate(RequestStatus::CONNECT_OFF, PROFILE_NAME_PBAP_PSE, device);
690 observerMgrList_.ForEach([device](IPbapPseObserver &observer) {
691 observer.OnServiceConnectionStateChanged(device, static_cast<int>(BTConnectState::DISCONNECTED));
692 });
693 PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
694 }
695
Exit()696 void PseDisConnected::Exit()
697 {}
698
Dispatch(const utility::Message & msg)699 bool PseDisConnected::Dispatch(const utility::Message &msg)
700 {
701 PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
702 PBAP_PSE_LOG_ERROR("NOT SUPPORT MSGID %{public}d", msg.what_);
703 PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
704 return false;
705 }
706
PseDisConnecting(const std::string & name,PbapPseStateMachine & stm,BaseObserverList<IPbapPseObserver> & observerMgrList)707 PseDisConnecting::PseDisConnecting(
708 const std::string &name, PbapPseStateMachine &stm, BaseObserverList<IPbapPseObserver> &observerMgrList)
709 : State(name, stm), stm_(stm), observerMgrList_(observerMgrList)
710 {}
711
Entry()712 void PseDisConnecting::Entry()
713 {
714 PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
715 auto &device = stm_.GetDevice();
716 observerMgrList_.ForEach([device](IPbapPseObserver &observer) {
717 observer.OnServiceConnectionStateChanged(device, static_cast<int>(BTConnectState::DISCONNECTING));
718 });
719 PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
720 }
721
Exit()722 void PseDisConnecting::Exit()
723 {
724 PBAP_PSE_LOG_INFO("%{public}s", __PRETTY_FUNCTION__);
725 }
726
Dispatch(const utility::Message & msg)727 bool PseDisConnecting::Dispatch(const utility::Message &msg)
728 {
729 PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
730 bool ret = true;
731 switch (msg.what_) {
732 case PSE_DEVICE_DISCONNECTED:
733 Transition(PbapPseStateMachine::PSE_DISCONNECTED_STATE);
734 break;
735 default:
736 PBAP_PSE_LOG_ERROR("NOT SUPPORT MSGID %{public}d", msg.what_);
737 ret = false;
738 break;
739 }
740
741 PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
742 return ret;
743 }
744
PbapPseStateMachine(const RawAddress & device,BaseObserverList<IPbapPseObserver> & observerMgrList,std::function<uint32_t ()> getNextConnectIdFun)745 PbapPseStateMachine::PbapPseStateMachine(const RawAddress &device, BaseObserverList<IPbapPseObserver> &observerMgrList,
746 std::function<uint32_t()> getNextConnectIdFun)
747 : device_(device), observerMgrList_(observerMgrList), getNextConnectIdFun_(std::move(getNextConnectIdFun))
748 {
749 }
750
~PbapPseStateMachine()751 PbapPseStateMachine::~PbapPseStateMachine()
752 {
753 PBAP_PSE_LOG_INFO("%{public}s", __PRETTY_FUNCTION__);
754 }
755
756 const std::string PbapPseStateMachine::PSE_WAITING_FOR_CONNECT_STATE = "PseWaitingForConnect";
757 const std::string PbapPseStateMachine::PSE_CONNECTED_STATE = "PseConnected";
758 const std::string PbapPseStateMachine::PSE_CONNECTING_STATE = "PseConnecting";
759 const std::string PbapPseStateMachine::PSE_DISCONNECTED_STATE = "PseDisConnected";
760 const std::string PbapPseStateMachine::PSE_DISCONNECTING_STATE = "PseDisConnecting";
761
Init()762 void PbapPseStateMachine::Init()
763 {
764 std::unique_ptr<State> disconnected =
765 std::make_unique<PseDisConnected>(PSE_DISCONNECTED_STATE, *this, observerMgrList_);
766 std::unique_ptr<State> disconnecting =
767 std::make_unique<PseDisConnecting>(PSE_DISCONNECTING_STATE, *this, observerMgrList_);
768 std::unique_ptr<State> connecting =
769 std::make_unique<PseConnecting>(PSE_CONNECTING_STATE, *this, observerMgrList_, getNextConnectIdFun_);
770 std::unique_ptr<State> waitingForCnt = std::make_unique<PseWaitingForConnect>(PSE_WAITING_FOR_CONNECT_STATE, *this);
771 std::unique_ptr<State> connected = std::make_unique<PseConnected>(PSE_CONNECTED_STATE, *this, observerMgrList_);
772
773 Move(disconnected);
774 Move(disconnecting);
775 Move(connecting);
776 Move(waitingForCnt);
777 Move(connected);
778
779 InitState(PSE_WAITING_FOR_CONNECT_STATE);
780 }
781
StartTimer(std::function<void ()> callback,int ms)782 bool PbapPseStateMachine::StartTimer(std::function<void()> callback, int ms)
783 {
784 PBAP_PSE_LOG_INFO("%{public}s", __PRETTY_FUNCTION__);
785 timer_ = std::make_unique<utility::Timer>(callback);
786 return timer_->Start(ms, false);
787 }
788
StopTimer()789 void PbapPseStateMachine::StopTimer()
790 {
791 if (timer_) {
792 PBAP_PSE_LOG_INFO("%{public}s", __PRETTY_FUNCTION__);
793 timer_->Stop();
794 timer_ = nullptr;
795 }
796 }
797
GetConnectState() const798 BTConnectState PbapPseStateMachine::GetConnectState() const
799 {
800 std::string name = GetState()->Name();
801 if (name == PSE_CONNECTING_STATE) {
802 return BTConnectState::CONNECTING;
803 }
804 if (name == PSE_CONNECTED_STATE) {
805 return BTConnectState::CONNECTED;
806 }
807 if (name == PSE_DISCONNECTING_STATE) {
808 return BTConnectState::DISCONNECTING;
809 }
810 return BTConnectState::DISCONNECTED;
811 }
812
813 /**
814 * @brief get remote address
815 * @details get remote address
816 * @return RawAddress&
817 */
GetDevice() const818 const RawAddress &PbapPseStateMachine::GetDevice() const
819 {
820 return device_;
821 }
822
823 /**
824 * @brief Is Connected
825 * @details Is Connected
826 * @return bool
827 */
IsConnected() const828 bool PbapPseStateMachine::IsConnected() const
829 {
830 return GetState()->Name() == PSE_CONNECTED_STATE;
831 }
832
IsAccepted() const833 bool PbapPseStateMachine::IsAccepted() const
834 {
835 return stmInfo_.accepted_;
836 }
837
SetBusy(bool isBusy)838 void PbapPseStateMachine::SetBusy(bool isBusy)
839 {
840 if (stmInfo_.isBusy_ == isBusy) {
841 return;
842 }
843 stmInfo_.isBusy_ = isBusy;
844 if (isBusy) {
845 HILOGI("[%{public}s] PowerStatusUpdate -> BUSY", GetEncryptAddr(device_.GetAddress()).c_str());
846 IPowerManager::GetInstance().StatusUpdate(RequestStatus::BUSY, PROFILE_NAME_PBAP_PSE, device_);
847 } else {
848 HILOGI("[%{public}s] PowerStatusUpdate -> IDLE", GetEncryptAddr(device_.GetAddress()).c_str());
849 IPowerManager::GetInstance().StatusUpdate(RequestStatus::IDLE, PROFILE_NAME_PBAP_PSE, device_);
850 }
851 }
852
IsBusy() const853 bool PbapPseStateMachine::IsBusy() const
854 {
855 return stmInfo_.isBusy_;
856 }
857
GetStmInfo()858 PbapPseStateMachineInfo &PbapPseStateMachine::GetStmInfo()
859 {
860 return stmInfo_;
861 }
862 } // namespace bluetooth
863 } // namespace OHOS