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 #ifndef OBEX_CLIENT_H
17 #define OBEX_CLIENT_H
18 
19 #include <cstdint>
20 #include <cstring>
21 #include "btstack.h"
22 #include "dispatcher.h"
23 #include "obex_body.h"
24 #include "obex_headers.h"
25 #include "obex_session.h"
26 #include "obex_transport.h"
27 #include "obex_types.h"
28 
29 namespace OHOS {
30 namespace bluetooth {
31 enum class ObexClientState : uint8_t {
32     INIT = 0,
33     TRANSPORT_CONNECTED,
34     RELIABLE_SESSION_CREATED,
35     OBEX_CONNECTED,
36     OBEX_DISCONNECTED,
37     RELIABLE_SESSION_SUSPENDED,
38     RELIABLE_SESSION_RESUMED,
39     RELIABLE_SESSION_CLOSED,
40     TRANSPORT_DISCONNECTED
41 };
42 
43 struct ObexClientConfig {
44     BtAddr addr_ {};                         // Remote bluetooth address
45     uint16_t lpsm_ = 0;                      // l2cap's local psm while use l2cap
46     uint16_t scn_ = 0;                       // Rfcomm's channel num/ l2cap's psm
47     uint16_t mtu_ = 0;                       // The Maximum OBEX Packet Length.Default 1024byte
48     bool isGoepL2capPSM_ = false;            // L2cap:true, rfcomm:false
49     bool isSupportSrm_ = false;              // Using Single Response Mode
50     bool isSupportReliableSession_ = false;  // Using reliable session
51     BtUuid serviceUUID_ {};                  // Service's UUID128
52 };
53 
54 struct ObexConnectParams {
55     ObexTlvParamters *appParams_ = nullptr;          // Application Parameters
56     ObexDigestChallenge *authChallenges_ = nullptr;  // Auth Challenges
57     ObexDigestResponse *authResponses_ = nullptr;    // Auth Responses
58     uint32_t *count = nullptr;                      // Count
59 };
60 
61 class ObexClient;
62 /**
63  * @brief Callback function \n
64  * used to notify the upper layer of the event and related information.
65  */
66 class ObexClientObserver {
67 public:
68     virtual ~ObexClientObserver() = default;
69     /**
70      * @brief Called OnTransportFailed
71      * @param client ObexClient
72      * @param errCd error code
73      */
74     virtual void OnTransportFailed(ObexClient &client, int errCd) = 0;
75     /**
76      * @brief Called OnConnected
77      *
78      * @param client ObexClient
79      * @param resp The Response from Server
80      */
81     virtual void OnConnected(ObexClient &client, const ObexHeader &resp) = 0;
82     /**
83      * @brief Called OnConnectFailed
84      *
85      * @param client ObexClient
86      * @param resp The Response from Server
87      */
88     virtual void OnConnectFailed(ObexClient &client, const ObexHeader &resp) = 0;
89     /**
90      * @brief Called OnDisconnected
91      *
92      * @param client ObexClient
93      */
94     virtual void OnDisconnected(ObexClient &client) = 0;
95     /**
96      * @brief Called OnActionCompleted
97      *
98      * @param client ObexClient
99      * @param resp The Response from Server
100      */
101     virtual void OnActionCompleted(ObexClient &client, const ObexHeader &resp) = 0;
102     /**
103      * @brief Called OnBusy
104      *
105      * @param client ObexClient
106      * @param isBusy true:become busy false:become not busy
107      */
108     virtual void OnBusy(ObexClient &client, bool isBusy);
109 };
110 
111 /**
112  *  @brief ObexClient\n
113  *  ObexClient
114  */
115 class ObexClient {
116 public:
117     // create obex client
118     explicit ObexClient(const ObexClientConfig &config, ObexClientObserver &observer, utility::Dispatcher &dispatcher);
119 
120     // destroy obex client
121     virtual ~ObexClient() = default;
122 
123     /**
124      * @brief send obex request
125      *
126      * @param req the data of obex request
127      * @return int Request processing result:0:succeeded -1:failed
128      */
129     int SendRequest(const ObexHeader &req);
130 
131     /**
132      * @brief send obex connect request
133      *
134      * @return int Request processing result:0:succeeded -1:failed
135      */
136     int Connect();
137     /**
138      * @brief send obex connect request with Parameters
139      *
140      * @param connectParams Connect Parameters
141      * @return int Request processing result:0:succeeded -1:failed
142      */
143     int Connect(ObexConnectParams &connectParams);
144     /**
145      * @brief send obex disconnect request
146      * @param withObexReq is send obex disconnect request
147      * @return int Request processing result:0:succeeded -1:failed
148      */
149     int Disconnect(bool withObexReq = true);
150     /**
151      * @brief send obex abort request
152      *
153      * @return int Request processing result:0:succeeded -1:failed
154      */
155     int Abort();
156 
157     /**
158      * @brief send obex put request
159      *
160      * @param req the data of obex request
161      * @return int Request processing result:0:succeeded -1:failed
162      */
163     int Put(const ObexHeader &req);
164 
165     /**
166      * @brief send obex get request
167      *
168      * @param req the data of obex request for get
169      * @return int Request processing result:0:succeeded -1:failed
170      */
171     int Get(const ObexHeader &req);
172 
173     /**
174      * @brief send obex set_path request
175      *
176      * @param flag SETPATH flag \n
177      *             bit 0:backup a level before applying name (equivalent to ../ on many systems)\n
178      *                   @see OBEX_SETPATH_BACKUP
179      *             bit 1:Don’t create folder if it does not exist, return an error instead.
180      *                   @see OBEX_SETPATH_NOCREATE
181      * @param path path
182      * @return int Request processing result:0:succeeded -1:failed
183      */
184     int SetPath(uint8_t flag, const std::u16string &path);
185 
186     /**
187      * @brief send obex copy action request
188      *
189      * @param srcName Copy source name
190      * @param destName Copy destination name
191      * @return int Request processing result:0:succeeded -1:failed
192      */
193     int Copy(const std::u16string &srcName, const std::u16string &destName);
194     /**
195      * @brief send obex move action request
196      *
197      * @param srcName Move source name
198      * @param destName Move destination name
199      * @return int Request processing result:0:succeeded -1:failed
200      */
201     int Move(const std::u16string &srcName, const std::u16string &destName);
202     /**
203      * @brief send obex set permissions action request
204      *
205      * @param name Indicates the name of the object to perform the action upon.
206      * @param permissions Indicates the permissions for a Set Permissions action.
207      * @return int Request processing result:0:succeeded -1:failed
208      */
209     int SetPermissions(const std::u16string &name, const uint32_t permissions);
210 
211     /**
212      * @brief send obex CREATESESSION request \n
213      * The CREATESESSION command is sent by the Client to create a new session.
214      * @return int Request processing result:0:succeeded -1:failed
215      */
216     int CreateSession();
217     /**
218      * @brief send obex CREATESESSION request \n
219      * The CREATESESSION command is sent by the Client to create a new session.
220      * @param timeoutSec  timeout specifying the number of seconds.
221      *                    default is OBEX_SESSION_MAX_TIMEOUT_SEC
222      * @return int Request processing result:0:succeeded -1:failed
223      */
224     static int CreateSession(uint32_t timeoutSec);
225 
226     /**
227      * @brief send obex SUSPENDSESSION request \n
228      * SUSPENDSESSION is used to gracefully suspend the active session.
229      * @return int Request processing result:0:succeeded -1:failed
230      */
231     static int SuspendSession();
232 
233     /**
234      * @brief send obex RESUMESESSION request \n
235      * RESUMESESSION is used to resume a session that has been suspended.
236      * @return int Request processing result:0:succeeded -1:failed
237      */
238     static int ResumeSession();
239 
240     /**
241      * @brief send obex CLOSESESSION request \n
242      * CLOSESESSION is used to gracefully close an existing session.
243      * @return int Request processing result:0:succeeded -1:failed
244      */
245     static int CloseSession();
246 
247     /**
248      * @brief send obex SETTIMEOUT request \n
249      * The SETTIMEOUT command is used to negotiate a new timeout specifying the number of seconds a \n
250      * session should be maintained while the session is suspended.
251      * @param timeoutSec timeout specifying the number of seconds
252      * @return int Request processing result:0:succeeded -1:failed
253      */
254     static int SetSessionTimeout(uint32_t timeoutSec = OBEX_SESSION_MAX_TIMEOUT_SEC);
255 
256     // Get ClientSession
257     ObexClientSession &GetClientSession() const;
258 
259     // Get GetClientId
260     const std::string &GetClientId();
261 
262     static int RegisterL2capLPsm(uint16_t lpsm);
263     static void DeregisterL2capLPsm(uint16_t lpsm);
264 
265 protected:
266     // Client Transport Obsverver
267     class ObexClientTransportObserver : public ObexTransportObserver {
268     public:
269         explicit ObexClientTransportObserver(ObexClient &obexClient);
270         ~ObexClientTransportObserver() override = default;
271         // call back from transport
272         void OnTransportConnected(ObexTransport &transport) override;
273         void OnTransportDisconnected(ObexTransport &transport) override;
274         void OnTransportDataAvailable(ObexTransport &transport, ObexPacket &obexPacket) override;
275         void OnTransportDataBusy(ObexTransport &transport, uint8_t isBusy) override;
276         void OnTransportError(ObexTransport &transport, int errCd) override;
277 
278     private:
279         ObexClient &obexClient_;
280         std::unique_ptr<bluetooth::ObexHeader> GetObexHeaderFromPacket(ObexPacket &obexPacket);
281         void HandleDataAvailableConnect(const ObexHeader &resp);
282         void HandleDataAvailableDisconnect(const ObexHeader &resp);
283         void HandleDataAvailablePut(const ObexHeader &resp);
284         void HandleDataAvailableGet(const ObexHeader &resp);
285         void HandleDataAvailableSetPath(const ObexHeader &resp);
286         void HandleDataAvailableSession(const ObexHeader &resp);
287         void HandleDataAvailableAbort(const ObexHeader &resp);
288         void HandleDataAvailableAction(const ObexHeader &resp);
289         BT_DISALLOW_COPY_AND_ASSIGN(ObexClientTransportObserver);
290     };
291 
292     int ProcessAbort();
293     int SendAbortRequest();
294     int SendConnectRequest(ObexHeader &header);
295     bool CheckBeforeRequest(uint8_t opeId) const;
296     static bool CheckBeforeSession(uint8_t sessionOpcode);
297     virtual void PutDataAvailable(const ObexHeader &resp);
298     virtual void GetDataAvailable(const ObexHeader &resp);
299     virtual void SetPathDataAvailable(const ObexHeader &resp);
300     virtual void AbortDataAvailable(const ObexHeader &resp);
301     virtual void HandleTransportDataBusy(uint8_t isBusy);
302     virtual void SetBusy(bool isBusy);
303     std::unique_ptr<ObexClientTransportObserver> transportObserver_ = nullptr;
304     std::unique_ptr<ObexClientSession> clientSession_ = nullptr;
305     std::unique_ptr<ObexClientTransport> clientTransport_ = nullptr;
306     std::unique_ptr<ObexHeader> connectReqHeader_ = nullptr;
307     std::unique_ptr<ObexHeader> reliableSessionReqHeader_ = nullptr;
308     ObexClientObserver &clientObserver_;
309     ObexClientState clientState_ = ObexClientState::INIT;
310     bool isObexConnected_ = false;
311     bool isWaitingSendAbort_ = false;
312     bool isAbortSended_ = false;
313     bool isReliableSessionCreated_ = false;
314     bool isSupportSrm_ = false;
315     bool isSupportReliableSession_ = false;
316     bool isProcessing_ = false;
317     std::string clientId_ = "";
318     utility::Dispatcher &dispatcher_;
319     BT_DISALLOW_COPY_AND_ASSIGN(ObexClient);
320 };
321 }  // namespace bluetooth
322 }  // namespace OHOS
323 #endif  // OBEX_CLIENT_H