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 #include "soft_bus_channel.h"
16 
17 #include <securec.h>
18 
19 #include "constant_common.h"
20 #include "device_info_manager.h"
21 #ifdef EVENTHANDLER_ENABLE
22 #include "access_event_handler.h"
23 #endif
24 #include "token_sync_manager_service.h"
25 #include "singleton.h"
26 #include "soft_bus_manager.h"
27 
28 namespace OHOS {
29 namespace Security {
30 namespace AccessToken {
31 namespace {
32 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, SECURITY_DOMAIN_ACCESSTOKEN, "SoftBusChannel"};
33 }
34 namespace {
35 static const std::string REQUEST_TYPE = "request";
36 static const std::string RESPONSE_TYPE = "response";
37 static const std::string TASK_NAME_CLOSE_SESSION = "atm_soft_bus_channel_close_session";
38 static const int32_t EXECUTE_COMMAND_TIME_OUT = 3000;
39 static const int32_t WAIT_SESSION_CLOSE_MILLISECONDS = 5 * 1000;
40 // send buf size for header
41 static const int RPC_TRANSFER_HEAD_BYTES_LENGTH = 1024 * 256;
42 // decompress buf size
43 static const int RPC_TRANSFER_BYTES_MAX_LENGTH = 1024 * 1024;
44 } // namespace
SoftBusChannel(const std::string & deviceId)45 SoftBusChannel::SoftBusChannel(const std::string &deviceId)
46     : deviceId_(deviceId), mutex_(), callbacks_(), responseResult_(""), loadedCond_()
47 {
48     ACCESSTOKEN_LOG_DEBUG(LABEL, "SoftBusChannel(deviceId)");
49     isDelayClosing_ = false;
50     socketFd_ = Constant::INVALID_SOCKET_FD;
51     isSocketUsing_ = false;
52 }
53 
~SoftBusChannel()54 SoftBusChannel::~SoftBusChannel()
55 {
56     ACCESSTOKEN_LOG_DEBUG(LABEL, "~SoftBusChannel()");
57 }
58 
BuildConnection()59 int SoftBusChannel::BuildConnection()
60 {
61     CancelCloseConnectionIfNeeded();
62 
63     std::unique_lock<std::mutex> lock(socketMutex_);
64     if (socketFd_ != Constant::INVALID_SOCKET_FD) {
65         ACCESSTOKEN_LOG_INFO(LABEL, "Socket is exist, no need open again.");
66         return Constant::SUCCESS;
67     }
68 
69     if (socketFd_ == Constant::INVALID_SOCKET_FD) {
70         ACCESSTOKEN_LOG_INFO(LABEL, "Bind service with device: %{public}s",
71             ConstantCommon::EncryptDevId(deviceId_).c_str());
72         int socket = SoftBusManager::GetInstance().BindService(deviceId_);
73         if (socket == Constant::INVALID_SOCKET_FD) {
74             ACCESSTOKEN_LOG_ERROR(LABEL, "Bind service failed.");
75             return Constant::FAILURE;
76         }
77         socketFd_ = socket;
78     }
79     return Constant::SUCCESS;
80 }
81 
CloseConnection()82 void SoftBusChannel::CloseConnection()
83 {
84     ACCESSTOKEN_LOG_DEBUG(LABEL, "Close connection");
85     std::unique_lock<std::mutex> lock(mutex_);
86     if (isDelayClosing_) {
87         return;
88     }
89 
90 #ifdef EVENTHANDLER_ENABLE
91     std::shared_ptr<AccessEventHandler> handler =
92         DelayedSingleton<TokenSyncManagerService>::GetInstance()->GetSendEventHandler();
93     if (handler == nullptr) {
94         ACCESSTOKEN_LOG_ERROR(LABEL, "Fail to get EventHandler");
95         return;
96     }
97 #endif
98     std::weak_ptr<SoftBusChannel> weakPtr = shared_from_this();
99     std::function<void()> delayed = ([weakPtr]() {
100         auto self = weakPtr.lock();
101         if (self == nullptr) {
102             ACCESSTOKEN_LOG_ERROR(LABEL, "SoftBusChannel is nullptr");
103             return;
104         }
105         std::unique_lock<std::mutex> lock(self->socketMutex_);
106         if (self->isSocketUsing_) {
107             ACCESSTOKEN_LOG_DEBUG(LABEL, "Socket is in using, cancel close socket");
108         } else {
109             SoftBusManager::GetInstance().CloseSocket(self->socketFd_);
110             self->socketFd_ = Constant::INVALID_SESSION;
111             ACCESSTOKEN_LOG_INFO(LABEL, "Close socket for device: %{public}s",
112                 ConstantCommon::EncryptDevId(self->deviceId_).c_str());
113         }
114         self->isDelayClosing_ = false;
115     });
116 
117     ACCESSTOKEN_LOG_DEBUG(LABEL, "Close socket after %{public}d ms", WAIT_SESSION_CLOSE_MILLISECONDS);
118 #ifdef EVENTHANDLER_ENABLE
119     handler->ProxyPostTask(delayed, TASK_NAME_CLOSE_SESSION, WAIT_SESSION_CLOSE_MILLISECONDS);
120 #endif
121 
122     isDelayClosing_ = true;
123 }
124 
Release()125 void SoftBusChannel::Release()
126 {
127 #ifdef EVENTHANDLER_ENABLE
128     std::shared_ptr<AccessEventHandler> handler =
129         DelayedSingleton<TokenSyncManagerService>::GetInstance()->GetSendEventHandler();
130     if (handler == nullptr) {
131         ACCESSTOKEN_LOG_ERROR(LABEL, "Fail to get EventHandler");
132         return;
133     }
134     handler->ProxyRemoveTask(TASK_NAME_CLOSE_SESSION);
135 #endif
136 }
137 
GetUuid()138 std::string SoftBusChannel::GetUuid()
139 {
140     // to use a lib like libuuid
141     int uuidStrLen = 37; // 32+4+1
142     char uuidbuf[uuidStrLen];
143     RandomUuid(uuidbuf, uuidStrLen);
144     std::string uuid(uuidbuf);
145     ACCESSTOKEN_LOG_DEBUG(LABEL, "Generated message uuid: %{public}s", ConstantCommon::EncryptDevId(uuid).c_str());
146 
147     return uuid;
148 }
149 
InsertCallback(int result,std::string & uuid)150 void SoftBusChannel::InsertCallback(int result, std::string &uuid)
151 {
152     std::unique_lock<std::mutex> lock(socketMutex_);
153     std::function<void(const std::string &)> callback = [this](const std::string &result) {
154         responseResult_ = std::string(result);
155         loadedCond_.notify_all();
156         ACCESSTOKEN_LOG_DEBUG(LABEL, "OnResponse called end");
157     };
158     callbacks_.insert(std::pair<std::string, std::function<void(std::string)>>(uuid, callback));
159 
160     isSocketUsing_ = true;
161     lock.unlock();
162 }
163 
ExecuteCommand(const std::string & commandName,const std::string & jsonPayload)164 std::string SoftBusChannel::ExecuteCommand(const std::string &commandName, const std::string &jsonPayload)
165 {
166     if (commandName.empty() || jsonPayload.empty()) {
167         ACCESSTOKEN_LOG_ERROR(LABEL, "Invalid params, commandName: %{public}s", commandName.c_str());
168         return "";
169     }
170 
171     std::string uuid = GetUuid();
172 
173     int len = static_cast<int32_t>(RPC_TRANSFER_HEAD_BYTES_LENGTH + jsonPayload.length());
174     unsigned char *buf = new (std::nothrow) unsigned char[len + 1];
175     if (buf == nullptr) {
176         ACCESSTOKEN_LOG_ERROR(LABEL, "No enough memory: %{public}d", len);
177         return "";
178     }
179     (void)memset_s(buf, len + 1, 0, len + 1);
180     BytesInfo info;
181     info.bytes = buf;
182     info.bytesLength = len;
183     int result = PrepareBytes(REQUEST_TYPE, uuid, commandName, jsonPayload, info);
184     if (result != Constant::SUCCESS) {
185         delete[] buf;
186         return "";
187     }
188     InsertCallback(result, uuid);
189     int retCode = SendRequestBytes(buf, info.bytesLength);
190     delete[] buf;
191 
192     std::unique_lock<std::mutex> lock2(socketMutex_);
193     if (retCode != Constant::SUCCESS) {
194         ACCESSTOKEN_LOG_ERROR(LABEL, "Send request data failed: %{public}d ", retCode);
195         callbacks_.erase(uuid);
196         isSocketUsing_ = false;
197         return "";
198     }
199 
200     ACCESSTOKEN_LOG_DEBUG(LABEL, "Wait command response");
201     if (loadedCond_.wait_for(lock2, std::chrono::milliseconds(EXECUTE_COMMAND_TIME_OUT)) == std::cv_status::timeout) {
202         ACCESSTOKEN_LOG_WARN(LABEL, "Time out to wait response.");
203         callbacks_.erase(uuid);
204         isSocketUsing_ = false;
205         return "";
206     }
207 
208     isSocketUsing_ = false;
209     return responseResult_;
210 }
211 
HandleDataReceived(int socket,const unsigned char * bytes,int length)212 void SoftBusChannel::HandleDataReceived(int socket, const unsigned char *bytes, int length)
213 {
214     ACCESSTOKEN_LOG_DEBUG(LABEL, "HandleDataReceived");
215 #ifdef DEBUG_API_PERFORMANCE
216     ACCESSTOKEN_LOG_INFO(LABEL, "Api_performance:recieve message from softbus");
217 #endif
218     if (socket <= 0 || length <= 0) {
219         ACCESSTOKEN_LOG_ERROR(LABEL, "Invalid params: socket: %{public}d, data length: %{public}d", socket, length);
220         return;
221     }
222     std::string receiveData = Decompress(bytes, length);
223     if (receiveData.empty()) {
224         ACCESSTOKEN_LOG_ERROR(LABEL, "Invalid parameter bytes");
225         return;
226     }
227     std::shared_ptr<SoftBusMessage> message = SoftBusMessage::FromJson(receiveData);
228     if (message == nullptr) {
229         ACCESSTOKEN_LOG_DEBUG(LABEL, "Invalid json string");
230         return;
231     }
232     if (!message->IsValid()) {
233         ACCESSTOKEN_LOG_DEBUG(LABEL, "Invalid data, has empty field");
234         return;
235     }
236 
237     std::string type = message->GetType();
238     if (REQUEST_TYPE == (type)) {
239         std::function<void()> delayed = ([weak = weak_from_this(), socket, message]() {
240             auto self = weak.lock();
241             if (self == nullptr) {
242                 ACCESSTOKEN_LOG_ERROR(LABEL, "SoftBusChannel is nullptr");
243                 return;
244             }
245             self->HandleRequest(socket, message->GetId(), message->GetCommandName(), message->GetJsonPayload());
246         });
247 
248 #ifdef EVENTHANDLER_ENABLE
249         std::shared_ptr<AccessEventHandler> handler =
250             DelayedSingleton<TokenSyncManagerService>::GetInstance()->GetRecvEventHandler();
251         if (handler == nullptr) {
252             ACCESSTOKEN_LOG_ERROR(LABEL, "Fail to get EventHandler");
253             return;
254         }
255         handler->ProxyPostTask(delayed, "HandleDataReceived_HandleRequest");
256 #endif
257     } else if (RESPONSE_TYPE == (type)) {
258         HandleResponse(message->GetId(), message->GetJsonPayload());
259     } else {
260         ACCESSTOKEN_LOG_ERROR(LABEL, "Invalid type: %{public}s ", type.c_str());
261     }
262 }
263 
PrepareBytes(const std::string & type,const std::string & id,const std::string & commandName,const std::string & jsonPayload,BytesInfo & info)264 int SoftBusChannel::PrepareBytes(const std::string &type, const std::string &id, const std::string &commandName,
265     const std::string &jsonPayload, BytesInfo &info)
266 {
267     SoftBusMessage messageEntity(type, id, commandName, jsonPayload);
268     std::string json = messageEntity.ToJson();
269     return Compress(json, info.bytes, info.bytesLength);
270 }
271 
Compress(const std::string & json,const unsigned char * compressedBytes,int & compressedLength)272 int SoftBusChannel::Compress(const std::string &json, const unsigned char *compressedBytes, int &compressedLength)
273 {
274     uLong len = compressBound(json.size());
275     // length will not so that long
276     if (compressedLength > 0 && static_cast<int32_t>(len) > compressedLength) {
277         ACCESSTOKEN_LOG_ERROR(LABEL,
278             "compress error. data length overflow, bound length: %{public}d, buffer length: %{public}d",
279             static_cast<int32_t>(len), compressedLength);
280         return Constant::FAILURE;
281     }
282 
283     int result = compress(const_cast<Byte *>(compressedBytes), &len,
284         reinterpret_cast<unsigned char *>(const_cast<char *>(json.c_str())), json.size() + 1);
285     if (result != Z_OK) {
286         ACCESSTOKEN_LOG_ERROR(LABEL, "Compress failed! error code: %{public}d", result);
287         return result;
288     }
289     ACCESSTOKEN_LOG_DEBUG(LABEL, "Compress complete. compress %{public}d bytes to %{public}d", compressedLength,
290         static_cast<int32_t>(len));
291     compressedLength = static_cast<int32_t>(len);
292     return Constant::SUCCESS;
293 }
294 
Decompress(const unsigned char * bytes,const int length)295 std::string SoftBusChannel::Decompress(const unsigned char *bytes, const int length)
296 {
297     ACCESSTOKEN_LOG_DEBUG(LABEL, "Input length: %{public}d", length);
298     uLong len = RPC_TRANSFER_BYTES_MAX_LENGTH;
299     unsigned char *buf = new (std::nothrow) unsigned char[len + 1];
300     if (buf == nullptr) {
301         ACCESSTOKEN_LOG_ERROR(LABEL, "No enough memory!");
302         return "";
303     }
304     (void)memset_s(buf, len + 1, 0, len + 1);
305     int result = uncompress(buf, &len, const_cast<unsigned char *>(bytes), length);
306     if (result != Z_OK) {
307         ACCESSTOKEN_LOG_ERROR(LABEL,
308             "uncompress failed, error code: %{public}d, bound length: %{public}d, buffer length: %{public}d", result,
309             static_cast<int32_t>(len), length);
310         delete[] buf;
311         return "";
312     }
313     buf[len] = '\0';
314     std::string str(reinterpret_cast<char *>(buf));
315     delete[] buf;
316     return str;
317 }
318 
SendRequestBytes(const unsigned char * bytes,const int bytesLength)319 int SoftBusChannel::SendRequestBytes(const unsigned char *bytes, const int bytesLength)
320 {
321     if (bytesLength == 0) {
322         ACCESSTOKEN_LOG_ERROR(LABEL, "Bytes data is invalid.");
323         return Constant::FAILURE;
324     }
325 
326     std::unique_lock<std::mutex> lock(socketMutex_);
327     if (CheckSessionMayReopenLocked() != Constant::SUCCESS) {
328         ACCESSTOKEN_LOG_ERROR(LABEL, "Socket invalid and reopen failed!");
329         return Constant::FAILURE;
330     }
331 
332     ACCESSTOKEN_LOG_DEBUG(LABEL, "Send len (after compress len)= %{public}d", bytesLength);
333 #ifdef DEBUG_API_PERFORMANCE
334     ACCESSTOKEN_LOG_INFO(LABEL, "Api_performance:send command to softbus");
335 #endif
336     int result = ::SendBytes(socketFd_, bytes, bytesLength);
337     if (result != Constant::SUCCESS) {
338         ACCESSTOKEN_LOG_ERROR(LABEL, "Fail to send! result= %{public}d", result);
339         return Constant::FAILURE;
340     }
341     ACCESSTOKEN_LOG_DEBUG(LABEL, "Send successfully.");
342     return Constant::SUCCESS;
343 }
344 
CheckSessionMayReopenLocked()345 int SoftBusChannel::CheckSessionMayReopenLocked()
346 {
347     // when socket is opened, we got a valid sessionid, when socket closed, we will reset sessionid.
348     if (IsSessionAvailable()) {
349         return Constant::SUCCESS;
350     }
351     int socket = SoftBusManager::GetInstance().BindService(deviceId_);
352     if (socket != Constant::INVALID_SESSION) {
353         socketFd_ = socket;
354         return Constant::SUCCESS;
355     }
356     return Constant::FAILURE;
357 }
358 
IsSessionAvailable()359 bool SoftBusChannel::IsSessionAvailable()
360 {
361     return socketFd_ > Constant::INVALID_SESSION;
362 }
363 
CancelCloseConnectionIfNeeded()364 void SoftBusChannel::CancelCloseConnectionIfNeeded()
365 {
366     std::unique_lock<std::mutex> lock(mutex_);
367     if (!isDelayClosing_) {
368         return;
369     }
370     ACCESSTOKEN_LOG_DEBUG(LABEL, "Cancel close connection");
371 
372     Release();
373     isDelayClosing_ = false;
374 }
375 
HandleRequest(int socket,const std::string & id,const std::string & commandName,const std::string & jsonPayload)376 void SoftBusChannel::HandleRequest(int socket, const std::string &id, const std::string &commandName,
377     const std::string &jsonPayload)
378 {
379     std::shared_ptr<BaseRemoteCommand> command =
380         RemoteCommandFactory::GetInstance().NewRemoteCommandFromJson(commandName, jsonPayload);
381     if (command == nullptr) {
382         // send result back directly
383         ACCESSTOKEN_LOG_WARN(LABEL, "Command %{public}s cannot get from json", commandName.c_str());
384 
385         int sendlen = static_cast<int32_t>(RPC_TRANSFER_HEAD_BYTES_LENGTH + jsonPayload.length());
386         unsigned char *sendbuf = new (std::nothrow) unsigned char[sendlen + 1];
387         if (sendbuf == nullptr) {
388             ACCESSTOKEN_LOG_ERROR(LABEL, "No enough memory: %{public}d", sendlen);
389             return;
390         }
391         (void)memset_s(sendbuf, sendlen + 1, 0, sendlen + 1);
392         BytesInfo info;
393         info.bytes = sendbuf;
394         info.bytesLength = sendlen;
395         int sendResult = PrepareBytes(RESPONSE_TYPE, id, commandName, jsonPayload, info);
396         if (sendResult != Constant::SUCCESS) {
397             delete[] sendbuf;
398             return;
399         }
400         int sendResultCode = SendResponseBytes(socket, sendbuf, info.bytesLength);
401         delete[] sendbuf;
402         ACCESSTOKEN_LOG_DEBUG(LABEL, "Send response result= %{public}d ", sendResultCode);
403         return;
404     }
405 
406     // execute command
407     command->Execute();
408     ACCESSTOKEN_LOG_DEBUG(LABEL, "Command uniqueId: %{public}s, finish with status: %{public}d, message: %{public}s",
409         ConstantCommon::EncryptDevId(command->remoteProtocol_.uniqueId).c_str(), command->remoteProtocol_.statusCode,
410         command->remoteProtocol_.message.c_str());
411 
412     // send result back
413     std::string resultJsonPayload = command->ToJsonPayload();
414     int len = static_cast<int32_t>(RPC_TRANSFER_HEAD_BYTES_LENGTH + resultJsonPayload.length());
415     unsigned char *buf = new (std::nothrow) unsigned char[len + 1];
416     if (buf == nullptr) {
417         ACCESSTOKEN_LOG_ERROR(LABEL, "No enough memory: %{public}d", len);
418         return;
419     }
420     (void)memset_s(buf, len + 1, 0, len + 1);
421     BytesInfo info;
422     info.bytes = buf;
423     info.bytesLength = len;
424     int result = PrepareBytes(RESPONSE_TYPE, id, commandName, resultJsonPayload, info);
425     if (result != Constant::SUCCESS) {
426         delete[] buf;
427         return;
428     }
429     int retCode = SendResponseBytes(socket, buf, info.bytesLength);
430     delete[] buf;
431     ACCESSTOKEN_LOG_DEBUG(LABEL, "Send response result= %{public}d", retCode);
432 }
433 
HandleResponse(const std::string & id,const std::string & jsonPayload)434 void SoftBusChannel::HandleResponse(const std::string &id, const std::string &jsonPayload)
435 {
436     std::unique_lock<std::mutex> lock(socketMutex_);
437     auto callback = callbacks_.find(id);
438     if (callback != callbacks_.end()) {
439         (callback->second)(jsonPayload);
440         callbacks_.erase(callback);
441     }
442 }
443 
SendResponseBytes(int socket,const unsigned char * bytes,const int bytesLength)444 int SoftBusChannel::SendResponseBytes(int socket, const unsigned char *bytes, const int bytesLength)
445 {
446     ACCESSTOKEN_LOG_DEBUG(LABEL, "Send len (after compress len)= %{public}d", bytesLength);
447     int result = ::SendBytes(socket, bytes, bytesLength);
448     if (result != Constant::SUCCESS) {
449         ACCESSTOKEN_LOG_ERROR(LABEL, "Fail to send! result= %{public}d", result);
450         return Constant::FAILURE;
451     }
452     ACCESSTOKEN_LOG_DEBUG(LABEL, "Send successfully.");
453     return Constant::SUCCESS;
454 }
455 
FromJson(const std::string & jsonString)456 std::shared_ptr<SoftBusMessage> SoftBusMessage::FromJson(const std::string &jsonString)
457 {
458     nlohmann::json json;
459     if (!json.accept(jsonString)) {
460         return nullptr;
461     }
462     json = json.parse(jsonString, nullptr, false);
463     if (json.is_discarded() || (!json.is_object())) {
464         ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to parse jsonString");
465         return nullptr;
466     }
467 
468     std::string type;
469     std::string id;
470     std::string commandName;
471     std::string jsonPayload;
472     if (json.find("type") != json.end() && json.at("type").is_string()) {
473         json.at("type").get_to(type);
474     }
475     if (json.find("id") != json.end() && json.at("id").is_string()) {
476         json.at("id").get_to(id);
477     }
478     if (json.find("commandName") != json.end() && json.at("commandName").is_string()) {
479         json.at("commandName").get_to(commandName);
480     }
481     if (json.find("jsonPayload") != json.end() && json.at("jsonPayload").is_string()) {
482         json.at("jsonPayload").get_to(jsonPayload);
483     }
484     if (type.empty() || id.empty() || commandName.empty() || jsonPayload.empty()) {
485         ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to get json string(json format error)");
486         return nullptr;
487     }
488     std::shared_ptr<SoftBusMessage> message = std::make_shared<SoftBusMessage>(type, id, commandName, jsonPayload);
489     return message;
490 }
491 } // namespace AccessToken
492 } // namespace Security
493 } // namespace OHOS
494