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