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 "obex_mp_client.h"
17 #include "log.h"
18 namespace OHOS {
19 namespace bluetooth {
ObexMpClient(const ObexClientConfig & config,ObexClientObserver & observer,utility::Dispatcher & dispatcher)20 ObexMpClient::ObexMpClient(
21 const ObexClientConfig &config, ObexClientObserver &observer, utility::Dispatcher &dispatcher)
22 : ObexClient(config, observer, dispatcher)
23 {}
24
Put(const ObexHeader & req)25 int ObexMpClient::Put(const ObexHeader &req)
26 {
27 return ObexClient::Put(req);
28 }
29
Put(const ObexHeader & req,std::shared_ptr<ObexBodyObject> reader)30 int ObexMpClient::Put(const ObexHeader &req, std::shared_ptr<ObexBodyObject> reader)
31 {
32 OBEX_LOG_INFO("[%{public}s] Call %{public}s", GetClientId().c_str(), __PRETTY_FUNCTION__);
33 if (!CheckBeforeRequest(req.GetFieldCode())) {
34 return -1;
35 }
36 if (req.GetFieldCode() != static_cast<uint8_t>(ObexOpeId::PUT) &&
37 req.GetFieldCode() != static_cast<uint8_t>(ObexOpeId::PUT_FINAL)) {
38 OBEX_LOG_ERROR("Error: Opcode is wrong.");
39 return -1;
40 }
41 if (req.HasHeader(ObexHeader::BODY) || req.HasHeader(ObexHeader::END_OF_BODY)) {
42 OBEX_LOG_ERROR("Error: Can't include body/end-of-body header in this method.");
43 return -1;
44 }
45
46 uint16_t mtu = clientSession_->GetMaxPacketLength();
47 OBEX_LOG_DEBUG("Create ObexClientSendObject mtu=%{public}d", int(mtu));
48
49 auto &sendObject = clientSession_->CreateSendObject(req, reader, mtu);
50 auto sendReq = sendObject->GetNextReqHeader(isSupportSrm_);
51 if (sendReq == nullptr) {
52 clientSession_->FreeSendObject();
53 return -1;
54 }
55 int ret = SendRequest(*sendReq);
56 if (ret != 0) {
57 clientSession_->FreeSendObject();
58 } else {
59 SetBusy(true);
60 }
61 return ret;
62 }
63
Get(const ObexHeader & req)64 int ObexMpClient::Get(const ObexHeader &req)
65 {
66 return ObexClient::Get(req);
67 }
68
Get(const ObexHeader & req,std::shared_ptr<ObexBodyObject> writer,int srmpCount)69 int ObexMpClient::Get(const ObexHeader &req, std::shared_ptr<ObexBodyObject> writer, int srmpCount)
70 {
71 OBEX_LOG_INFO("[%{public}s] Call %{public}s", GetClientId().c_str(), __PRETTY_FUNCTION__);
72 if (!CheckBeforeRequest(req.GetFieldCode())) {
73 return -1;
74 }
75 if (req.GetFieldCode() != static_cast<uint8_t>(ObexOpeId::GET) &&
76 req.GetFieldCode() != static_cast<uint8_t>(ObexOpeId::GET_FINAL)) {
77 OBEX_LOG_ERROR("Error: Opcode is wrong.");
78 return -1;
79 }
80 auto &recvObj = clientSession_->CreateReceivedObject(req, writer, isSupportSrm_, srmpCount);
81 const auto &sendReq = recvObj->GetFirstReqHeader();
82 int ret = SendRequest(sendReq);
83 if (ret != 0) {
84 clientSession_->FreeReceivedObject();
85 } else {
86 SetBusy(true);
87 }
88 return ret;
89 }
90
SetPath(uint8_t flag,const std::u16string & path)91 int ObexMpClient::SetPath(uint8_t flag, const std::u16string &path)
92 {
93 OBEX_LOG_INFO("[%{public}s] Call %{public}s", GetClientId().c_str(), __PRETTY_FUNCTION__);
94 return ObexClient::SetPath(flag, path);
95 }
96
SetPath(const std::vector<std::u16string> & paths)97 int ObexMpClient::SetPath(const std::vector<std::u16string> &paths)
98 {
99 OBEX_LOG_INFO("[%{public}s] Call %{public}s", GetClientId().c_str(), __PRETTY_FUNCTION__);
100 if (paths.size() == 0) {
101 OBEX_LOG_ERROR("Error: SetPath Job's size is 0.");
102 return -1;
103 }
104 if (clientSession_->GetSetPathObject() != nullptr && !clientSession_->GetSetPathObject()->IsDone()) {
105 OBEX_LOG_ERROR("Error: Another SetPath Job is being processing.");
106 return -1;
107 }
108 clientSession_->CreateSetPathObject(paths);
109 // first goto root
110 return ObexClient::SetPath(OBEX_SETPATH_NOCREATE, u"");
111 }
112
PutDataAvailable(const ObexHeader & resp)113 void ObexMpClient::PutDataAvailable(const ObexHeader &resp)
114 {
115 OBEX_LOG_INFO("[%{public}s] Call %{public}s", GetClientId().c_str(), __PRETTY_FUNCTION__);
116 if (isWaitingSendAbort_) {
117 OBEX_LOG_DEBUG("PutDataAvailable: skip received data, send aborted request!");
118 isProcessing_ = false;
119 SendAbortRequest();
120 clientSession_->FreeSendObject();
121 return;
122 }
123 if (isAbortSended_) {
124 OBEX_LOG_DEBUG("PutDataAvailable: skip received data.");
125 clientSession_->FreeSendObject();
126 return;
127 }
128 HandlePutData(resp);
129 }
130
HandlePutData(const ObexHeader & resp)131 void ObexMpClient::HandlePutData(const ObexHeader &resp)
132 {
133 auto &sendObject = clientSession_->GetSendObject();
134 if (sendObject != nullptr && resp.GetFieldCode() == static_cast<uint8_t>(ObexRspCode::CONTINUE)) {
135 if (isSupportSrm_ && !sendObject->IsSrmSending()) {
136 if (resp.HasHeader(ObexHeader::SRM)) {
137 bool srmEnable = resp.GetItemSrm();
138 sendObject->SetSrmEnable(srmEnable);
139 OBEX_LOG_DEBUG("PutDataAvailable: srm mode enable.");
140 }
141 if (resp.HasHeader(ObexHeader::SRMP)) {
142 bool srmWait = resp.GetItemSrmp();
143 sendObject->SetSrmWait(srmWait);
144 OBEX_LOG_DEBUG("PutDataAvailable: srmp waiting.");
145 } else if (sendObject->IsSrmEnable()) {
146 sendObject->SetSrmWait(false);
147 OBEX_LOG_DEBUG("PutDataAvailable: srmp wait done.");
148 }
149 }
150 if (sendObject->IsSrmEnable() && !sendObject->IsSrmWait()) {
151 OBEX_LOG_DEBUG("PutDataAvailable: send put with srm. START");
152 ProcessSendPutWithSrm();
153 } else if (sendObject->IsDone()) {
154 clientSession_->FreeSendObject();
155 clientObserver_.OnActionCompleted(*this, resp);
156 } else {
157 auto nexReqHdr = sendObject->GetNextReqHeader();
158 isProcessing_ = false;
159 int ret = SendRequest(*nexReqHdr);
160 if (ret != 0) {
161 clientSession_->FreeSendObject();
162 clientObserver_.OnTransportFailed(*this, ret);
163 }
164 }
165 return;
166 }
167 clientSession_->FreeSendObject();
168 ObexClient::PutDataAvailable(resp);
169 }
170
ProcessSendPutWithSrm()171 int ObexMpClient::ProcessSendPutWithSrm()
172 {
173 OBEX_LOG_INFO("[%{public}s] Call %{public}s", GetClientId().c_str(), __PRETTY_FUNCTION__);
174 if (isWaitingSendAbort_) {
175 OBEX_LOG_DEBUG("ProcessSendPutWithSrm: send abort request, break srm send!");
176 isProcessing_ = false;
177 SendAbortRequest();
178 clientSession_->FreeSendObject();
179 return 0;
180 }
181 if (isAbortSended_) {
182 OBEX_LOG_DEBUG("ProcessSendPutWithSrm: break srm send");
183 clientSession_->FreeSendObject();
184 return 0;
185 }
186 auto &sendObject = clientSession_->GetSendObject();
187 if (!sendObject) {
188 return -1;
189 }
190 sendObject->SetSrmSending();
191 if (sendObject->IsBusy()) {
192 OBEX_LOG_DEBUG("ProcessSendPutWithSrm: Transport is busy, waiting...");
193 return 0;
194 }
195 auto nexReqHdr = sendObject->GetNextReqHeader();
196 if (nexReqHdr == nullptr) {
197 if (!sendObject->IsDone()) {
198 clientSession_->FreeSendObject();
199 clientObserver_.OnTransportFailed(*this, -1);
200 }
201 return -1;
202 }
203 isProcessing_ = false;
204 int ret = SendRequest(*nexReqHdr);
205 if (ret != 0) {
206 clientSession_->FreeSendObject();
207 clientObserver_.OnTransportFailed(*this, ret);
208 return ret;
209 }
210 if (sendObject->IsDone()) {
211 OBEX_LOG_DEBUG("ProcessSendPutWithSrm: DONE!");
212 return 0;
213 }
214 OBEX_LOG_DEBUG("ProcessSendPutWithSrm: CONTINUE");
215 dispatcher_.PostTask(std::bind(&ObexMpClient ::ProcessSendPutWithSrm, this));
216 return 0;
217 }
218
GetDataAvailable(const ObexHeader & resp)219 void ObexMpClient::GetDataAvailable(const ObexHeader &resp)
220 {
221 OBEX_LOG_INFO("[%{public}s] Call %{public}s", GetClientId().c_str(), __PRETTY_FUNCTION__);
222 if (isWaitingSendAbort_) {
223 OBEX_LOG_DEBUG("GetDataAvailable: skip received data, send aborted request!");
224 SendAbortRequest();
225 clientSession_->FreeReceivedObject();
226 return;
227 }
228 if (isAbortSended_) {
229 clientSession_->FreeReceivedObject();
230 OBEX_LOG_DEBUG("GetDataAvailable: skip received data.");
231 return;
232 }
233 const auto &recvObj = clientSession_->GetReceivedObject();
234
235 if (recvObj != nullptr && resp.GetFieldCode() == static_cast<uint8_t>(ObexRspCode::CONTINUE)) {
236 OBEX_LOG_DEBUG("GetDataAvailable: recvObj != null, Received CONTINUE Response!");
237 ProcessGetContinueData(resp);
238 return;
239 }
240 if (recvObj != nullptr && resp.GetFieldCode() == static_cast<uint8_t>(ObexRspCode::SUCCESS)) {
241 OBEX_LOG_DEBUG("GetDataAvailable: recvObj != null, Received SUCCESS Response!");
242 ProcessGetSuccessData(resp);
243 return;
244 }
245 if (recvObj != nullptr) {
246 OBEX_LOG_DEBUG("GetDataAvailable: recvObj != null, Received Error Response! 0x%02X", resp.GetFieldCode());
247 // OBEX ERROR CODE
248 clientSession_->FreeReceivedObject();
249 ObexClient::GetDataAvailable(resp);
250 return;
251 }
252 clientSession_->FreeReceivedObject();
253 ObexClient::GetDataAvailable(resp);
254 }
255
ProcessGetContinueData(const ObexHeader & resp)256 void ObexMpClient::ProcessGetContinueData(const ObexHeader &resp)
257 {
258 OBEX_LOG_INFO("[%{public}s] Call %{public}s", GetClientId().c_str(), __PRETTY_FUNCTION__);
259 auto &recvObj = clientSession_->GetReceivedObject();
260
261 recvObj->CacheResp(resp);
262 auto body = resp.GetItemBody();
263 if (body != nullptr) {
264 recvObj->AppendBody(body->GetBytes().get(), body->GetHeaderDataSize());
265 }
266 bool sendNextReq = true;
267 if (recvObj->IsSupportSrmMode()) {
268 if (!recvObj->IsSendNextReq()) {
269 sendNextReq = false;
270 } else {
271 if (resp.HasHeader(ObexHeader::SRM)) {
272 recvObj->SetSrmEnable(resp.GetItemSrm());
273 }
274 if (resp.HasHeader(ObexHeader::SRMP)) {
275 recvObj->SetSrmWait(resp.GetItemSrmp());
276 } else {
277 recvObj->SetSrmWait(false);
278 }
279 if (!recvObj->IsSendNextReq()) {
280 OBEX_LOG_DEBUG(
281 "GetDataAvailable: Srm mode is enabled. not send next request util received succeeded response!");
282 sendNextReq = false;
283 }
284 }
285 }
286 if (sendNextReq) {
287 OBEX_LOG_DEBUG("GetDataAvailable: send next get request");
288 int ret = SendRequest(*recvObj->GetContinueReqHeader());
289 if (ret != 0) {
290 OBEX_LOG_ERROR("GetDataAvailable: Send Continue Next request fail!");
291 }
292 }
293 }
294
ProcessGetSuccessData(const ObexHeader & resp)295 void ObexMpClient::ProcessGetSuccessData(const ObexHeader &resp)
296 {
297 OBEX_LOG_INFO("[%{public}s] Call %{public}s", GetClientId().c_str(), __PRETTY_FUNCTION__);
298 auto &recvObj = clientSession_->GetReceivedObject();
299 recvObj->CacheResp(resp);
300 auto body = resp.GetItemEndBody();
301 if (body != nullptr) {
302 recvObj->AppendBody(body->GetBytes().get(), body->GetHeaderDataSize());
303 }
304 recvObj->SetDone(true);
305 auto newRespHeader = recvObj->GetFirstRespHeader();
306 if (newRespHeader == nullptr) {
307 OBEX_LOG_ERROR("[%{public}s] Call %{public}s, newRespHeader is nullptr",
308 GetClientId().c_str(), __PRETTY_FUNCTION__);
309 return;
310 }
311 auto newResp = *newRespHeader;
312 newResp.SetRespCode(resp.GetFieldCode());
313 newResp.SetExtendBodyObject(recvObj->GetBodyWriter());
314 ObexClient::GetDataAvailable(newResp);
315 clientSession_->FreeReceivedObject();
316 }
317
SetPathDataAvailable(const ObexHeader & resp)318 void ObexMpClient::SetPathDataAvailable(const ObexHeader &resp)
319 {
320 OBEX_LOG_INFO("[%{public}s] Call %{public}s", GetClientId().c_str(), __PRETTY_FUNCTION__);
321 if (resp.GetFieldCode() == static_cast<uint8_t>(ObexRspCode::SUCCESS)) {
322 auto &setPathObject = clientSession_->GetSetPathObject();
323 if (setPathObject != nullptr && !setPathObject->IsDone()) {
324 int ret = ObexClient::SetPath(OBEX_SETPATH_NOCREATE, setPathObject->GetNextPath());
325 if (ret != 0) {
326 clientSession_->FreeSetPathObject();
327 clientObserver_.OnTransportFailed(*this, -1);
328 }
329 return;
330 }
331 }
332 clientSession_->FreeSetPathObject();
333 ObexClient::SetPathDataAvailable(resp);
334 }
335
AbortDataAvailable(const ObexHeader & resp)336 void ObexMpClient::AbortDataAvailable(const ObexHeader &resp)
337 {
338 OBEX_LOG_INFO("[%{public}s] Call %{public}s", GetClientId().c_str(), __PRETTY_FUNCTION__);
339 isWaitingSendAbort_ = false;
340 isAbortSended_ = false;
341 clientSession_->FreeReceivedObject();
342 clientSession_->FreeSendObject();
343 ObexClient::AbortDataAvailable(resp);
344 }
345
HandleTransportDataBusy(uint8_t isBusy)346 void ObexMpClient::HandleTransportDataBusy(uint8_t isBusy)
347 {
348 OBEX_LOG_INFO("[%{public}s] Call %{public}s, isBusy %u", GetClientId().c_str(), __PRETTY_FUNCTION__, isBusy);
349 auto &sendObject = clientSession_->GetSendObject();
350 if (!sendObject) {
351 return;
352 }
353 bool oldBusy = sendObject->IsBusy();
354 bool newBusy = (isBusy == 0x01);
355 sendObject->SetBusy(newBusy);
356 // busy -> not busy , srm data is sending
357 if (oldBusy && !newBusy && sendObject->IsSrmSending()) {
358 OBEX_LOG_DEBUG("Transport change to not busy, continue send srm request data.");
359 ProcessSendPutWithSrm();
360 }
361 }
362 } // namespace bluetooth
363 } // namespace OHOS