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