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