1 /*
2  * Copyright (c) 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 SOFT_BUS_CHANNEL_H
17 #define SOFT_BUS_CHANNEL_H
18 
19 #include <atomic>
20 #include <condition_variable>
21 #include <mutex>
22 #include <memory>
23 #include <map>
24 #include <securec.h>
25 #include <string>
26 #include <zlib.h>
27 
28 #include "accesstoken_log.h"
29 #include "nlohmann/json.hpp"
30 #include "rpc_channel.h"
31 #include "socket.h"
32 #include "random.h"
33 
34 namespace OHOS {
35 namespace Security {
36 namespace AccessToken {
37 struct BytesInfo {
38     unsigned char *bytes;
39     int bytesLength;
40 };
41 
42 class SoftBusChannel final : public RpcChannel, public std::enable_shared_from_this<SoftBusChannel> {
43 public:
44     explicit SoftBusChannel(const std::string &deviceId);
45     virtual ~SoftBusChannel();
46 
47     /**
48      * @brief Build connection with peer device.
49      *
50      * @return Result code, 0 indicated build successfully, -1 indicates failure.
51      * @since 1.0
52      * @version 1.0
53      * @see Release
54      */
55     int BuildConnection() override;
56 
57     void InsertCallback(int result, std::string &uuid);
58 
59     /**
60      * @brief Execute BaseRemoteCommand at peer device.
61      *
62      * @param commandName The name of Command.
63      * @param jsonPayload The json payload of command.
64      * @return Executed result response string.
65      * @since 1.0
66      * @version 1.0
67      */
68     std::string ExecuteCommand(const std::string &commandName, const std::string &jsonPayload) override;
69 
70     /**
71      * @brief Handle data received. This interface only use for soft bus channel.
72      *
73      * @param socket Session with peer device.
74      * @param bytes Data sent from the peer device.
75      * @param length Data length sent from the peer device.
76      * @since 1.0
77      * @version 1.0
78      */
79     void HandleDataReceived(int socket, const unsigned char *bytes, int length) override;
80 
81     /**
82      * @brief Close rpc connection when no data is being transmitted. it will run in a delayed task.
83      *
84      * @since 1.0
85      * @version 1.0
86      */
87     void CloseConnection() override;
88 
89     /**
90      * @brief Release resources when the device offline.
91      *
92      * @since 1.0
93      * @version 1.0
94      */
95     void Release() override;
96 
97 private:
98     /**
99      * @brief compress json command to char array command.
100      *
101      * @param type request or response
102      * @param id unique message id
103      * @param commandName command name
104      * @param jsonPayload command notated by json string
105      * @param bytes transfer data array
106      * @param bytesLength transfer data length
107      * @return The execute result, SUCCESS: 0; FAILURE: -1.
108      * @see Compress
109      * @since 1.0
110      * @version 1.0
111      */
112     int PrepareBytes(const std::string &type, const std::string &id, const std::string &commandName,
113         const std::string &jsonPayload, BytesInfo &info);
114 
115     /**
116      * @brief compress string to char array.
117      *
118      * @param json string to be compressed
119      * @param compressedBytes compressed data array
120      * @param compressedLength compressed data length
121      * @return The execute result, SUCCESS: 0; FAILURE: -1.
122      * @since 1.0
123      * @version 1.0
124      */
125     int Compress(const std::string &json, const unsigned char *compressedBytes, int &compressedLength);
126 
127     /**
128      * @brief decompress char array to string.
129      *
130      * @param bytes compressed data array
131      * @param length compressed data length
132      * @return decompressed string
133      * @since 1.0
134      * @version 1.0
135      */
136     std::string Decompress(const unsigned char *bytes, const int length);
137 
138     /**
139      * @brief transfer request data to soft bus.
140      *
141      * @param bytes data array to transfer
142      * @param bytesLength data length
143      * @return The execute result, SUCCESS: 0; FAILURE: -1.
144      * @since 1.0
145      * @version 1.0
146      */
147     int SendRequestBytes(const unsigned char *bytes, const int bytesLength);
148 
149     /**
150      * @brief transfer response data to soft bus.
151      *
152      * @param socket response socket id
153      * @param bytes data array to transfer
154      * @param bytesLength data length
155      * @return The execute result, SUCCESS: 0; FAILURE: -1.
156      * @since 1.0
157      * @version 1.0
158      */
159     int SendResponseBytes(int socket, const unsigned char *bytes, const int bytesLength);
160 
161     /**
162      * @brief enforce socket is available. if socket is opened, reopen it.
163      *
164      * @return The execute result, SUCCESS: 0; FAILURE: -1.
165      * @since 1.0
166      * @version 1.0
167      */
168     int CheckSessionMayReopenLocked();
169 
170     /**
171      * @brief check socket is available.
172      *
173      * @return The execute result, available: true, otherwise: false.
174      * @since 1.0
175      * @version 1.0
176      */
177     bool IsSessionAvailable();
178 
179     /**
180      * @brief cancel closing connection.
181      *
182      * @since 1.0
183      * @version 1.0
184      */
185     void CancelCloseConnectionIfNeeded();
186 
187     /**
188      * @brief request callback for HandleDataReceived
189      *
190      * @param id unique message id
191      * @param commandName command name
192      * @param jsonPayload command notated by json string
193      * @return decompressed string
194      * @see HandleDataReceived
195      * @since 1.0
196      * @version 1.0
197      */
198     void HandleRequest(
199         int socket, const std::string &id, const std::string &commandName, const std::string &jsonPayload);
200 
201     /**
202      * @brief response callback for HandleDataReceived
203      *
204      * @param id unique message id
205      * @param jsonPayload command notated by json string
206      * @return decompressed string
207      * @see HandleDataReceived
208      * @since 1.0
209      * @version 1.0
210      */
211     void HandleResponse(const std::string &id, const std::string &jsonPayload);
212 
213     /**
214      * @brief Get uuid.
215      *
216      * @return uuid.
217      * @since 1.0
218      * @version 1.0
219      */
220     std::string GetUuid();
221 
222     /**
223      * @brief temp function to generate uuid.
224      *
225      * @param buf uuid string
226      * @param bufSize uuid string size
227      * @since 1.0
228      * @version 1.0
229      */
RandomUuid(char buf[37],int bufSize)230     void RandomUuid(char buf[37], int bufSize)
231     {
232         const int xbase = 15;
233         const int bbase = 255;
234         const int index6 = 6;
235         const int index8 = 8;
236         const int index3 = 3;
237         const int index5 = 5;
238         const int index7 = 7;
239         const int index9 = 9;
240         const int blen = 2;
241         const int uuidlen = 16;
242         const char *c = "89ab";
243         char *p = buf;
244         int n;
245 
246         for (n = 0; n < uuidlen; ++n) {
247             int b = static_cast<int32_t>(GetRandomUint32() % bbase);
248             switch (n) {
249                 case index6:
250                     if (sprintf_s(p, bufSize, "4%x", b % xbase) < 0) {
251                         return;
252                     }
253                     break;
254                 case index8:
255                     if (sprintf_s(p, bufSize, "%c%x", c[GetRandomUint32() % strlen(c)], b % xbase) < 0) {
256                         return;
257                     }
258                     break;
259                 default:
260                     if (sprintf_s(p, bufSize, "%02x", b) < 0) {
261                         return;
262                     }
263                     break;
264             }
265             p += blen;
266             if (n == index3 || n == index5 || n == index7 || n == index9) {
267                 *p++ = '-';
268                 break;
269             }
270         }
271         *p = 0;
272         // prevent array length warning
273         if (p - buf == bufSize) {
274             return;
275         }
276     }
277 
278     // bind device id for this channel
279     std::string deviceId_;
280 
281     // channel mutex
282     std::mutex mutex_;
283 
284     // connection closing state. true: in closing, false: otherwise
285     bool isDelayClosing_;
286 
287     // soft bus socket mutex
288     std::mutex socketMutex_;
289 
290     // soft bus socket id, -1 for invalid socket id.
291     int socketFd_;
292 
293     // soft bus socket busy flag, true: busy, false: otherwise
294     bool isSocketUsing_;
295 
296     // communication callbacks map. key: unique message id, value: response callback.
297     std::map<std::string, std::function<void(std::string)>> callbacks_;
298 
299     // callback function arguments: response string variable
300     std::string responseResult_;
301     // callback function execute variable
302     std::condition_variable loadedCond_;
303 };
304 
305 class SoftBusMessage {
306 public:
SoftBusMessage(const std::string & type,const std::string & id,const std::string & commandName,const std::string & jsonPayload)307     SoftBusMessage(
308         const std::string &type, const std::string &id, const std::string &commandName, const std::string &jsonPayload)
309         : type_(type), id_(id), commandName_(commandName), jsonPayload_(jsonPayload)
310     {}
311     ~SoftBusMessage() = default;
312 
IsValid()313     bool IsValid() const
314     {
315         if (this->type_.empty()) {
316             return false;
317         }
318         if (this->id_.empty()) {
319             return false;
320         }
321         if (this->commandName_.empty()) {
322             return false;
323         }
324         return !(this->jsonPayload_.empty());
325     }
326 
327     /**
328      * Convert SoftBusMessage object to corresponding json string.
329      *
330      * @return Soft bus message json string.
331      */
ToJson()332     std::string ToJson() const
333     {
334         nlohmann::json json;
335         json["type"] = this->type_;
336         json["id"] = this->id_;
337         json["commandName"] = this->commandName_;
338         json["jsonPayload"] = this->jsonPayload_;
339         return json.dump();
340     }
341 
GetType()342     const std::string &GetType() const
343     {
344         return type_;
345     }
GetId()346     const std::string &GetId() const
347     {
348         return id_;
349     }
GetCommandName()350     const std::string &GetCommandName() const
351     {
352         return commandName_;
353     }
GetJsonPayload()354     const std::string &GetJsonPayload() const
355     {
356         return jsonPayload_;
357     }
358 
359     static std::shared_ptr<SoftBusMessage> FromJson(const std::string &jsonString);
360 private:
361     std::string type_;
362     std::string id_;
363     std::string commandName_;
364     std::string jsonPayload_;
365 };
366 }  // namespace AccessToken
367 }  // namespace Security
368 }  // namespace OHOS
369 
370 #endif  // SOFT_BUS_CHANNEL_H
371