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