1 /*
2 * Copyright (C) 2021 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_pce_obex_client.h"
17 #include "pbap_pce_def.h"
18 #include "pbap_pce_service.h"
19 #include "log_util.h"
20
21 namespace OHOS {
22 namespace bluetooth {
ObexFileBodyObject(const std::string & file)23 ObexFileBodyObject::ObexFileBodyObject(const std::string &file)
24 {
25 OpenOutFile(file);
26 }
27
OpenOutFile(const std::string & file)28 void ObexFileBodyObject::OpenOutFile(const std::string &file)
29 {
30 ofs_.open(file, std::ios::out);
31 if (!ofs_.is_open()) {
32 PBAP_PCE_LOG_ERROR("%{public}s file open failed", __PRETTY_FUNCTION__);
33 } else {
34 PBAP_PCE_LOG_DEBUG("%{public}s file=%{public}s opened.", __PRETTY_FUNCTION__, file.c_str());
35 }
36 }
37
Read(uint8_t * buf,size_t bufLen)38 size_t ObexFileBodyObject::Read(uint8_t *buf, size_t bufLen)
39 {
40 size_t readSize = bufLen;
41 return readSize;
42 }
43
Write(const uint8_t * buf,size_t bufLen)44 size_t ObexFileBodyObject::Write(const uint8_t *buf, size_t bufLen)
45 {
46 if (ofs_.is_open()) {
47 auto buffer = reinterpret_cast<const char*>(buf);
48 ofs_.write(buffer, bufLen);
49 PBAP_PCE_LOG_DEBUG("%{public}s write file bufLen=%zu", __PRETTY_FUNCTION__, bufLen);
50 } else {
51 PBAP_PCE_LOG_ERROR("%{public}s file open failed", __PRETTY_FUNCTION__);
52 }
53 return bufLen;
54 }
55
Close()56 int ObexFileBodyObject::Close()
57 {
58 ofs_.close();
59 return 0;
60 }
61
PbapPceObexClient(const ObexClientConfig & config,PbapPceService & pceService)62 PbapPceObexClient::PbapPceObexClient(const ObexClientConfig &config, PbapPceService &pceService)
63 : obexConfig_(config), pceService_(pceService)
64 {
65 observer_ = std::make_unique<PceObexObserver>(pceService_);
66 client_ = std::make_unique<ObexMpClient>(obexConfig_, *observer_, *pceService.GetDispatcher());
67 }
68
~PbapPceObexClient()69 PbapPceObexClient::~PbapPceObexClient()
70 {}
71
Connect(bool supported)72 int PbapPceObexClient::Connect(bool supported)
73 {
74 PBAP_PCE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
75 int ret = RET_BAD_STATUS;
76 if (observer_ == nullptr) {
77 PBAP_PCE_LOG_ERROR("%{public}s end, observer_ is null", __PRETTY_FUNCTION__);
78 return ret;
79 }
80 if (IsBusy()) {
81 PBAP_PCE_LOG_ERROR("%{public}s end, IS busy", __PRETTY_FUNCTION__);
82 return ret;
83 }
84 SetBusy(true);
85 if (supported) {
86 ObexTlvParamters p;
87 TlvTriplet tlv(static_cast<uint8_t>(PbapSupportedFeatures::PCE_PBAP_SUPPORTED_FEATURES), PBAP_PCE_FEATURES);
88 p.AppendTlvtriplet(tlv);
89 ObexConnectParams param = {.appParams_ = &p};
90 ret = client_->Connect(param);
91 } else {
92 ret = client_->Connect();
93 }
94
95 PBAP_PCE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
96 return ret;
97 }
98
Reconnect(ObexDigestChallenge & challenge,ObexDigestResponse & digest)99 int PbapPceObexClient::Reconnect(ObexDigestChallenge &challenge, ObexDigestResponse &digest)
100 {
101 PBAP_PCE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
102 int ret = RET_BAD_STATUS;
103 if (observer_ == nullptr) {
104 PBAP_PCE_LOG_ERROR("%{public}s end, observer_ is null", __PRETTY_FUNCTION__);
105 return ret;
106 }
107
108 if (IsBusy()) {
109 PBAP_PCE_LOG_ERROR("%{public}s end, IS busy", __PRETTY_FUNCTION__);
110 return ret;
111 }
112 SetBusy(true);
113 ObexTlvParamters p;
114 ObexConnectParams param = {&p, &challenge, &digest};
115 ret = client_->Connect(param);
116 PBAP_PCE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
117 return ret;
118 }
119
Disconnect(bool withObexReq) const120 int PbapPceObexClient::Disconnect(bool withObexReq) const
121 {
122 PBAP_PCE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
123 int ret = RET_BAD_STATUS;
124 if (client_ == nullptr) {
125 PBAP_PCE_LOG_ERROR("%{public}s end, client_ is null", __PRETTY_FUNCTION__);
126 return ret;
127 }
128 ret = client_->Disconnect(withObexReq);
129 PBAP_PCE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
130 return ret;
131 }
132
Get(const ObexHeader & req,int reqMsgType) const133 int PbapPceObexClient::Get(const ObexHeader &req, int reqMsgType) const
134 {
135 PBAP_PCE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
136 int ret = RET_BAD_STATUS;
137 if ((client_ == nullptr) || (observer_ == nullptr)) {
138 PBAP_PCE_LOG_ERROR("%{public}s end, client_ or observer_ is null", __PRETTY_FUNCTION__);
139 return ret;
140 }
141 #ifdef PBAP_PCE_RECEIVED_BY_OBEX_ARRAY
142 auto writer = std::make_shared<ObexArrayBodyObject>();
143 ret = client_->Get(req, writer);
144 #else
145 if (reqMsgType == PCE_REQ_PULLPHONEBOOK) {
146 auto &device = client_->GetClientSession().GetRemoteAddr();
147 std::string file = pceService_.GetDownloadFileName(device);
148 auto writer = std::make_shared<ObexFileBodyObject>(file);
149 ret = client_->Get(req, writer);
150 } else {
151 auto writer = std::make_shared<ObexArrayBodyObject>();
152 ret = client_->Get(req, writer);
153 }
154 #endif // PBAP_PCE_RECEIVED_BY_OBEX_ARRAY
155
156 auto &pSession = client_->GetClientSession();
157 observer_->SetPhoneBookActionInfo(pSession.GetLastOpeId(), reqMsgType);
158
159 PBAP_PCE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
160 return ret;
161 }
162
SetPath(uint8_t flag,const std::u16string & path) const163 int PbapPceObexClient::SetPath(uint8_t flag, const std::u16string &path) const
164 {
165 PBAP_PCE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
166 int ret = RET_BAD_STATUS;
167 if ((client_ == nullptr) || (observer_ == nullptr)) {
168 PBAP_PCE_LOG_ERROR("%{public}s end, client_ or observer_ is null", __PRETTY_FUNCTION__);
169 return ret;
170 }
171
172 // absolute path
173 char16_t separator = u'/';
174 if (path.find(separator) != std::u16string::npos) {
175 std::vector<std::u16string> paths;
176 size_t prevPos = 0;
177 size_t pos = 0;
178 while (pos < path.size()) {
179 if (path[pos] == separator) {
180 paths.push_back(path.substr(prevPos, pos - prevPos));
181 prevPos = pos + 1;
182 }
183 pos++;
184 }
185 paths.push_back(path.substr(prevPos, pos - prevPos));
186 ret = client_->SetPath(paths);
187 } else {
188 ret = client_->SetPath(flag, path);
189 }
190
191 auto &pSession = client_->GetClientSession();
192 observer_->SetPhoneBookActionInfo(pSession.GetLastOpeId(), PCE_REQ_SETPHONEBOOK, path, flag);
193
194 PBAP_PCE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
195 return ret;
196 }
197
Abort() const198 int PbapPceObexClient::Abort() const
199 {
200 int ret = RET_BAD_STATUS;
201 if ((client_ == nullptr) || (observer_ == nullptr)) {
202 PBAP_PCE_LOG_ERROR("%{public}s client_ or observer_ is null", __PRETTY_FUNCTION__);
203 return ret;
204 }
205 ret = client_->Abort();
206 SetAbort(true);
207 return ret;
208 }
209
GetClient() const210 ObexMpClient *PbapPceObexClient::GetClient() const
211 {
212 if (client_ == nullptr) {
213 PBAP_PCE_LOG_ERROR("%{public}s client_ is null", __PRETTY_FUNCTION__);
214 return nullptr;
215 }
216 return client_.get();
217 }
218
OnTransportFailed(ObexClient & client,int errCd)219 void PbapPceObexClient::PceObexObserver::OnTransportFailed(ObexClient &client, int errCd)
220 {
221 PBAP_PCE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
222 PBAP_PCE_LOG_ERROR("Transport failed with error %{public}d", errCd);
223 isBusy_ = false;
224 const auto &device = client.GetClientSession().GetRemoteAddr();
225 utility::Message msg(PCE_TRANSPORT_FAILED, errCd);
226 pceService_.ProcessObexRespMessage(device, msg);
227 PBAP_PCE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
228 }
229
OnConnected(ObexClient & client,const ObexHeader & resp)230 void PbapPceObexClient::PceObexObserver::OnConnected(ObexClient &client, const ObexHeader &resp)
231 {
232 PBAP_PCE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
233 isBusy_ = false;
234 const auto &device = client.GetClientSession().GetRemoteAddr();
235 std::unique_ptr<PbapPceObexMessage> obexMsg = std::make_unique<PbapPceObexMessage>(client, resp);
236 utility::Message msg(PCE_OBEX_CONNECTED, 0, static_cast<void *>(obexMsg.get()));
237 pceService_.ProcessObexRespMessage(device, msg);
238 PBAP_PCE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
239 }
240
OnConnectFailed(ObexClient & client,const ObexHeader & resp)241 void PbapPceObexClient::PceObexObserver::OnConnectFailed(ObexClient &client, const ObexHeader &resp)
242 {
243 PBAP_PCE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
244 isBusy_ = false;
245 const auto &device = client.GetClientSession().GetRemoteAddr();
246 std::unique_ptr<PbapPceObexMessage> obexMsg = std::make_unique<PbapPceObexMessage>(client, resp);
247 utility::Message msg(PCE_OBEX_CONNECT_FAILED, 0, static_cast<void *>(obexMsg.get()));
248 pceService_.ProcessObexRespMessage(device, msg);
249 PBAP_PCE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
250 }
251
OnDisconnected(ObexClient & client)252 void PbapPceObexClient::PceObexObserver::OnDisconnected(ObexClient &client)
253 {
254 PBAP_PCE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
255 isBusy_ = false;
256 const auto &device = client.GetClientSession().GetRemoteAddr();
257 utility::Message msg(PCE_OBEX_DISCONNECTED);
258 pceService_.ProcessObexRespMessage(device, msg);
259
260 PBAP_PCE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
261 }
262
OnActionCompleted(ObexClient & client,const ObexHeader & resp)263 void PbapPceObexClient::PceObexObserver::OnActionCompleted(ObexClient &client, const ObexHeader &resp)
264 {
265 PBAP_PCE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
266 isBusy_ = false;
267 auto &pSession = client.GetClientSession();
268 int lastCommandMsgType = 0;
269 std::u16string path;
270 uint8_t flags = 0;
271 GetPhoneBookActionInfo(pSession.GetLastOpeId(), lastCommandMsgType, path, flags);
272 const int offsetToComp = 1;
273 if (isAbort_) {
274 isAbort_ = false;
275 // req id to completed id
276 lastCommandMsgType = PCE_REQ_ABORTDOWNLOADING + offsetToComp;
277 } else {
278 // req id to completed id
279 lastCommandMsgType = lastCommandMsgType + offsetToComp;
280 }
281
282 const auto &device = client.GetClientSession().GetRemoteAddr();
283 PbapPceActionObexMessage obexMsg(client, resp, path, flags);
284 utility::Message msg(lastCommandMsgType, 0, static_cast<void *>(&obexMsg));
285 pceService_.ProcessObexRespMessage(device, msg);
286 PBAP_PCE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
287 }
288
OnBusy(ObexClient & client,bool isBusy)289 void PbapPceObexClient::PceObexObserver::OnBusy(ObexClient &client, bool isBusy)
290 {
291 auto &device = client.GetClientSession().GetRemoteAddr();
292 HILOGI("device=%{public}s, isBusy=%{public}d", GET_ENCRYPT_ADDR(device), isBusy ? 1 : 0);
293 }
294
GetPhoneBookActionInfo(int operationId,int & retReqMsgType,std::u16string & retPath,uint8_t & retFlags) const295 bool PbapPceObexClient::PceObexObserver::GetPhoneBookActionInfo(
296 int operationId, int &retReqMsgType, std::u16string &retPath, uint8_t &retFlags) const
297 {
298 bool ret = true;
299 retReqMsgType = phoneBookActionInfo_.reqMsgType_;
300 retPath = phoneBookActionInfo_.path_;
301 retFlags = phoneBookActionInfo_.flags_;
302 return ret;
303 }
304
SetPhoneBookActionInfo(int operationId,int reqMsgType,const std::u16string & path,uint8_t flags,bool isBusy)305 void PbapPceObexClient::PceObexObserver::SetPhoneBookActionInfo(
306 int operationId, int reqMsgType, const std::u16string &path, uint8_t flags, bool isBusy)
307 {
308 phoneBookActionInfo_.operationId_ = operationId;
309 phoneBookActionInfo_.reqMsgType_ = reqMsgType;
310 phoneBookActionInfo_.path_ = path;
311 phoneBookActionInfo_.flags_ = flags;
312 isBusy_ = isBusy;
313 }
314
SetBusy(bool isBusy) const315 void PbapPceObexClient::SetBusy(bool isBusy) const
316 {
317 PBAP_PCE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
318 if (observer_ != nullptr) {
319 observer_->isBusy_ = isBusy;
320 }
321 PBAP_PCE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
322 }
323
IsBusy() const324 bool PbapPceObexClient::IsBusy() const
325 {
326 PBAP_PCE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
327 if (observer_ != nullptr) {
328 return observer_->isBusy_;
329 }
330 PBAP_PCE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
331 return false;
332 }
333
SetAbort(bool isAbort) const334 void PbapPceObexClient::SetAbort(bool isAbort) const
335 {
336 PBAP_PCE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
337 if (observer_ != nullptr) {
338 observer_->isAbort_ = isAbort;
339 }
340 PBAP_PCE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
341 }
342 } // namespace bluetooth
343 } // namespace OHOS
344