diff --git a/BUILD.gn b/BUILD.gn index 693aed9c3118ecb9690cd738c0e93b05a102a7b8..d5c662ce54473217215da1bbf960f24a0b147001 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -284,8 +284,8 @@ template("build_hdc") { ] external_deps = [ "hilog:hilog_rust", - "rust_libc:lib", "rust_rust-openssl:lib", + "rust_libc:lib", ] if (product_name != "ohos-sdk") { @@ -402,9 +402,11 @@ ohos_executable("hdc") { ] if (is_ohos) { - sources += [ "src/common/password.cpp" ] + sources += [ "src/common/credential_message.cpp" ] sources += [ "src/common/hdc_huks.cpp" ] + sources += [ "src/common/password.cpp" ] defines += [ "HDC_SUPPORT_ENCRYPT_PRIVATE_KEY" ] + defines += [ "HOST_OHOS" ] external_deps += [ "huks:libhukssdk" ] } diff --git a/bundle.json b/bundle.json index e596389f03d454193af20337370365cdb185e45c..46a938ca9bc9c8b7f7a050743c7e8179cd2c140b 100644 --- a/bundle.json +++ b/bundle.json @@ -13,7 +13,8 @@ "name": "hdc", "subsystem": "developtools", "features": [ - "hdc_feature_support_sudo" + "hdc_feature_support_sudo", + "hdc_feature_support_credential" ], "adapted_system_type": [ "standard" @@ -30,6 +31,7 @@ "ipc", "ability_base", "ability_runtime", + "common_event_service", "window_manager", "ylong_runtime", "bounds_checking_function", @@ -54,9 +56,10 @@ "//developtools/hdc:hdc_register", "//developtools/hdc:hdcd_updater", "//developtools/hdc:hdc_updater", - "//developtools/hdc/sudo:sudo" + "//developtools/hdc/sudo:sudo", + "//developtools/hdc/credential:hdc_credential" ], - "inner_kits": [ + "inner_kits": [ { "name":"//developtools/hdc:hdc_updater", "header":{ diff --git a/credential/BUILD.gn b/credential/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..f7a1f9f13137e0384fc8cf19b3b3b7c44505a073 --- /dev/null +++ b/credential/BUILD.gn @@ -0,0 +1,85 @@ +# Copyright (C) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//developtools/hdc/hdc.gni") + +config("hdc_config") { + include_dirs = [ + "../src/common", + ] + cflags_cc = [ "-std=c++17" ] + if (is_mingw) { + cflags_cc += [ "-Wno-inconsistent-dllimport" ] # in mingw some sec api will + # overwrite by utilsecurec + } +} + +ohos_executable("hdc_credential_exec") { + if (hdc_feature_support_credential) { + use_exceptions = true + ldflags = [ + "-Wl,--whole-archive", + "-ldl", + "-lrt", + "-Wl,--no-whole-archive", + ] + libs = [] + defines = [] + configs = [ ":hdc_config" ] + deps = [] + + if (hdc_debug) { + defines += [ "HDC_DEBUG" ] + } + sources = [ + "main.cpp", + ] + + external_deps = [ + "openssl:libcrypto_shared", + "bounds_checking_function:libsec_shared", + "libuv:uv", + ] + if (product_name != "ohos-sdk") { + external_deps += [ + "os_account:os_account_innerkits", + "os_account:account_iam_innerkits" + ] + } + if (is_ohos) { + sources += [ "../src/common/base.cpp" ] + sources += [ "../src/common/credential_message.cpp" ] + sources += [ "../src/common/hdc_huks.cpp" ] + sources += [ "../src/common/password.cpp" ] + sources += [ "credential_base.cpp" ] + sources += [ "hdc_subscriber.cpp" ] + external_deps += [ "huks:libhukssdk" ] + external_deps += [ "hilog:libhilog" ] + defines += [ + "HDC_SUPPORT_ENCRYPT_PRIVATE_KEY", + "HDC_HILOG", + ] + install_images = [ "system" ] + } + output_name = "hdc_credential" + } + subsystem_name = "developtools" + part_name = "hdc" +} + +group ("hdc_credential") { + if (hdc_feature_support_credential) { + deps = [ ":hdc_credential_exec" ] + } +} \ No newline at end of file diff --git a/credential/credential_base.cpp b/credential/credential_base.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3d2640cb5e0a6a6cf1b597243603c1f6dac4381c --- /dev/null +++ b/credential/credential_base.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "credential_base.h" + +using namespace Hdc; + +char GetPathSep() +{ +#ifdef _WIN32 + const char sep = '\\'; +#else + const char sep = '/'; +#endif + return sep; +} + +int RemoveDir(const std::string& dir) +{ + DIR *pdir = opendir(dir.c_str()); + if (pdir == nullptr) { + WRITE_LOG(LOG_FATAL, "opendir failed dir:%s", dir.c_str()); + return -1; + } + struct dirent *ent; + struct stat st; + while ((ent = readdir(pdir)) != nullptr) { + if (ent->d_name[0] == '.') { + continue; + } + std::string subpath = dir + GetPathSep() + ent->d_name; + if (lstat(subpath.c_str(), &st) == -1) { + WRITE_LOG(LOG_WARN, "lstat failed subpath:%s", subpath.c_str()); + continue; + } + if (S_ISDIR(st.st_mode)) { + if (RemoveDir(subpath) == -1) { + closedir(pdir); + return -1; + } + rmdir(subpath.c_str()); + } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { + unlink(subpath.c_str()); + } else { + WRITE_LOG(LOG_DEBUG, "lstat st_mode:%07o subpath:%s", st.st_mode, subpath.c_str()); + } + } + if (rmdir(dir.c_str()) == -1) { + closedir(pdir); + return -1; + } + closedir(pdir); + return 0; +} + +int RemovePath(const std::string& path) +{ + struct stat st; + if (lstat(path.c_str(), &st) == -1) { + WRITE_LOG(LOG_WARN, "lstat failed path:%s", path.c_str()); + return -1; + } + if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { + unlink(path.c_str()); + } else if (S_ISDIR(st.st_mode)) { + if (path == "." || path == "..") { + return 0; + } + int rc = RemoveDir(path); + WRITE_LOG(LOG_INFO, "RemoveDir rc:%d path:%s", rc, path.c_str()); + return rc; + } + return 0; +} + +const std::string StringFormat(const char* const formater, ...) +{ + va_list vaArgs; + va_start(vaArgs, formater); + std::string ret = StringFormat(formater, vaArgs); + va_end(vaArgs); + return ret; +} + +const std::string StringFormat(const char* const formater, va_list& vaArgs) +{ + std::vector args(MAX_SIZE_IOBUF_STABLE); + const int retSize = vsnprintf_s( + args.data(), MAX_SIZE_IOBUF_STABLE, (args.size() >= 1) ? (args.size() - 1) : 0, formater, vaArgs); + if (retSize < 0) { + return std::string(""); + } else { + return std::string(args.data(), retSize); + } +} \ No newline at end of file diff --git a/credential/credential_base.h b/credential/credential_base.h new file mode 100644 index 0000000000000000000000000000000000000000..0989bee1f74a82b31ac9f409d25549bef909178d --- /dev/null +++ b/credential/credential_base.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef HDC_CREDENTIAL_BASE_H +#define HDC_CREDENTIAL_BASE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "credential_message.h" +#include "hdc_subscriber.h" +#include "hdc_huks.h" +#include "log.h" + +#ifdef HDC_HILOG +#ifdef LOG_DOMAIN +#undef LOG_DOMAIN +#endif // LOG_DOMAIN + +#define LOG_DOMAIN 0xD002D13 +#ifdef LOG_TAG +#undef LOG_TAG +#endif // LOG_TAG +#define LOG_TAG "HDC_LOG" +#endif // HDC_HILOG + +// 0x10000000 is 1.0.0a +constexpr uint32_t CREDENTIAL_VERSION_NUMBER = 0x10000000; +constexpr size_t SOCKET_CLIENT_NUMS = 1; + +#define HDC_PRIVATE_KEY_FILE_PWD_KEY_ALIAS "hdc_private_key_file_pwd_key_alias" +#define PASSWORD_LENGTH 10 + +constexpr uint32_t MAX_SIZE_IOBUF_STABLE = 60 * 1024; // 60KB, compatible with previous version +constexpr const char* HDC_CREDENTIAL_SOCKET_REAL_PATH = + "/data/service/el1/public/hdc_server/hdc_common/hdc_credential.socket"; +constexpr uint8_t CMD_ARG1_COUNT = 2; + +int RemoveDir(const std::string& dir); +int RemovePath(const std::string& path); +const std::string StringFormat(const char* const formater, ...); +const std::string StringFormat(const char* const formater, va_list& vaArgs); +char GetPathSep(); + +#endif // HDC_CREDENTIAL_BASE_H \ No newline at end of file diff --git a/credential/hdc_subscriber.cpp b/credential/hdc_subscriber.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2c758f61fcff443a697d13799e9cfee55a58b6c3 --- /dev/null +++ b/credential/hdc_subscriber.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "credential_base.h" +#include "hdc_subscriber.h" + +using namespace Hdc; +using namespace OHOS::AccountSA; + +void HdcSubscriber::OnStateChanged(const OHOS::AccountSA::OsAccountStateData& data) +{ + WRITE_LOG(LOG_INFO, "Recv data.state:%d", data.state); + std::string str_id = std::to_string(data.toId); + if (!std::regex_match(str_id, std::regex("^\\d+$"))) { + WRITE_LOG(LOG_FATAL, "data.toId is not a number:%s", str_id.c_str()); + } + std::string path = std::string("/data/service/el1/public/hdc_server/") + + str_id.c_str(); + mode_t mode = (S_IRWXU | S_IRWXG | S_IXOTH | S_ISGID); + bool operationSuccess = false; + + switch(data.state) { + case OsAccountState::CREATED: + if (::mkdir(path.c_str(), mode) != 0) { + WRITE_LOG(LOG_FATAL, "Failed to create directory ,error is :%s", strerror(errno)); + break; + } + if (::chmod(path.c_str(), mode) != 0) { + WRITE_LOG(LOG_FATAL, "Failed to set directory permissions, error is :%s", strerror(errno)); + break; + } + WRITE_LOG(LOG_DEBUG, "Directory created successfully."); + operationSuccess = true; + break; + case OsAccountState::REMOVED: + if (!RemovePath(path.c_str())) { + WRITE_LOG(LOG_DEBUG, "Directory removed successfully."); + operationSuccess = true; + } else { + WRITE_LOG(LOG_FATAL, "Failed to remove directory, error is:%s", strerror(errno)); + } + break; + default: + WRITE_LOG(LOG_FATAL, "This state is not support,state is:%d", data.state); + break; + } + if (data.callback != nullptr) { + if (operationSuccess) { + data.callback->OnComplete(); // 执行握手回调 + } + } + return; +} + +void HdcSubscriber::OnAccountsChanged(const int& id) +{ +} + +int HdcAccountSubscriberMonitor() +{ + static std::shared_ptr subscriber; + if (subscriber == nullptr) { + std::set states = { OsAccountState::CREATED, OsAccountState::REMOVED }; + OsAccountSubscribeInfo subscribeInfo(states, false); + subscriber = std::make_shared(subscribeInfo); + + const int MAX_RETRY = 10; + int retryCount = 0; + + while (retryCount < MAX_RETRY && + OsAccountManager::SubscribeOsAccount(subscriber)) { + ++retryCount; + std::this_thread::sleep_for(std::chrono::seconds(1)); + WRITE_LOG(LOG_FATAL, "SubscribeOsAccount failed, %d/%d", retryCount, MAX_RETRY); + } + + if (retryCount < MAX_RETRY) { + WRITE_LOG(LOG_DEBUG, "SubscribeOsAccount success."); + } else { + WRITE_LOG(LOG_FATAL, "SubscribeOsAccount failed after %d retries.", MAX_RETRY); + } + } else { + WRITE_LOG(LOG_FATAL, "Already subscribed to OsAccount change."); + } + + return 0; +} \ No newline at end of file diff --git a/credential/hdc_subscriber.h b/credential/hdc_subscriber.h new file mode 100644 index 0000000000000000000000000000000000000000..3fe0c60daeb4fc7b4c5bffe53cdbb93392825eee --- /dev/null +++ b/credential/hdc_subscriber.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef HDC_SUBSCRIBER_H +#define HDC_SUBSCRIBER_H + +#include "os_account_subscriber.h" +#include "os_account_manager.h" + +class HdcSubscriber : public OHOS::AccountSA::OsAccountSubscriber { +public: + HdcSubscriber(const OHOS::AccountSA::OsAccountSubscribeInfo& info) : OHOS::AccountSA::OsAccountSubscriber(info){}; + + void OnStateChanged(const OHOS::AccountSA::OsAccountStateData& data) override; + void OnAccountsChanged(const int& id) override; +}; + +int HdcAccountSubscriberMonitor(); + +#endif // HDC_SUBSCRIBER_H \ No newline at end of file diff --git a/credential/main.cpp b/credential/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..01dfaf7dc029f42c72eb51455b4baedc4fa3d89d --- /dev/null +++ b/credential/main.cpp @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "credential_base.h" +#include "credential_message.h" +#include "hdc_subscriber.h" +#include "password.h" + +using namespace Hdc; + +Hdc::HdcHuks hdcHuks(HDC_PRIVATE_KEY_FILE_PWD_KEY_ALIAS); +Hdc::HdcPassword pwd(HDC_PRIVATE_KEY_FILE_PWD_KEY_ALIAS); + +std::string BytetoHex(const uint8_t* byteDate, size_t length) +{ + uint8_t tmp; + std::string encryptPwd; + + for (size_t i = 0; i < length; i++) { + tmp = byteDate[i]; + encryptPwd.push_back(pwd.GetHexChar(tmp >> 4)); // 4 get high 4 bits + encryptPwd.push_back(pwd.GetHexChar(tmp & 0x0F)); + } + return encryptPwd; +} + +bool ResetPwdKey(void) +{ + return hdcHuks.ResetHuksKey(); +} + +std::string CredentialEncryptPwd(const std::string& messageStr) +{ + std::vector encryptData; + const char* rawCharData = messageStr.c_str(); + const uint8_t* uint8MessageStr = reinterpret_cast(rawCharData); + + bool encryptResult = hdcHuks.AesGcmEncrypt(uint8MessageStr, PASSWORD_LENGTH, encryptData); + if (!encryptResult) { + WRITE_LOG(LOG_FATAL, "CredentialEncryptPwd: AES GCM encryption failed."); + return ""; + } + + return std::string(reinterpret_cast(encryptData.data()), encryptData.size()); +} + +std::pair EncryptPwd(const std::string& messageStr) +{ + if (!ResetPwdKey()) { + WRITE_LOG(LOG_FATAL, "EncryptPwd: ResetPwdKey failed."); + return std::make_pair(std::string(), 0); + } + + std::string encryptPwd = CredentialEncryptPwd(messageStr); + if (encryptPwd.empty()) { + WRITE_LOG(LOG_FATAL, "EncryptPwd: CredentialEncryptPwd failed."); + return std::make_pair(std::string(), 0); + } + + return std::make_pair(encryptPwd, encryptPwd.size()); +} + +std::pair DecryptPwd(const std::string& messageStr) +{ + uint8_t pwd[PASSWORD_LENGTH] = {0}; + std::pair decryptPwd = hdcHuks.AesGcmDecrypt(messageStr); + if (decryptPwd.first == nullptr) { + WRITE_LOG(LOG_FATAL, "AesGcmDecrypt failed."); + return std::make_pair(std::string(), 0); + } + + do { + if (decryptPwd.second != PASSWORD_LENGTH) { + WRITE_LOG(LOG_FATAL, "Invalid pwd len %d", decryptPwd.second); + break; + } + int ret = memcpy_s(pwd, PASSWORD_LENGTH, decryptPwd.first, decryptPwd.second); + if (ret != EOK) { + WRITE_LOG(LOG_FATAL, "Copy failed.ret is %d", ret); + break; + } + } while (0); + + memset_s(decryptPwd.first, decryptPwd.second, 0, decryptPwd.second); + delete[] decryptPwd.first; + + std::string pwdStr(reinterpret_cast(pwd), PASSWORD_LENGTH); + memset_s(pwd, PASSWORD_LENGTH, 0, PASSWORD_LENGTH); + + return std::make_pair(pwdStr, pwdStr.size()); +} + +std::string ParseAndProcessMessageStr(const std::string& messageStr) +{ + CredentialMessage messageStruct(messageStr); + if (messageStruct.GetMessageBody().empty() || + messageStruct.GetMessageVersion() != METHOD_VERSION_V1) { + WRITE_LOG(LOG_FATAL, "Invalid message structure or version not v1."); + return ""; + } + std::pair processMessageValue; + switch (messageStruct.GetMessageMethodType()) { + case METHOD_ENCRYPT: { + processMessageValue = EncryptPwd(messageStruct.GetMessageBody()); + break; + } + case METHOD_DECRYPT: { + processMessageValue = DecryptPwd(messageStruct.GetMessageBody()); + break; + } + default: { + WRITE_LOG(LOG_FATAL, "Unsupported message method type."); + return ""; + } + } + + messageStruct.SetMessageBody(processMessageValue.first); + + return messageStruct.Construct(); +} + +int create_and_bind_socket(const std::string& socketPath) +{ + int sockfd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (sockfd < 0) { + WRITE_LOG(LOG_FATAL, "Failed to create socket."); + return -1; + } + + struct sockaddr_un addr; + memset_s(&addr, sizeof(addr), 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + size_t buf_size = socketPath.length() + 1; + memcpy_s(addr.sun_path, buf_size, socketPath.c_str(), buf_size); + + struct timeval timeout; + timeout.tv_sec = 1; + timeout.tv_usec = 0; + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &timeout, sizeof(timeout)) < 0) { + WRITE_LOG(LOG_FATAL, "Failed to set socket options, message: %s.", strerror(errno)); + close(sockfd); + return -1; + } + + if (access(socketPath.c_str(), F_OK) == 0) { + if (remove(socketPath.c_str()) < 0) { + WRITE_LOG(LOG_FATAL, "Failed to remove existing socket file, message: %s.", strerror(errno)); + return -1; + } + } + + if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + WRITE_LOG(LOG_FATAL, "Failed to bind socket, message: %s.", strerror(errno)); + close(sockfd); + return -1; + } + + if (chmod(addr.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) != 0) { + WRITE_LOG(LOG_FATAL, "Failed to chmod socket file, message: %s.", strerror(errno)); + close(sockfd); + return -1; + } + return sockfd; +} + +std::string CredentialUsage() +{ + std::string ret = ""; + ret = "\n Harmony device connector (HDC) credential process \n\n" + "Usage: hdc_credential [options]...\n" + "\n" + "general options:\n" + " -h - Print help\n" + " -v - Print version information\n"; + return ret; +} + +std::string CredentialVersion() +{ + const uint8_t a = 'a'; + uint8_t major = (CREDENTIAL_VERSION_NUMBER >> 28) & 0xff; + uint8_t minor = (CREDENTIAL_VERSION_NUMBER << 4 >> 24) & 0xff; + uint8_t version = (CREDENTIAL_VERSION_NUMBER << 12 >> 24) & 0xff; + uint8_t fix = (CREDENTIAL_VERSION_NUMBER << 20 >> 28) & 0xff; // max 16, tail is p + std::string ver = StringFormat("%x.%x.%x%c", major, minor, version, a + fix); + return "Ver: " + ver; +} + +bool SplitCommandToArgs(int argc, const char **argv) +{ + if (argc == CMD_ARG1_COUNT) { + if (!strcmp(argv[1], "-h")) { + std::string usage = CredentialUsage(); + fprintf(stderr, "%s", usage.c_str()); + return false; + } else if (!strcmp(argv[1], "-v")) { + std::string ver = CredentialVersion(); + fprintf(stderr, "%s\n", ver.c_str()); + return false; + } + } + if (argc != 1) { + fprintf(stderr, "Invalid input parameters, please recheck.\n"); + std::string usage = CredentialUsage(); + fprintf(stderr, "%s\n", usage.c_str()); + return false; + } + return true; +} +int main(int argc, const char *argv[]) +{ + if (!SplitCommandToArgs(argc, argv)) { + return 0; + } + HdcAccountSubscriberMonitor(); + int sockfd = create_and_bind_socket(HDC_CREDENTIAL_SOCKET_REAL_PATH); + if (sockfd < 0) { + WRITE_LOG(LOG_FATAL, "Failed to create and bind socket."); + return -1; + } + if (listen(sockfd, SOCKET_CLIENT_NUMS) < 0) { + WRITE_LOG(LOG_FATAL, "Failed to listen on socket."); + close(sockfd); + return -1; + } + WRITE_LOG(LOG_INFO, "Listening on socket: %s", HDC_CREDENTIAL_SOCKET_REAL_PATH); + bool running = true; + while (running) { + int connfd = accept(sockfd, nullptr, nullptr); + if (connfd < 0) { + WRITE_LOG(LOG_FATAL, "Failed to accept connection!"); + continue; + } + + char buffer[MESSAGE_STR_MAX_LEN] = {0}; + ssize_t bytesRead = read(connfd, buffer, sizeof(buffer) - 1); + if (bytesRead < 0) { + WRITE_LOG(LOG_FATAL, "Error: Failed to read from socket."); + close(connfd); + continue; + } + std::string sendBuf = ParseAndProcessMessageStr(std::string(buffer, bytesRead)); + if (sendBuf.empty()) { + WRITE_LOG(LOG_FATAL, "Error: Processed message is empty."); + close(connfd); + continue; + } + + size_t bytesSend = write(connfd, sendBuf.c_str(), sendBuf.size()); + if (bytesSend != sendBuf.size()) { + WRITE_LOG(LOG_FATAL, "Failed to send message."); + close(connfd); + } + memset_s(buffer, sizeof(buffer), 0, sizeof(buffer)); // Clear the buffer + close(connfd); + } // Keep the server running indefinitely + close(sockfd); + unlink(HDC_CREDENTIAL_SOCKET_REAL_PATH); + return 0; +} \ No newline at end of file diff --git a/hdc.gni b/hdc.gni index ecf8e9301be39b9a7661a6068e0c593bcc8bba30..688a5bf8f095017441fb28316850bc57214f7e74 100644 --- a/hdc.gni +++ b/hdc.gni @@ -24,6 +24,7 @@ declare_args() { hdc_version_check = false support_hdcd_user_permit = false hdc_feature_support_sudo = false + hdc_feature_support_credential = false if (defined(global_parts_info)) { if (defined(global_parts_info.ability_ability_base)) { diff --git a/src/common/auth.cpp b/src/common/auth.cpp index be23e884a63cfaabee016d76384b60de798eea1b..3f5d0098ee8dc62ae492490efd4409d03fac554c 100644 --- a/src/common/auth.cpp +++ b/src/common/auth.cpp @@ -26,7 +26,6 @@ using namespace Hdc; #define BIGNUMTOBIT 32 -#define HDC_PRIVATE_KEY_FILE_PWD_KEY_ALIAS "hdc_private_key_file_pwd_key_alias" namespace HdcAuth { // ---------------------------------------Cheat compiler--------------------------------------------------------- diff --git a/src/common/auth.h b/src/common/auth.h index 3b2536a36830560f7f2d81d0b10a81f70621127b..02fe478a9afefeb927c2600dbe73a23835d92b78 100644 --- a/src/common/auth.h +++ b/src/common/auth.h @@ -41,5 +41,8 @@ int GetPublicKeyFileBuf(unsigned char *data, size_t len); bool AuthVerify(uint8_t *token, uint8_t *sig, int siglen); bool PostUIConfirm(string publicKey); } +#ifdef HDC_SUPPORT_ENCRYPT_PRIVATE_KEY +#define HDC_PRIVATE_KEY_FILE_PWD_KEY_ALIAS "hdc_private_key_file_pwd_key_alias" +#endif #endif \ No newline at end of file diff --git a/src/common/base.cpp b/src/common/base.cpp index 4b4d2ea7af7496fd83edebc42b8efc9945bdaeb6..658e06b7bc1a20b3d06db2c872ec00ea20d80e27 100644 --- a/src/common/base.cpp +++ b/src/common/base.cpp @@ -196,7 +196,12 @@ namespace Base { #else int flags = UV_FS_O_RDWR | UV_FS_O_APPEND | UV_FS_O_CREAT; uv_fs_t req; - int fd = uv_fs_open(nullptr, &req, path, flags, S_IWUSR | S_IRUSR, nullptr); +#ifdef HOST_OHOS + mode_t mode = (S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP); +#else + mode_t mode = (S_IWUSR | S_IRUSR); +#endif + int fd = uv_fs_open(nullptr, &req, path, flags, mode, nullptr); if (fd < 0) { char buffer[BUF_SIZE_DEFAULT] = { 0 }; uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT); @@ -663,9 +668,13 @@ static void EchoLog(string &buf) string debugInfo = functionName; GetLogDebugFunctionName(debugInfo, line, threadIdString); GetLogLevelAndTime(logLevel, logLevelString, timeString); +#ifdef OHOS_HOST + string logBuf = StringFormat("[%s][%s][%u]%s%s %s%s", logLevelString.c_str(), timeString.c_str(), + getuid(), threadIdString.c_str(), debugInfo.c_str(), buf, sep.c_str()); +#else string logBuf = StringFormat("[%s][%s]%s%s %s%s", logLevelString.c_str(), timeString.c_str(), threadIdString.c_str(), debugInfo.c_str(), buf, sep.c_str()); - +#endif EchoLog(logBuf); if (!g_logCache) { @@ -718,6 +727,20 @@ static void EchoLog(string &buf) return tmpString; } +#ifdef HOST_OHOS + void SetUdsOptions(uv_pipe_t *udsHandle, int bufMaxSize) + { + if (!udsHandle) { + return; + } + // if MAX_SIZE_IOBUF==5k,bufMaxSize at least 40k. It must be set to io 8 times is more appropriate, + // otherwise asynchronous IO is too fast, a lot of IO is wasted on IOloop, transmission speed will decrease + + uv_recv_buffer_size((uv_handle_t *)udsHandle, &bufMaxSize); + uv_send_buffer_size((uv_handle_t *)udsHandle, &bufMaxSize); + } +#endif + void SetTcpOptions(uv_tcp_t *tcpHandle, int bufMaxSize) { if (!tcpHandle) { @@ -1348,7 +1371,12 @@ static void EchoLog(string &buf) resolvedPath = CanonicalizeSpecPath(srcPath); } uv_fs_t req; - int fd = uv_fs_open(nullptr, &req, resolvedPath.c_str(), flags, S_IWUSR | S_IRUSR, nullptr); +#ifdef __OHOS__ + mode_t mode = (S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP); +#else + mode_t mode = (S_IWUSR | S_IRUSR); +#endif + int fd = uv_fs_open(nullptr, &req, resolvedPath.c_str(), flags, mode, nullptr); if (fd < 0) { char buffer[BUF_SIZE_DEFAULT] = { 0 }; uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT); @@ -1388,10 +1416,17 @@ static void EchoLog(string &buf) char buf[BUF_SIZE_DEFAULT] = ""; char pidBuf[BUF_SIZE_TINY] = ""; size_t size = sizeof(buf); +#ifndef HOST_OHOS if (uv_os_tmpdir(buf, &size) < 0) { WRITE_LOG(LOG_FATAL, "Tmppath failed"); return ERR_API_FAIL; } +#else + if (uv_os_homedir(buf, &size) < 0) { + WRITE_LOG(LOG_FATAL, "Homepath failed"); + return ERR_API_FAIL; + } +#endif if (snprintf_s(bufPath, sizeof(bufPath), sizeof(bufPath) - 1, "%s%c.%s.pid", buf, Base::GetPathSep(), procname) < 0) { return ERR_BUF_OVERFLOW; @@ -2112,6 +2147,19 @@ static void EchoLog(string &buf) return dupFd; } +#ifdef HOST_OHOS + uv_os_sock_t DuplicateUvPipe(uv_pipe_t *pipe) + { + uv_os_sock_t dupFd = -1; + uv_os_fd_t fdOs; + if (uv_fileno((const uv_handle_t *)pipe, &fdOs) < 0) { + return ERR_API_FAIL; + } + dupFd = dup(uv_open_osfhandle(fdOs)); + return dupFd; + } +#endif + string GetCwd() { int value = -1; @@ -2145,7 +2193,11 @@ static void EchoLog(string &buf) int value = -1; char path[PATH_MAX] = ""; size_t size = sizeof(path); +#ifdef HOST_OHOS + value = uv_os_homedir(path, &size); +#else value = uv_os_tmpdir(path, &size); +#endif if (value < 0) { constexpr int bufSize = 1024; char buf[bufSize] = { 0 }; @@ -2946,7 +2998,12 @@ void CloseOpenFd(void) { int flags = UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_APPEND; uv_fs_t req; - int fd = uv_fs_open(nullptr, &req, path.c_str(), flags, S_IWUSR | S_IRUSR, nullptr); +#ifdef HOST_OHOS + mode_t mode = (S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP); +#else + mode_t mode = (S_IWUSR | S_IRUSR); +#endif + int fd = uv_fs_open(nullptr, &req, path.c_str(), flags, mode, nullptr); if (fd < 0) { char buffer[BUF_SIZE_DEFAULT] = { 0 }; uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT); diff --git a/src/common/base.h b/src/common/base.h index a0d15aa76fe003443c74de2c3de323ce73df554e..f593960c6fd97490bf5c576a5e59f387e9b9afc3 100644 --- a/src/common/base.h +++ b/src/common/base.h @@ -47,6 +47,9 @@ namespace Base { void PrintMessageAndWriteLog(const char *fmt, ...); // tcpHandle can't be const as it's passed into uv_tcp_keepalive void SetTcpOptions(uv_tcp_t *tcpHandle, int bufMaxSize = HDC_SOCKETPAIR_SIZE); +#ifdef HOST_OHOS + void SetUdsOptions(uv_pipe_t *udsHandle, int bufMaxSize = HDC_SOCKETPAIR_SIZE); +#endif // Realloc need to update origBuf&origSize which can't be const void ReallocBuf(uint8_t **origBuf, int *nOrigSize, size_t sizeWanted); // handle&sendHandle must keep sync with uv_write @@ -215,6 +218,9 @@ namespace Base { } #endif uv_os_sock_t DuplicateUvSocket(uv_tcp_t *tcp); +#ifdef HOST_OHOS + uv_os_sock_t DuplicateUvPipe(uv_pipe_t *pipe); +#endif bool IsRoot(); char GetPathSep(); string GetHdcAbsolutePath(); diff --git a/src/common/channel.cpp b/src/common/channel.cpp index 7d605ada0af46d73ed300b0c6ba5619eaecfa200..2fba58b82230c9b26f31e7a6889a10abd7635cea 100644 --- a/src/common/channel.cpp +++ b/src/common/channel.cpp @@ -363,11 +363,28 @@ void HdcChannelBase::SendChannel(HChannel hChannel, uint8_t *bufPtr, const int s WRITE_LOG(LOG_DEBUG, "memcpy_s failed size:%d", size); return; } + +#ifdef HOST_OHOS + if (hChannel->hWorkThread == uv_thread_self()) { + if (!hChannel->isUds) { + sendStream = (uv_stream_t *)&hChannel->hWorkTCP; + } else { + sendStream = (uv_stream_t *)&hChannel->hWorkUds; + } + } else { + if (!hChannel->isUds) { + sendStream = (uv_stream_t *)&hChannel->hChildWorkTCP; + } else { + sendStream = (uv_stream_t *)&hChannel->hChildWorkUds; + } + } +#else if (hChannel->hWorkThread == uv_thread_self()) { sendStream = (uv_stream_t *)&hChannel->hWorkTCP; } else { sendStream = (uv_stream_t *)&hChannel->hChildWorkTCP; } +#endif int rc = -1; if (!uv_is_closing((const uv_handle_t *)sendStream) && uv_is_writable(sendStream)) { ++hChannel->ref; @@ -420,6 +437,53 @@ uint32_t HdcChannelBase::GetChannelPseudoUid() return uid; } +#ifdef HOST_OHOS +uint32_t HdcChannelBase::MallocChannel(HChannel *hOutChannel) +{ +#ifdef CONFIG_USE_JEMALLOC_DFX_INIF + mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE); + mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE); +#endif + auto hChannel = new HdcChannel(); + if (!hChannel || !(*hOutChannel)) { + WRITE_LOG(LOG_FATAL, "malloc channel failed"); + return 0; + } + hChannel->isUds = (*hOutChannel)->isUds; + hChannel->stdinTty.data = nullptr; + hChannel->stdoutTty.data = nullptr; + uint32_t channelId = GetChannelPseudoUid(); + if (isServerOrClient) { + hChannel->serverOrClient = isServerOrClient; + ++channelId; // Use different value for serverForClient&client in per process + } + if (!hChannel->isUds) { + int rc = uv_tcp_init(loopMain, &hChannel->hWorkTCP); + if (rc < 0) { + WRITE_LOG(LOG_FATAL, "MallocChannel uv_tcp_init failed, rc:%d cid:%u", rc, channelId); + } + hChannel->hWorkTCP.data = hChannel; + (void)memset_s(&hChannel->hChildWorkTCP, sizeof(hChannel->hChildWorkTCP), 0, sizeof(uv_tcp_t)); + } else { + int rc = uv_pipe_init(loopMain, &hChannel->hWorkUds, 0); + if (rc < 0) { + WRITE_LOG(LOG_FATAL, "MallocChannel uv_pipe_init failed, rc:%d cid:%u", rc, channelId); + } + hChannel->hWorkUds.data = hChannel; + (void)memset_s(&hChannel->hChildWorkUds, sizeof(hChannel->hChildWorkUds), 0, sizeof(uv_pipe_t)); + } + ++hChannel->uvHandleRef; + hChannel->hWorkThread = uv_thread_self(); + hChannel->clsChannel = this; + hChannel->channelId = channelId; + hChannel->loopStatus = &loopMainStatus; + AdminChannel(OP_ADD, channelId, hChannel); + delete *hOutChannel; + *hOutChannel = hChannel; + WRITE_LOG(isServerOrClient ? LOG_INFO : LOG_DEBUG, "Mallocchannel:%u", channelId); + return channelId; +} +#else uint32_t HdcChannelBase::MallocChannel(HChannel *hOutChannel) { #ifdef CONFIG_USE_JEMALLOC_DFX_INIF @@ -442,6 +506,7 @@ uint32_t HdcChannelBase::MallocChannel(HChannel *hOutChannel) if (rc < 0) { WRITE_LOG(LOG_FATAL, "MallocChannel uv_tcp_init failed, rc:%d cid:%u", rc, channelId); } + ++hChannel->uvHandleRef; hChannel->hWorkThread = uv_thread_self(); hChannel->hWorkTCP.data = hChannel; @@ -451,13 +516,10 @@ uint32_t HdcChannelBase::MallocChannel(HChannel *hOutChannel) (void)memset_s(&hChannel->hChildWorkTCP, sizeof(hChannel->hChildWorkTCP), 0, sizeof(uv_tcp_t)); AdminChannel(OP_ADD, channelId, hChannel); *hOutChannel = hChannel; - if (isServerOrClient) { - WRITE_LOG(LOG_INFO, "Mallocchannel:%u", channelId); - } else { - WRITE_LOG(LOG_DEBUG, "Mallocchannel:%u", channelId); - } + WRITE_LOG(isServerOrClient ? LOG_INFO : LOG_DEBUG, "Mallocchannel:%u", channelId); return channelId; } +#endif // work when libuv-handle at struct of HdcSession has all callback finished void HdcChannelBase::FreeChannelFinally(uv_idle_t *handle) @@ -527,14 +589,66 @@ void HdcChannelBase::FreeChannelContinue(HChannel hChannel) Base::TryCloseHandle((uv_handle_t *)&hChannel->stdinTty, closeChannelHandle); Base::TryCloseHandle((uv_handle_t *)&hChannel->stdoutTty, closeChannelHandle); } +#ifdef HOST_OHOS + if (!hChannel->isUds) { + if (uv_is_closing((const uv_handle_t *)&hChannel->hWorkTCP)) { + --hChannel->uvHandleRef; + } else { + Base::TryCloseHandle((uv_handle_t *)&hChannel->hWorkTCP, closeChannelHandle); + } + } else { + if (uv_is_closing((const uv_handle_t *)&hChannel->hWorkUds)) { + --hChannel->uvHandleRef; + } else { + Base::TryCloseHandle((uv_handle_t *)&hChannel->hWorkUds, closeChannelHandle); + } + } +#else if (uv_is_closing((const uv_handle_t *)&hChannel->hWorkTCP)) { --hChannel->uvHandleRef; } else { Base::TryCloseHandle((uv_handle_t *)&hChannel->hWorkTCP, closeChannelHandle); } +#endif Base::IdleUvTask(loopMain, hChannel, FreeChannelFinally); } +#ifdef HOST_OHOS +void HdcChannelBase::FreeChannelOpeate(uv_timer_t *handle) +{ + StartTraceScope("HdcChannelBase::FreeChannelOpeate"); + HChannel hChannel = (HChannel)handle->data; + HdcChannelBase *thisClass = (HdcChannelBase *)hChannel->clsChannel; + if (hChannel->ref > 0) { + return; + } + thisClass->DispMntnInfo(hChannel); + if (hChannel->hChildWorkTCP.loop || hChannel->hChildWorkUds.loop) { + auto ctrl = HdcSessionBase::BuildCtrlString(SP_DEATCH_CHANNEL, hChannel->channelId, nullptr, 0); + bool ret = thisClass->ChannelSendSessionCtrlMsg(ctrl, hChannel->targetSessionId); + if (!ret) { + WRITE_LOG(LOG_WARN, "FreeChannelOpeate deatch failed channelId:%u sid:%u", + hChannel->channelId, hChannel->targetSessionId); + hChannel->childCleared = true; + } + auto callbackCheckFreeChannelContinue = [](uv_timer_t *handle) -> void { + HChannel hChannel = (HChannel)handle->data; + HdcChannelBase *thisClass = (HdcChannelBase *)hChannel->clsChannel; + if (!hChannel->childCleared) { + WRITE_LOG(LOG_WARN, "FreeChannelOpeate childCleared:%d channelId:%u sid:%u", + hChannel->childCleared, hChannel->channelId, hChannel->targetSessionId); + return; + } + Base::TryCloseHandle((uv_handle_t *)handle, Base::CloseTimerCallback); + thisClass->FreeChannelContinue(hChannel); + }; + Base::TimerUvTask(thisClass->loopMain, hChannel, callbackCheckFreeChannelContinue); + } else { + thisClass->FreeChannelContinue(hChannel); + } + Base::TryCloseHandle((uv_handle_t *)handle, Base::CloseTimerCallback); +} +#else void HdcChannelBase::FreeChannelOpeate(uv_timer_t *handle) { StartTraceScope("HdcChannelBase::FreeChannelOpeate"); @@ -569,6 +683,7 @@ void HdcChannelBase::FreeChannelOpeate(uv_timer_t *handle) } Base::TryCloseHandle((uv_handle_t *)handle, Base::CloseTimerCallback); } +#endif void HdcChannelBase::FreeChannel(const uint32_t channelId) { @@ -615,6 +730,7 @@ HChannel HdcChannelBase::AdminChannel(const uint8_t op, const uint32_t channelId #ifdef HDC_HOST PrintChannel(channelId); #endif + break; case OP_ADD: uv_rwlock_wrlock(&lockMapChannel); mapChannel[channelId] = hInput; diff --git a/src/common/channel.h b/src/common/channel.h old mode 100755 new mode 100644 diff --git a/src/common/credential_message.cpp b/src/common/credential_message.cpp new file mode 100644 index 0000000000000000000000000000000000000000..061606aa8c2c4cc98ef497771f040bcd2d5a1cda --- /dev/null +++ b/src/common/credential_message.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "credential_message.h" + +using namespace Hdc; + +CredentialMessage::CredentialMessage(const std::string& messageStr) +{ + if (messageStr.empty() || messageStr.length() < MESSAGE_BODY_POS) { + WRITE_LOG(LOG_FATAL, "messageStr is too short!"); + return; + } + + int versionInt = messageStr[MESSAGE_VERSION_POS] - '0'; + if (!IsInRange(versionInt, METHOD_VERSION_V1, METHOD_VERSION_MAX)) { + WRITE_LOG(LOG_FATAL, "Invalid message version %d.", versionInt); + return; + } + + messageVersion = versionInt; + + std::string messageMethodStr = messageStr.substr(MESSAGE_METHOD_POS, MESSAGE_METHOD_LEN); + messageMethodType = StripLeadingZeros(messageMethodStr); + + std::string messageLengthStr = messageStr.substr(MESSAGE_LENGTH_POS, MESSAGE_LENGTH_LEN); + char* end = nullptr; + size_t bodyLength = strtol(messageLengthStr.c_str(), &end, 10); + if (end == nullptr || *end != '\0' || bodyLength > MESSAGE_STR_MAX_LEN) { + WRITE_LOG(LOG_FATAL, "Invalid message body length %s.", messageLengthStr.c_str()); + return; + } + + if (messageStr.length() < MESSAGE_BODY_POS + bodyLength) { + WRITE_LOG(LOG_FATAL, "messageStr is too short: %s", messageStr.c_str()); + return; + } + + messageBodyLen = static_cast(bodyLength); + messageBody = messageStr.substr(MESSAGE_BODY_POS, bodyLength); +} +CredentialMessage::~CredentialMessage() +{ + if (!messageBody.empty()) { + memset_s(&messageBody[0], messageBody.size(), 0, messageBody.size()); + messageBody.clear(); + } +} + +void CredentialMessage::SetMessageVersion(int version) +{ + if (version >= METHOD_VERSION_V1 && version <= METHOD_VERSION_MAX) { + messageVersion = version; + } else { + WRITE_LOG(LOG_FATAL, "Invalid message version %d.", version); + } +} + +void CredentialMessage::SetMessageBody(const std::string& body) +{ + if (body.size() > MESSAGE_STR_MAX_LEN) { + WRITE_LOG(LOG_FATAL, "Message body length exceeds maximum allowed length."); + return; + } + messageBody = body; + messageBodyLen = static_cast(messageBody.size()); +} + +std::string CredentialMessage::Construct() const +{ + size_t totalLength = 0; + totalLength += 1; + totalLength += MESSAGE_METHOD_LEN; + totalLength += MESSAGE_LENGTH_LEN; + totalLength += messageBody.size(); + + std::string messageMethodTypeStr = ConvertInt(messageMethodType, MESSAGE_METHOD_LEN); + if (messageMethodTypeStr.size() != MESSAGE_METHOD_LEN) { + WRITE_LOG(LOG_FATAL, "messageMethod length Error!"); + return ""; + } + + std::string messageBodyLenStr = ConvertInt(messageBodyLen, MESSAGE_LENGTH_LEN); + if (messageBodyLenStr.size() > MESSAGE_LENGTH_LEN) { + WRITE_LOG(LOG_FATAL, "messageBodyLen length must be:%d,now is:%s", + MESSAGE_LENGTH_LEN, messageBodyLenStr.c_str()); + return ""; + } + + std::vector newBuffer(totalLength + 1, '\0'); + int resLen = snprintf_s(newBuffer.data(), newBuffer.size(), newBuffer.size() - 1, "%c%s%s%s", ('0' + messageVersion), + messageMethodTypeStr.c_str(), messageBodyLenStr.c_str(), messageBody.c_str()); + if (resLen < 0) { + WRITE_LOG(LOG_FATAL, "Construct Error!, resLen is:%d", resLen); + return ""; + } + + std::string result(newBuffer.data(), totalLength); + return result; +} + +bool IsNumeric(const std::string& str) +{ + if (str.empty()) { + return false; + } + size_t i = 0; + for (; i < str.size(); ++i) { + if (!std::isdigit(str[i])) { + return false; + } + } + return true; +} + +int StripLeadingZeros(const std::string& input) +{ + if (input.empty() || input == "0") { + return 0; + } + size_t firstNonZero = input.find_first_not_of('0'); + if (firstNonZero == std::string::npos) { + return 0; + } + + std::string numberStr = input.substr(firstNonZero); + if (!IsNumeric(numberStr)) { + WRITE_LOG(LOG_FATAL, "StripLeadingZeros: invalid numeric string."); + return -1; + } + + char* end = nullptr; + long value = strtol(numberStr.c_str(), &end, 10); + return static_cast(value); +} + +inline bool IsInRange(int value, int min, int max) +{ + return (value >= min && value <= max); +} + +std::vector String2Uint8(const std::string& str, size_t len) +{ + std::vector byteData(len); + for (size_t i = 0; i < len; i++) { + byteData[i] = static_cast(str[i]); + } + return byteData; +} + +std::string ConvertInt(int len, int maxLen) +{ + std::string str = std::to_string(len); + if (str.length() > static_cast(maxLen)) { + return ""; + } + return std::string(maxLen - str.length(), '0') + str; +} \ No newline at end of file diff --git a/src/common/credential_message.h b/src/common/credential_message.h new file mode 100644 index 0000000000000000000000000000000000000000..a7ff6a6fd779204c8fd0e87daa0457b4f4fdf6ac --- /dev/null +++ b/src/common/credential_message.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef HDC_CREDENTIAL_MESSAGE_H +#define HDC_CREDENTIAL_MESSAGE_H + +#include +#include "log.h" +#include "securec.h" + +class CredentialMessage { +public: + CredentialMessage() = default; + explicit CredentialMessage(const std::string& messageStr); + ~CredentialMessage(); + int GetMessageVersion() const { return messageVersion; } + int GetMessageMethodType() const { return messageMethodType; } + int GetMessageBodyLen() const { return messageBodyLen; } + const std::string& GetMessageBody() const { return messageBody; } + + void SetMessageVersion(int version); + void SetMessageMethodType(int type) { messageMethodType = type; } + void SetMessageBodyLen(int len) { messageBodyLen = len; } + void SetMessageBody(const std::string& body); + std::string Construct() const; + +private: + int messageVersion = 0; + int messageMethodType = 0; + int messageBodyLen = 0; + std::string messageBody; +}; + +bool IsNumeric(const std::string& str); +int StripLeadingZeros(const std::string& input); +bool IsInRange(int value, int min, int max); +std::string ConvertInt(int len, int maxLen); +std::vector String2Uint8(const std::string& str, size_t len); + +constexpr size_t MESSAGE_STR_MAX_LEN = 1024; +constexpr size_t MESSAGE_VERSION_POS = 0; +constexpr size_t MESSAGE_METHOD_POS = 1; +constexpr size_t MESSAGE_METHOD_LEN = 3; +constexpr size_t MESSAGE_LENGTH_POS = 4; +constexpr size_t MESSAGE_LENGTH_LEN = 4; +constexpr size_t MESSAGE_BODY_POS = 8; + +enum V1MethodID { + METHOD_ENCRYPT = 1, + METHOD_DECRYPT, +}; + +enum MethodVersion { + METHOD_VERSION_V1 = 1, + METHOD_VERSION_MAX = 9, +}; + +#endif // HDC_CREDENTIAL_MESSAGE_H \ No newline at end of file diff --git a/src/common/define.h b/src/common/define.h index fd414e9a2d93f247b3a6da84c342f6f1cce8fb29..ff42fee020c9c358f5c1bf6ef81bfcd3bc19f164 100644 --- a/src/common/define.h +++ b/src/common/define.h @@ -44,6 +44,10 @@ const string ENV_SERVER_HEARTBEAT = "OHOS_HDC_HEARTBEAT"; // 1: turn off heartbe const string ENV_ENCRYPT_CHANNEL = "OHOS_HDC_ENCRYPT_CHANNEL"; // 1: turn on encrypt channel const string STR_PSK_IDENTITY = "Client_identity"; const string TLS_AES_128_GCM_SHA256 = "TLS_AES_128_GCM_SHA256"; +#ifdef __OHOS__ +const string UDS_PATH = "/data/hdc/hdc_debug/hdc_server"; +const string UDS_STR = "uds"; +#endif // ################################ macro define ################################### constexpr uint8_t MINOR_TIMEOUT = 5; @@ -155,6 +159,10 @@ const char HUGE_BUF_TAG = 'H'; // support huge buffer const size_t BANNER_FEATURE_TAG_OFFSET = 11; const char WAIT_DEVICE_TAG = 'W'; const size_t WAIT_TAG_OFFSET = 11; +#ifdef HOST_OHOS +const size_t SERVICE_KILL_OFFSET = 10; +const char SERVICE_KILL_TAG = 'K'; +#endif // input command const string CMDSTR_SOFTWARE_VERSION = "version"; const string CMDSTR_SOFTWARE_HELP = "help"; diff --git a/src/common/define_plus.h b/src/common/define_plus.h index e1c9b12a1d9b1a0b1773f9ec2778cae5f9b0c88e..f2a29a2da23ba8fb5bf0317b989e70034738def2 100644 --- a/src/common/define_plus.h +++ b/src/common/define_plus.h @@ -358,6 +358,11 @@ struct HdcChannel { void *clsChannel; // ptr Class of serverForClient or client uint32_t channelId; std::string connectKey; +#ifdef HOST_OHOS + bool isUds = false; + uv_pipe_t hWorkUds; + uv_pipe_t hChildWorkUds; +#endif uv_tcp_t hWorkTCP; // work channel for client, forward channel for server uv_thread_t hWorkThread; uint8_t uvHandleRef = 0; // libuv handle ref -- just main thread now @@ -388,6 +393,9 @@ struct HdcChannel { bool connectLocalDevice = false; bool isStableBuf = false; std::atomic writeFailedTimes; +#ifdef HOST_OHOS + bool isSupportedKillServerCmd = false; +#endif #ifdef HDC_HOST uint64_t startTime = 0; uint64_t endTime = 0; diff --git a/src/common/file.cpp b/src/common/file.cpp index 591219de9b0358c764de2ad10a5dbeea4c9e7264..884102238be952382bef5a8341a9b695026a9b7c 100644 --- a/src/common/file.cpp +++ b/src/common/file.cpp @@ -99,7 +99,7 @@ bool HdcFile::CheckBlacklistPath(CtxFile *context) { // Initialize blacklistFiles, // if you need to add blacklistFiles content, you can use blacklistFiles.insert(""); - std::unordered_set blacklistFiles = {"/data/service/el1/public/hdc"}; + std::unordered_set blacklistFiles = {"/data/service/el1/public/hdc/"}; if (containsBlacklistedSubstring(context->localPath, blacklistFiles)) { LogMsg(MSG_FAIL, "[E005008] Operation not allowed"); return false; diff --git a/src/common/password.cpp b/src/common/password.cpp index 76a621ff0ade5017e68a06d548d032f75509b8c1..200102ab71344716a01ebdb87207c0a3fe7ef46e 100644 --- a/src/common/password.cpp +++ b/src/common/password.cpp @@ -12,14 +12,160 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "password.h" -#include "securec.h" #include "base.h" #include "common.h" +#include "password.h" +#include "sys/socket.h" + namespace Hdc { static const char* SPECIAL_CHARS = "~!@#$%^&*()-_=+\\|[{}];:'\",<.>/?"; static const uint8_t INVALID_HEX_CHAR_TO_INT_RESULT = 255; +std::string HdcPassword::SendToUnixSocketAndRecvStr(const char *socketPath, const std::string &messageStr) +{ + int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sockfd < 0) { + WRITE_LOG(LOG_FATAL, "Failed to create socket."); + return ""; + } + + struct sockaddr_un addr = {}; + addr.sun_family = AF_UNIX; + size_t maxPathLen = sizeof(addr.sun_path) - 1; + size_t pathLen = strlen(socketPath); + if (pathLen > maxPathLen) { + WRITE_LOG(LOG_FATAL, "Socket path too long."); + close(sockfd); + return ""; + } + memcpy_s(addr.sun_path, maxPathLen, socketPath, pathLen); + + if (connect(sockfd, reinterpret_cast(&addr), sizeof(addr)) < 0) { + WRITE_LOG(LOG_FATAL, "Failed to connect to socket."); + close(sockfd); + return ""; + } + + ssize_t bytesSend = send(sockfd, messageStr.c_str(), messageStr.size(), 0); + if (bytesSend < 0) { + WRITE_LOG(LOG_FATAL, "Failed to send message."); + close(sockfd); + return ""; + } + + std::string response; + char buffer[MESSAGE_STR_MAX_LEN] = {0}; + ssize_t bytesRead = 0; + while ((bytesRead = recv(sockfd, buffer, sizeof(buffer) - 1, 0)) > 0) { + response.append(buffer, bytesRead); + if (memset_s(buffer, sizeof(buffer), 0, MESSAGE_STR_MAX_LEN) != EOK) { + WRITE_LOG(LOG_FATAL, "memset_s failed."); + close(sockfd); + return ""; + } + } + if (bytesRead < 0) { + WRITE_LOG(LOG_FATAL, "Failed to read from socket."); + close(sockfd); + return ""; + } + + close(sockfd); + return response; +} + +std::string HdcPassword::SplicMessageStr(const std::string &str, const size_t type) +{ + if (str.empty()) { + WRITE_LOG(LOG_FATAL, "Input string is empty."); + return ""; + } + const size_t bodyLen = str.size(); + size_t totalLength = MESSAGE_METHOD_POS + MESSAGE_METHOD_LEN + + MESSAGE_LENGTH_LEN + bodyLen + 1; + + std::string messageMethodTypeStr = ConvertInt(type, MESSAGE_METHOD_LEN); + if (messageMethodTypeStr.length() != MESSAGE_METHOD_LEN) { + WRITE_LOG(LOG_FATAL, "messageMethodTypeStr length must be:%d,now is:%s", + MESSAGE_METHOD_LEN, messageMethodTypeStr.c_str()); + return ""; + } + + std::string messageBodyLen = ConvertInt(str.length(), MESSAGE_LENGTH_LEN); + if (messageBodyLen.length() > MESSAGE_LENGTH_LEN) { + WRITE_LOG(LOG_FATAL, "messageBodyLen length must be:%d,now is:%s", MESSAGE_LENGTH_LEN, messageBodyLen.c_str()); + return ""; + } + + std::vector newBuffer(totalLength + 1, '\0'); + if (snprintf_s(newBuffer.data(), newBuffer.size(), newBuffer.size() - 1, "%c%s%s%s", ('0' + METHOD_VERSION_V1), + messageMethodTypeStr.c_str(), messageBodyLen.c_str(), str.data()) + < 0) { + WRITE_LOG(LOG_FATAL, "SplicMessage Error!"); + return ""; + } + + std::string result(newBuffer.data(), totalLength); + return result; +} + +std::vector HdcPassword::EncryptGetPwdValue(uint8_t *pwd, int pwdLen) +{ + std::string pwdStr(reinterpret_cast(pwd), pwdLen); + std::string sendStr = SplicMessageStr(pwdStr, METHOD_ENCRYPT); + memset_s(pwdStr.data(), pwdStr.size(), 0, pwdStr.size()); + if (sendStr.empty()) { + WRITE_LOG(LOG_FATAL, "sendStr is empty."); + return std::vector(); + } + std::string recvStr = SendToUnixSocketAndRecvStr(HDC_CREDENTIAL_SOCKET_SANDBOX_PATH, sendStr.c_str()); + memset_s(sendStr.data(), sendStr.size(), 0, sendStr.size()); + if (recvStr.empty()) { + WRITE_LOG(LOG_FATAL, "recvStr is empty."); + return std::vector(); + } + + CredentialMessage messageStruct(recvStr); + memset_s(recvStr.data(), recvStr.size(), 0, recvStr.size()); + if (messageStruct.GetMessageBodyLen() > 0) { + std::string body = messageStruct.GetMessageBody(); + std::vector retByteData = String2Uint8(body, messageStruct.GetMessageBodyLen()); + if (!body.empty()) { + memset_s(&body[0], body.size(), 0, body.size()); + } + return retByteData; + } else { + WRITE_LOG(LOG_FATAL, "Error: messageBodyLen is 0."); + return std::vector(); + } +} + +std::pair HdcPassword::DecryptGetPwdValue(const std::string &encryptData) +{ + std::string sendStr = SplicMessageStr(encryptData, METHOD_DECRYPT); + if (sendStr.empty()) { + WRITE_LOG(LOG_FATAL, "sendStr is empty."); + return std::make_pair(nullptr, 0); + } + std::string recvStr = SendToUnixSocketAndRecvStr(HDC_CREDENTIAL_SOCKET_SANDBOX_PATH, sendStr.c_str()); + memset_s(sendStr.data(), sendStr.size(), 0, sendStr.size()); + if (recvStr.empty()) { + WRITE_LOG(LOG_FATAL, "recvStr is empty."); + return std::make_pair(nullptr, 0); + } + + CredentialMessage messageStruct(recvStr); + memset_s(recvStr.data(), recvStr.size(), 0, recvStr.size()); + if (messageStruct.GetMessageBodyLen() > 0) { + uint8_t *keyData = new uint8_t[messageStruct.GetMessageBodyLen() + 1]; + std::copy(messageStruct.GetMessageBody().begin(), messageStruct.GetMessageBody().end(), keyData); + keyData[messageStruct.GetMessageBodyLen()] = '\0'; + return std::make_pair(keyData, messageStruct.GetMessageBodyLen()); + } else { + WRITE_LOG(LOG_FATAL, "Error: messageBodyLen is 0."); + return std::make_pair(nullptr, 0); + } +} HdcPassword::HdcPassword(const std::string &pwdKeyAlias):hdcHuks(pwdKeyAlias) { memset_s(pwd, sizeof(pwd), 0, sizeof(pwd)); @@ -77,7 +223,7 @@ void HdcPassword::ByteToHex(std::vector& byteData) bool HdcPassword::HexToByte(std::vector& hexData) { - if ((hexData.size() % 2) != 0) { //2 hexData len must be even + if ((hexData.size() % 2) != 0) { // 2 hexData len must be even WRITE_LOG(LOG_FATAL, "invalid data size %d", hexData.size()); return false; } @@ -115,7 +261,7 @@ bool HdcPassword::DecryptPwd(std::vector& encryptData) if (!HexToByte(encryptData)) { return false; } - std::pair result = hdcHuks.AesGcmDecrypt(encryptPwd); + std::pair result = DecryptGetPwdValue(encryptPwd); if (result.first == nullptr) { return false; } @@ -133,7 +279,7 @@ bool HdcPassword::DecryptPwd(std::vector& encryptData) } while (0); if (memset_s(result.first, result.second, 0, PASSWORD_LENGTH) != EOK) { - WRITE_LOG(LOG_FATAL, "memset_s failed"); + WRITE_LOG(LOG_FATAL, "memset_s failed."); success = false; } delete[] result.first; @@ -144,10 +290,7 @@ bool HdcPassword::EncryptPwd(void) { std::vector encryptData; ClearEncryptPwd(); - bool encryptResult = hdcHuks.AesGcmEncrypt(pwd, PASSWORD_LENGTH, encryptData); - if (!encryptResult) { - return false; - } + encryptData = EncryptGetPwdValue(pwd, PASSWORD_LENGTH); ByteToHex(encryptData); return true; } @@ -159,7 +302,7 @@ bool HdcPassword::ResetPwdKey() int HdcPassword::GetEncryptPwdLength() { - return HdcHuks::CaculateGcmEncryptLen(PASSWORD_LENGTH) * 2; //2, bytes to hex + return HdcHuks::CaculateGcmEncryptLen(PASSWORD_LENGTH) * 2; // 2, bytes to hex } void HdcPassword::ClearEncryptPwd(void) diff --git a/src/common/password.h b/src/common/password.h index 8e48c99af1139bd3d71bb6701ef4ada6a5f1236e..6c4eb6dbe1345eb725ccef3c43bac11190cf444d 100644 --- a/src/common/password.h +++ b/src/common/password.h @@ -18,10 +18,15 @@ #include #include #include +#include + +#include "credential_message.h" #include "hdc_huks.h" namespace Hdc { #define PASSWORD_LENGTH 10 +constexpr const char* HDC_CREDENTIAL_SOCKET_SANDBOX_PATH = "/data/hdc/hdc_huks/hdc_credential.socket"; + class HdcPassword { public: ~HdcPassword(); @@ -33,15 +38,22 @@ public: std::string GetEncryptPassword(void); bool ResetPwdKey(); int GetEncryptPwdLength(); + char GetHexChar(uint8_t data); private: uint8_t pwd[PASSWORD_LENGTH]; std::string encryptPwd; HdcHuks hdcHuks; - char GetHexChar(uint8_t data); void ByteToHex(std::vector& byteData); bool HexToByte(std::vector& hexData); uint8_t HexCharToInt(uint8_t data); void ClearEncryptPwd(void); +#ifdef HDC_SUPPORT_ENCRYPT_PRIVATE_KEY + std::string SplicMessageStr(const std::string& str, const size_t type); + std::string SendToUnixSocketAndRecvStr(const char* socketPath, const std::string& messageStr); + std::vector EncryptGetPwdValue(uint8_t* pwd, int pwdLen); + std::pair DecryptGetPwdValue(const std::string& encryptData); +#endif }; + } // namespace Hdc #endif // HDC_PASSWORD_H \ No newline at end of file diff --git a/src/daemon/etc/BUILD.gn b/src/daemon/etc/BUILD.gn index 3b9687ee5bafd9f7e7b24d771bb48122d289363b..3a9547bd1822980ee52589191ce744d8f1cc1057 100644 --- a/src/daemon/etc/BUILD.gn +++ b/src/daemon/etc/BUILD.gn @@ -19,9 +19,19 @@ group("daemon_etc") { ":hdc.para", ":hdc.para.dac", ":hdcd.cfg", + ":hdc_credential.cfg", ] } +ohos_prebuilt_etc("hdc_credential.cfg") { + source = "hdc_credential.cfg" + relative_install_dir = "init" + install_images = [ "system" ] + output = "hdc_credential.cfg" + part_name = "hdc" + subsystem_name = "developtools" +} + ohos_prebuilt_etc("hdcd.cfg") { source = "hdcd.root.cfg" if (build_variant == "user") { diff --git a/src/daemon/etc/hdc_credential.cfg b/src/daemon/etc/hdc_credential.cfg new file mode 100644 index 0000000000000000000000000000000000000000..5bcc5a84a5e2b20348abe9251e77c60263a333f5 --- /dev/null +++ b/src/daemon/etc/hdc_credential.cfg @@ -0,0 +1,35 @@ +{ + "jobs" : [{ + "name" : "post-fs-data", + "cmds" : [ + "mkdir /data/service/el1/public/hdc_server 2711 hdc hdc", + "mkdir /data/service/el1/public/hdc_server/hdc_common 2711 hdc hdc", + "restorecon /data/service/el1/public/hdc_server", + "restorecon /data/service/el1/public/hdc_server/hdc_common", + "start hdc_credential" + ] + } + ], + "services" : [{ + "name" : "hdc_credential", + "path" : ["/system/bin/hdc_credential"], + "uid" : "hdc", + "gid" : [ "hdc", "file_manager", "netsys_socket" ], + "socket" : [{ + "name" : "hdc", + "family" : "AF_UNIX", + "type" : "SOCK_SEQPACKET", + "protocol" : "default", + "permissions" : "0660", + "uid" : "hdc", + "gid" : "hdc" + }], + "apl" : "normal", + "permission" : [ "ohos.permission.INTERACT_ACROSS_LOCAL_ACCOUNTS" ], + "sandbox" : 0, + "start-mode" : "condition", + "secon" : "u:r:hdc_credential:s0", + "disabled" : 1 + } + ] +} \ No newline at end of file diff --git a/src/host/client.cpp b/src/host/client.cpp index 4cf0db854dae8132263f1701e981d62c25d6df33..b818db21669aea8d08a98c26cf67a0e8f176b0d9 100755 --- a/src/host/client.cpp +++ b/src/host/client.cpp @@ -18,6 +18,9 @@ #endif #include "host_updater.h" #include "server.h" +#ifdef __OHOS__ +#include +#endif #include "file.h" std::map g_lists; @@ -28,6 +31,11 @@ bool g_terminalStateChange = false; HdcClient::HdcClient(const bool serverOrClient, const string &addrString, uv_loop_t *loopMainIn, bool checkVersion) : HdcChannelBase(serverOrClient, addrString, loopMainIn) { +#ifdef __OHOS__ + serverAddress = addrString; + channel = new HdcChannel(); + channel->isUds = (serverAddress.empty() || serverAddress == UDS_STR); +#endif MallocChannel(&channel); // free by logic debugRetryCount = 0; #ifndef _WIN32 @@ -57,13 +65,20 @@ void HdcClient::NotifyInstanceChannelFree(HChannel hChannel) uint32_t HdcClient::GetLastPID() { char bufPath[BUF_SIZE_MEDIUM] = ""; - size_t size = BUF_SIZE_MEDIUM; char pidBuf[BUF_SIZE_TINY] = ""; // get running pid to kill it + size_t size = BUF_SIZE_MEDIUM; +#ifndef HOST_OHOS if (uv_os_tmpdir(bufPath, &size) < 0) { WRITE_LOG(LOG_FATAL, "Tmppath failed"); return 0; } +#else + if (uv_os_homedir(bufPath, &size) < 0) { + WRITE_LOG(LOG_FATAL, "Homepath failed"); + return 0; + } +#endif string path = Base::StringFormat("%s%c.%s.pid", bufPath, Base::GetPathSep(), SERVER_NAME.c_str()); Base::ReadBinFile(path.c_str(), reinterpret_cast(&pidBuf), BUF_SIZE_TINY); int pid = atoi(pidBuf); // pid maybe 0 @@ -228,6 +243,9 @@ string HdcClient::AutoConnectKey(string &doCommand, const string &preConnectKey) vecNoConnectKeyCommand.push_back(CMDSTR_SOFTWARE_VERSION); vecNoConnectKeyCommand.push_back(CMDSTR_SOFTWARE_HELP); vecNoConnectKeyCommand.push_back(CMDSTR_TARGET_DISCOVER); +#ifdef HOST_OHOS + vecNoConnectKeyCommand.push_back(CMDSTR_SERVICE_KILL); +#endif vecNoConnectKeyCommand.push_back(CMDSTR_LIST_TARGETS); vecNoConnectKeyCommand.push_back(CMDSTR_CHECK_SERVER); vecNoConnectKeyCommand.push_back(CMDSTR_CONNECT_TARGET); @@ -427,9 +445,11 @@ int HdcClient::ExecuteCommand(const string &commandIn) uint16_t port = 0; int ret = Base::ConnectKey2IPPort(channelHostPort.c_str(), ip, &port, sizeof(ip)); if (ret < 0) { +#ifndef __OHOS__ WRITE_LOG(LOG_FATAL, "ConnectKey2IPPort %s failed with %d", channelHostPort.c_str(), ret); return -1; +#endif } if (!strncmp(commandIn.c_str(), CMDSTR_HILOG.c_str(), CMDSTR_HILOG.size()) && @@ -448,7 +468,16 @@ int HdcClient::ExecuteCommand(const string &commandIn) } command = commandIn; connectKey = AutoConnectKey(command, connectKey); +#ifdef __OHOS__ + AdminChannel(OP_UPDATE, channel->channelId, channel); + if (channel->isUds) { + ConnectUdsServerForClient(); + } else { + ConnectServerForClient(ip, port); + } +#else ConnectServerForClient(ip, port); +#endif uv_timer_init(loopMain, &waitTimeDoCmd); waitTimeDoCmd.data = this; uv_timer_start(&waitTimeDoCmd, CommandWorker, UV_START_TIMEOUT, UV_START_REPEAT); @@ -459,6 +488,11 @@ int HdcClient::ExecuteCommand(const string &commandIn) int HdcClient::Initial(const string &connectKeyIn) { connectKey = connectKeyIn; +#ifdef __OHOS__ + if (channel->isUds) { + return 0; + } +#endif if (!channelHostPort.size() || !channelHost.size() || !channelPort) { WRITE_LOG(LOG_FATAL, "Listen string initial failed"); return ERR_PARM_FAIL; @@ -466,6 +500,29 @@ int HdcClient::Initial(const string &connectKeyIn) return 0; } +#ifdef __OHOS__ +int HdcClient::ConnectUdsServerForClient() +{ + if (uv_is_closing((const uv_handle_t *)&channel->hWorkUds)) { + WRITE_LOG(LOG_FATAL, "ConnectServerForClient uv_is_closing"); + return ERR_SOCKET_FAIL; + } + WRITE_LOG(LOG_DEBUG, "Try to connect uds"); + uv_connect_t *conn = new(std::nothrow) uv_connect_t(); + if (conn == nullptr) { + WRITE_LOG(LOG_FATAL, "ConnectServerForClient new conn failed"); + return ERR_GENERIC; + } + conn->data = this; + udsConnectRetryCount = 0; + uv_timer_init(loopMain, &retryUdsConnTimer); + retryUdsConnTimer.data = this; + + uv_pipe_connect(conn, (uv_pipe_t *)&channel->hWorkUds, UDS_PATH.c_str(), ConnectUds); + return 0; +} +#endif + int HdcClient::ConnectServerForClient(const char *ip, uint16_t port) { if (uv_is_closing((const uv_handle_t *)&channel->hWorkTCP)) { @@ -518,6 +575,14 @@ void HdcClient::CommandWorker(uv_timer_t *handle) return; } uv_timer_stop(handle); +#ifdef HOST_OHOS + if (!strncmp(thisClass->command.c_str(), CMDSTR_SERVICE_KILL.c_str(), + CMDSTR_SERVICE_KILL.size()) && !thisClass->channel->isSupportedKillServerCmd) { + WRITE_LOG(LOG_DEBUG, "uv_kill server"); + thisClass->CtrlServiceWork(CMDSTR_SERVICE_KILL.c_str()); + return; + } +#endif WRITE_LOG(LOG_DEBUG, "Connect server successful"); bool closeInput = false; if (!HostUpdater::ConfirmCommand(thisClass->command, closeInput)) { @@ -629,6 +694,41 @@ void HdcClient::BindLocalStd(HChannel hChannel) } } +#ifdef __OHOS__ +void HdcClient::ConnectUds(uv_connect_t *connection, int status) +{ + WRITE_LOG(LOG_DEBUG, "Enter ConnectUds, status:%d", status); + HdcClient *thisClass = (HdcClient *)connection->data; + CALLSTAT_GUARD(thisClass->loopMainStatus, connection->handle->loop, "HdcClient::Connect"); + delete connection; + HChannel hChannel = reinterpret_cast(thisClass->channel); + if (uv_is_closing((const uv_handle_t *)&hChannel->hWorkUds)) { + WRITE_LOG(LOG_DEBUG, "uv_is_closing..."); + thisClass->FreeChannel(hChannel->channelId); + return; + } + + // connect success + if (status == 0) { + thisClass->BindLocalStd(hChannel); + Base::SetUdsOptions((uv_pipe_t *)&hChannel->hWorkUds); + WRITE_LOG(LOG_DEBUG, "uv_read_start"); + uv_read_start((uv_stream_t *)&hChannel->hWorkUds, AllocCallback, ReadStream); + return; + } + + // connect failed, start timer and retry + WRITE_LOG(LOG_DEBUG, "retry count:%d", thisClass->udsConnectRetryCount); + if (thisClass->udsConnectRetryCount >= TCP_CONNECT_MAX_RETRY_COUNT) { + WRITE_LOG(LOG_DEBUG, "stop retry for connect"); + thisClass->FreeChannel(hChannel->channelId); + return; + } + thisClass->udsConnectRetryCount++; + uv_timer_start(&(thisClass->retryUdsConnTimer), thisClass->RetryUdsConnectWorker, TCP_CONNECT_RETRY_TIME_MS, 0); +} +#endif + void HdcClient::Connect(uv_connect_t *connection, int status) { WRITE_LOG(LOG_DEBUG, "Enter Connect, status:%d", status); @@ -662,6 +762,24 @@ void HdcClient::Connect(uv_connect_t *connection, int status) uv_timer_start(&(thisClass->retryTcpConnTimer), thisClass->RetryTcpConnectWorker, TCP_CONNECT_RETRY_TIME_MS, 0); } +#ifdef __OHOS__ +void HdcClient::RetryUdsConnectWorker(uv_timer_t *handle) +{ + HdcClient *thisClass = (HdcClient *)handle->data; + HChannel hChannel = reinterpret_cast(thisClass->channel); + CALLSTAT_GUARD(thisClass->loopMainStatus, handle->loop, "HdcClient::RetryUdsConnectWorker"); + uv_connect_t *connection = new(std::nothrow) uv_connect_t(); + if (connection == nullptr) { + WRITE_LOG(LOG_FATAL, "RetryUdsConnectWorker new conn failed"); + thisClass->FreeChannel(hChannel->channelId); + return; + } + connection->data = thisClass; + WRITE_LOG(LOG_DEBUG, "RetryUdsConnectWorker start tcp connect"); + uv_pipe_connect(connection, &(thisClass->channel->hWorkUds), UDS_PATH.c_str(), thisClass->ConnectUds); +} +#endif + void HdcClient::RetryTcpConnectWorker(uv_timer_t *handle) { HdcClient *thisClass = (HdcClient *)handle->data; @@ -693,8 +811,13 @@ int HdcClient::PreHandshake(HChannel hChannel, const uint8_t *buf) return ERR_BUF_CHECK; } hChannel->isStableBuf = (hShake->banner[BANNER_FEATURE_TAG_OFFSET] != HUGE_BUF_TAG); - WRITE_LOG(LOG_DEBUG, "Channel PreHandshake isStableBuf:%d", - hChannel->isStableBuf); +#ifdef HOST_OHOS + hChannel->isSupportedKillServerCmd = (hShake->banner[SERVICE_KILL_OFFSET] == SERVICE_KILL_TAG); + WRITE_LOG(LOG_DEBUG, "Channel PreHandshake isStableBuf:%d, killflag:%d", + hChannel->isStableBuf, hChannel->isSupportedKillServerCmd); +#else + WRITE_LOG(LOG_DEBUG, "Channel PreHandshake isStableBuf:%d", hChannel->isStableBuf); +#endif if (this->command == CMDSTR_WAIT_FOR && !connectKey.empty()) { hShake->banner[WAIT_TAG_OFFSET] = WAIT_DEVICE_TAG; } @@ -712,13 +835,11 @@ int HdcClient::PreHandshake(HChannel hChannel, const uint8_t *buf) WRITE_LOG(LOG_DEBUG, "Channel Hello failed"); return ERR_BUF_COPY; } - #ifdef HDC_VERSION_CHECK // add check version if (!isCheckVersionCmd) { // do not check version cause user want to get server version string clientVer = Base::GetVersion() + HDC_MSG_HASH; string serverVer(hShake->version); - if (clientVer != serverVer) { serverVer = serverVer.substr(0, Base::GetVersion().size()); WRITE_LOG(LOG_FATAL, "Client version:%s, server version:%s", clientVer.c_str(), serverVer.c_str()); diff --git a/src/host/client.h b/src/host/client.h index dd93eada0762c9093532999eb4bcd78cf284ff79..f6d88bc37b1babdb5a90a9926d1ef40d61f824d7 100755 --- a/src/host/client.h +++ b/src/host/client.h @@ -40,6 +40,11 @@ private: static void ReadStd(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf); static void CommandWorker(uv_timer_t *handle); static void RetryTcpConnectWorker(uv_timer_t *handle); +#ifdef __OHOS__ + static void RetryUdsConnectWorker(uv_timer_t *handle); + static void ConnectUds(uv_connect_t *connection, int status); + int ConnectUdsServerForClient(); +#endif int ConnectServerForClient(const char *ip, uint16_t port); int ReadChannel(HChannel hChannel, uint8_t *buf, const int bytesIO) override; int PreHandshake(HChannel hChannel, const uint8_t *buf); @@ -88,6 +93,11 @@ private: struct sockaddr_in6 dest; uv_timer_t retryTcpConnTimer; uint16_t tcpConnectRetryCount = 0; +#ifdef __OHOS__ + string serverAddress; + uv_timer_t retryUdsConnTimer; + uint16_t udsConnectRetryCount = 0; +#endif }; } // namespace Hdc #endif diff --git a/src/host/host_usb.h b/src/host/host_usb.h index 21493c81ba7b257524601523a6abfced408777f2..15c1eafa5d760c33a34132299a9ed8eabbf29f1c 100644 --- a/src/host/host_usb.h +++ b/src/host/host_usb.h @@ -36,6 +36,7 @@ public: void RemoveIgnoreDevice(string &mountInfo); static libusb_log_level GetLibusbLogLevel(void); static void SetLibusbLogLevelEnv(libusb_log_level logLevel); + void SendSoftResetToDaemon(HSession hSession, uint32_t sessionIdOld); private: enum UsbCheckStatus { @@ -69,7 +70,6 @@ private: void CancelUsbIo(HSession hSession) override; int UsbToHdcProtocol(uv_stream_t *stream, uint8_t *appendData, int dataSize) override; int SubmitUsbBio(HSession hSession, bool sendOrRecv, uint8_t *buf, int bufSize); - void SendSoftResetToDaemon(HSession hSession, uint32_t sessionIdOld); libusb_context *ctxUSB; uv_timer_t devListWatcher; diff --git a/src/host/main.cpp b/src/host/main.cpp index 817e2b4082fd746b1ab205d31a6484c99531656f..933e43f85d821f26ac270f6f3b80fd433c46accc 100644 --- a/src/host/main.cpp +++ b/src/host/main.cpp @@ -21,6 +21,9 @@ #ifdef _WIN32 #include #endif +#ifdef __OHOS__ +#include +#endif #ifndef HARMONY_PROJECT #include "ut_command.h" @@ -158,9 +161,11 @@ int SplitOptionAndCommand(int argc, const char **argv, string &outOption, string int RunServerMode(string &serverListenString) { +#ifndef __OHOS__ if (serverListenString.empty()) { return -1; } +#endif /* * Notice !!!!!! * For hdc server, all setenv must befor Base::RemoveLogFile() @@ -211,8 +216,12 @@ int RunClientMode(string &commands, string &serverListenString, string &connectK std::cerr << TranslateCommand::Usage(); return 0; } +#ifdef HOST_OHOS + if (!strncmp(commands.c_str(), CMDSTR_GENERATE_KEY.c_str(), CMDSTR_GENERATE_KEY.size())) { +#else if (!strncmp(commands.c_str(), CMDSTR_GENERATE_KEY.c_str(), CMDSTR_GENERATE_KEY.size()) || !strncmp(commands.c_str(), CMDSTR_SERVICE_KILL.c_str(), CMDSTR_SERVICE_KILL.size())) { +#endif client.CtrlServiceWork(commands.c_str()); return 0; } @@ -221,17 +230,76 @@ int RunClientMode(string &commands, string &serverListenString, string &connectK return 0; } if (isPullServer && Base::ProgramMutex(SERVER_NAME.c_str(), true) == 0) { +#ifdef HOST_OHOS + if (!strncmp(commands.c_str(), CMDSTR_SERVICE_KILL.c_str(), + CMDSTR_SERVICE_KILL.size())) { + WRITE_LOG(LOG_DEBUG, "kill server, but server not exist, so do nothing"); + return 0; + } +#endif // default pullup, just default listenstr.If want to customer listen-string, please use 'hdc -m -s lanip:port' HdcServer::PullupServer(serverListenString.c_str()); uv_sleep(START_SERVER_FOR_CLIENT_TIME); // give time to start serverForClient,at least 200ms } client.Initial(connectKey); client.ExecuteCommand(commands.c_str()); +#ifdef HOST_OHOS + if (!strncmp(commands.c_str(), CMDSTR_SERVICE_KILL.c_str(), CMDSTR_SERVICE_KILL.size())) { + //server need restart + string &cmd = commands; + if (cmd.find("-r") != std::string::npos) { + HdcServer::PullupServer(serverListenString.c_str()); + uv_sleep(START_SERVER_FOR_CLIENT_TIME); + } + } +#endif return 0; } +#ifdef __OHOS__ +bool IsHiShellLabel() +{ + pid_t pid = getpid(); + char pathBuf[BUF_SIZE_DEFAULT] = ""; + if (snprintf_s(pathBuf, sizeof(pathBuf), sizeof(pathBuf) - 1, "/proc/%d/attr/current", pid) < 0) { + WRITE_LOG(LOG_FATAL, "get pathBuf failed, pid is %d", pid); + return false; + } + + const char* attrName = "security.selinux"; + // get attribute size + ssize_t attrSize = getxattr(pathBuf, attrName, nullptr, 0); + if (attrSize == 0 || attrSize == - 1) { + return false; + } + char* attrValue = new(std::nothrow) char[attrSize]; + if (attrValue == nullptr) { + return false; + } + // get attribute value + if (getxattr(pathBuf, attrName, attrValue, attrSize) == -1) { + delete []attrValue; + return false; + } + string label(attrValue, attrSize - 1); + delete []attrValue; + return label == "u:r:hishell_hap:s0"; +} +#endif + bool ParseServerListenString(string &serverListenString, char *optarg) { +#ifdef __OHOS__ + string temp = optarg; + if (temp == UDS_STR) { + serverListenString = temp; + return true; + } + if (!IsHiShellLabel()) { + Base::PrintMessage("[E001105] Unsupport option [s], please try command in HiShell."); + return false; + } +#endif if (strlen(optarg) > strlen("0000::0000:0000:0000:0000%interfacename:65535")) { Base::PrintMessage("Unknown content of parament '-s'"); return false; @@ -453,8 +521,9 @@ int main(int argc, const char *argv[]) int optArgc = 0; char **optArgv = Base::SplitCommandToArgs(options.c_str(), &optArgc); bool cmdOptionResult; - +#ifndef __OHOS__ InitServerAddr(); +#endif cmdOptionResult = GetCommandlineOptions(optArgc, const_cast(optArgv)); delete[](reinterpret_cast(optArgv)); if (cmdOptionResult) { @@ -470,6 +539,11 @@ int main(int argc, const char *argv[]) } else if (g_isPcDebugRun) { Hdc::RunPcDebugMode(g_isPullServer, g_isTCPorUSB, g_isTestMethod); } else { +#ifdef __OHOS__ + if (g_serverListenString.empty()) { + g_serverListenString = UDS_STR; + } +#endif if (!g_isCustomLoglevel) { Base::SetLogLevel(LOG_INFO); } diff --git a/src/host/server.cpp b/src/host/server.cpp index e85406d4a4d14dd1bb6299c80d8ae2f21aac29b7..7b1f2fafa0b7980847fa1ffbf0b84bd640c8ca17 100644 --- a/src/host/server.cpp +++ b/src/host/server.cpp @@ -762,7 +762,15 @@ bool HdcServer::FetchCommand(HSession hSession, const uint32_t channelId, const pdiNew->forwardDirection = (reinterpret_cast(payload))[0] == '1'; pdiNew->taskString = reinterpret_cast(payload); AdminForwardMap(OP_ADD, STRING_EMPTY, pdiNew); +#ifdef __OHOS__ + if (hChannel->isUds) { + Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkUds); + } else { + Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkTCP); + } +#else Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkTCP); // detch client channel +#endif break; } case CMD_FILE_INIT: @@ -1034,7 +1042,126 @@ int HdcServer::CreateConnect(const string &connectKey, bool isCheck) return RET_SUCCESS; } +#ifdef HOST_OHOS +void HdcServer::AttachChannelInnerForUds(HSession hSession, const uint32_t channelId) +{ + int ret = 0; + HdcServerForClient *hSfc = static_cast(clsServerForClient); + HChannel hChannel = hSfc->AdminChannel(OP_QUERY_REF, channelId, nullptr); + if (!hChannel) { + WRITE_LOG(LOG_DEBUG, "AttachChannelInnerForUds hChannel null channelId:%u", channelId); + return; + } + uv_pipe_init(&hSession->childLoop, &hChannel->hChildWorkUds, 0); + hChannel->hChildWorkUds.data = hChannel; + hChannel->loopStatus = &hSession->childLoopStatus; + hChannel->targetSessionId = hSession->sessionId; + hSession->commandCount++; + if ((ret = uv_pipe_open((uv_pipe_t *)&hChannel->hChildWorkUds, hChannel->fdChildWorkTCP)) < 0) { + constexpr int bufSize = 1024; + char buf[bufSize] = { 0 }; + uv_err_name_r(ret, buf, bufSize); + WRITE_LOG(LOG_WARN, "Hdcserver AttachChannel uv_tcp_open failed %s, channelid:%d fdChildWorkTCP:%d", + buf, hChannel->channelId, hChannel->fdChildWorkTCP); + Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkUds); + --hChannel->ref; + return; + } + Base::SetUdsOptions((uv_pipe_t *)&hChannel->hChildWorkUds); + uv_read_start((uv_stream_t *)&hChannel->hChildWorkUds, hSfc->AllocCallback, hSfc->ReadStream); + --hChannel->ref; + WRITE_LOG(LOG_INFO, "AttachChannelInnerForUds"); +}; + +void HdcServer::DeatchChannelInnerForUds(HSession hSession, const uint32_t channelId) +{ + HdcServerForClient *hSfc = static_cast(clsServerForClient); + // childCleared has not set, no need OP_QUERY_REF + HChannel hChannel = hSfc->AdminChannel(OP_QUERY, channelId, nullptr); + if (!hChannel) { + ClearOwnTasks(hSession, channelId); + uint8_t count = 0; + Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, &count, 1); + WRITE_LOG(LOG_WARN, "DeatchChannelInnerForUds hChannel null channelId:%u", channelId); + return; + } + if (hChannel->childCleared) { + WRITE_LOG(LOG_DEBUG, "Childchannel has already freed, cid:%u", channelId); + return; + } + // The own task for this channel must be clear before free channel + ClearOwnTasks(hSession, channelId); + uint8_t count = 0; + Send(hSession->sessionId, hChannel->channelId, CMD_KERNEL_CHANNEL_CLOSE, &count, 1); + WRITE_LOG(LOG_DEBUG, "Childchannel begin close, cid:%u, sid:%u", hChannel->channelId, hSession->sessionId); + if (uv_is_closing((const uv_handle_t *)&hChannel->hChildWorkUds)) { + Base::DoNextLoop(&hSession->childLoop, hChannel, [](const uint8_t flag, string &msg, const void *data) { + HChannel hChannel = (HChannel)data; + hChannel->childCleared = true; + WRITE_LOG(LOG_DEBUG, "Childchannel free direct, cid:%u", hChannel->channelId); + }); + } else { + if (hChannel->hChildWorkUds.loop == NULL) { + WRITE_LOG(LOG_DEBUG, "Childchannel loop is null, cid:%u", hChannel->channelId); + } + Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkUds, [](uv_handle_t *handle) -> void { + HChannel hChannel = (HChannel)handle->data; + hChannel->childCleared = true; + WRITE_LOG(LOG_DEBUG, "Childchannel free callback, cid:%u", hChannel->channelId); + }); + } +}; + void HdcServer::AttachChannel(HSession hSession, const uint32_t channelId) +{ + HdcServerForClient *hSfc = static_cast(clsServerForClient); + HChannel hChannel = hSfc->AdminChannel(OP_QUERY, channelId, nullptr); + if (!hChannel) { + WRITE_LOG(LOG_DEBUG, "AttachChannel hChannel null channelId:%u", channelId); + return; + } + if (hChannel->isUds) { + AttachChannelInnerForUds(hSession, channelId); + } else { + AttachChannelInnerForTcp(hSession, channelId); + } +} + +void HdcServer::DeatchChannel(HSession hSession, const uint32_t channelId) +{ + HdcServerForClient *hSfc = static_cast(clsServerForClient); + // childCleared has not set, no need OP_QUERY_REF + HChannel hChannel = hSfc->AdminChannel(OP_QUERY, channelId, nullptr); + if (!hChannel) { + ClearOwnTasks(hSession, channelId); + uint8_t count = 0; + Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, &count, 1); + WRITE_LOG(LOG_WARN, "DeatchChannel hChannel null channelId:%u", channelId); + return; + } + if (hChannel->childCleared) { + WRITE_LOG(LOG_DEBUG, "Childchannel has already freed, cid:%u", channelId); + return; + } + if (hChannel->isUds) { + DeatchChannelInnerForUds(hSession, channelId); + } else { + DeatchChannelInnerForTcp(hSession, channelId); + } +} +#else +void HdcServer::AttachChannel(HSession hSession, const uint32_t channelId) +{ + AttachChannelInnerForTcp(hSession, channelId); +} + +void HdcServer::DeatchChannel(HSession hSession, const uint32_t channelId) +{ + DeatchChannelInnerForTcp(hSession, channelId); +} +#endif + +void HdcServer::AttachChannelInnerForTcp(HSession hSession, const uint32_t channelId) { int ret = 0; HdcServerForClient *hSfc = static_cast(clsServerForClient); @@ -1063,7 +1190,7 @@ void HdcServer::AttachChannel(HSession hSession, const uint32_t channelId) --hChannel->ref; }; -void HdcServer::DeatchChannel(HSession hSession, const uint32_t channelId) +void HdcServer::DeatchChannelInnerForTcp(HSession hSession, const uint32_t channelId) { HdcServerForClient *hSfc = static_cast(clsServerForClient); // childCleared has not set, no need OP_QUERY_REF @@ -1213,4 +1340,29 @@ void HdcServer::PrintCmdLogEx(const string& cmdStr) Hdc::ServerCmdLog::GetInstance().PushCmdLogStr(cmdStr); } +void HdcServer::SessionSoftReset() +{ +#ifdef HOST_OHOS + uv_rwlock_rdlock(&daemonAdmin); + map::iterator iter; + for (iter = mapDaemon.begin(); iter != mapDaemon.end(); ++iter) { + HDaemonInfo di = iter->second; + if (di == nullptr) { + continue; + } + string devname = di->devName; + if (devname.empty()) { + continue; + } + if (di->connType == CONN_USB) { + HSession hSession = di->hSession; + if (hSession == nullptr) { + continue; + } + clsUSBClt->SendSoftResetToDaemon(hSession, 0); + } + } + uv_rwlock_rdunlock(&daemonAdmin); +#endif +} } // namespace Hdc diff --git a/src/host/server.h b/src/host/server.h index 607146ca80dda0a9059c2b3fc6febe989a658dde..420e970bd3eb010d3221c97a158c5e59f451ddca 100644 --- a/src/host/server.h +++ b/src/host/server.h @@ -31,10 +31,17 @@ public: bool Initial(const char *listenString); void AttachChannel(HSession hSession, const uint32_t channelId) override; void DeatchChannel(HSession hSession, const uint32_t channelId) override; + void AttachChannelInnerForTcp(HSession hSession, const uint32_t channelId); + void DeatchChannelInnerForTcp(HSession hSession, const uint32_t channelId); +#ifdef HOST_OHOS + void AttachChannelInnerForUds(HSession hSession, const uint32_t channelId); + void DeatchChannelInnerForUds(HSession hSession, const uint32_t channelId); +#endif virtual void EchoToClientsForSession(uint32_t targetSessionId, const string &echo); static bool PullupServer(const char *listenString); static void UsbPreConnect(uv_timer_t *handle); void NotifyInstanceSessionFree(HSession hSession, bool freeOrClear) override; + void SessionSoftReset(); HdcHostTCP *clsTCPClt; HdcHostUSB *clsUSBClt; diff --git a/src/host/server_for_client.cpp b/src/host/server_for_client.cpp index dd6167c3efc2f1deb263705e79f3870176dd5ffc..4615dd00927c1de1a3a3025af052c93480f67d12 100644 --- a/src/host/server_for_client.cpp +++ b/src/host/server_for_client.cpp @@ -17,10 +17,16 @@ #include "hdc_hash_gen.h" #endif #include "server.h" +#ifdef __OHOS__ +#include +#endif #include "host_shell_option.h" namespace Hdc { static const int MAX_RETRY_COUNT = 500; static const int MAX_CONNECT_DEVICE_RETRY_COUNT = 100; +#ifdef __OHOS__ +static const int MAX_CONNECTIONS_COUNT = 16; +#endif HdcServerForClient::HdcServerForClient(const bool serverOrClient, const string &addrString, void *pClsServer, uv_loop_t *loopMainIn) @@ -37,6 +43,9 @@ HdcServerForClient::~HdcServerForClient() void HdcServerForClient::Stop() { Base::TryCloseHandle((uv_handle_t *)&tcpListen); +#ifdef __OHOS__ + Base::TryCloseHandle((uv_handle_t *)&udsListen); +#endif } uint16_t HdcServerForClient::GetTCPListenPort() @@ -44,13 +53,72 @@ uint16_t HdcServerForClient::GetTCPListenPort() return channelPort; } +#ifdef __OHOS__ +void HdcServerForClient::AcceptUdsClient(uv_stream_t *server, int status) +{ + StartTraceScope("HdcServerForClient::AcceptUdsClient"); + HdcServerForClient *thisClass = (HdcServerForClient *)(((uv_pipe_t *)server)->data); + CALLSTAT_GUARD(thisClass->loopMainStatus, server->loop, "HdcServerForClient::AcceptUdsClient"); + HChannel hChannel = new HdcChannel(); + hChannel->isUds = true; + uint32_t uid = thisClass->MallocChannel(&hChannel); + hChannel->startTime = Base::GetRuntimeMSec(); + int rc = 0; + if ((rc = uv_accept(server, (uv_stream_t *)&hChannel->hWorkUds)) < 0) { + WRITE_LOG(LOG_FATAL, "AcceptUdsClient uv_accept error rc:%d uid:%u", rc, uid); + thisClass->FreeChannel(uid); + return; + } + WRITE_LOG(LOG_DEBUG, "AcceptUdsClient uid:%u", uid); + // limit first recv + int bufMaxSize = 0; + uv_recv_buffer_size((uv_handle_t *)&hChannel->hWorkUds, &bufMaxSize); + auto funcChannelHeaderAlloc = [](uv_handle_t *handle, size_t sizeWanted, uv_buf_t *buf) -> void { + HChannel context = (HChannel)handle->data; + Base::ReallocBuf(&context->ioBuf, &context->bufSize, Base::GetMaxBufSize() * BUF_EXTEND_SIZE); + buf->base = (char *)context->ioBuf + context->availTailIndex; +#ifdef HDC_VERSION_CHECK + buf->len = sizeof(struct ChannelHandShake) + DWORD_SERIALIZE_SIZE; // only recv static size +#else + buf->len = offsetof(struct ChannelHandShake, version) + DWORD_SERIALIZE_SIZE; +#endif + }; + // first packet static size, after this packet will be dup for normal recv + uv_read_start((uv_stream_t *)&hChannel->hWorkUds, funcChannelHeaderAlloc, ReadStream); + // channel handshake step1 + struct ChannelHandShake handShake = {}; + if (EOK == strcpy_s(handShake.banner, sizeof(handShake.banner), HANDSHAKE_MESSAGE.c_str())) { + handShake.banner[BANNER_FEATURE_TAG_OFFSET] = HUGE_BUF_TAG; // set feature tag for huge buf size + handShake.banner[SERVICE_KILL_OFFSET] = SERVICE_KILL_TAG; + handShake.channelId = htonl(hChannel->channelId); + string ver = Base::GetVersion() + HDC_MSG_HASH; + WRITE_LOG(LOG_DEBUG, "Server ver:%s", ver.c_str()); + if (EOK != strcpy_s(handShake.version, sizeof(handShake.version), ver.c_str())) { + WRITE_LOG(LOG_FATAL, "strcpy_s failed"); + return; + } +#ifdef HDC_VERSION_CHECK + thisClass->Send(hChannel->channelId, (uint8_t *)&handShake, sizeof(struct ChannelHandShake)); +#else + // do not send version message if check feature disable + thisClass->Send(hChannel->channelId, reinterpret_cast(&handShake), + offsetof(struct ChannelHandShake, version)); +#endif + } +} +#endif + void HdcServerForClient::AcceptClient(uv_stream_t *server, int status) { StartTraceScope("HdcServerForClient::AcceptClient"); uv_tcp_t *pServTCP = (uv_tcp_t *)server; HdcServerForClient *thisClass = (HdcServerForClient *)pServTCP->data; CALLSTAT_GUARD(thisClass->loopMainStatus, server->loop, "HdcServerForClient::AcceptClient"); +#ifdef HOST_OHOS + HChannel hChannel = new HdcChannel(); +#else HChannel hChannel = nullptr; +#endif uint32_t uid = thisClass->MallocChannel(&hChannel); hChannel->startTime = Base::GetRuntimeMSec(); if (!hChannel) { @@ -83,6 +151,9 @@ void HdcServerForClient::AcceptClient(uv_stream_t *server, int status) struct ChannelHandShake handShake = {}; if (EOK == strcpy_s(handShake.banner, sizeof(handShake.banner), HANDSHAKE_MESSAGE.c_str())) { handShake.banner[BANNER_FEATURE_TAG_OFFSET] = HUGE_BUF_TAG; // set feature tag for huge buf size +#ifdef HOST_OHOS + handShake.banner[SERVICE_KILL_OFFSET] = SERVICE_KILL_TAG; +#endif handShake.channelId = htonl(hChannel->channelId); string ver = Base::GetVersion() + HDC_MSG_HASH; WRITE_LOG(LOG_DEBUG, "Server ver:%s", ver.c_str()); @@ -100,6 +171,40 @@ void HdcServerForClient::AcceptClient(uv_stream_t *server, int status) } } +#ifdef __OHOS__ +bool HdcServerForClient::SetUdsListen() +{ + udsListen.data = this; + int ret = -1; + ret = uv_pipe_init(loopMain, &udsListen, 0); + + unlink(UDS_PATH.c_str()); + + if ((ret = uv_pipe_bind(&udsListen, UDS_PATH.c_str())) != 0) { + WRITE_LOG(LOG_WARN, "bind uds addr fail! ret:%d", ret); + return false; + } + + uv_fs_t req = {}; + ret = uv_fs_chmod(nullptr, &req, UDS_PATH.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, + nullptr); + if (ret < 0) { + char buffer[BUF_SIZE_DEFAULT] = { 0 }; + uv_strerror_r(ret, buffer, BUF_SIZE_DEFAULT); + WRITE_LOG(LOG_WARN, "uv_fs_chmod uds failed %s", buffer); + uv_fs_req_cleanup(&req); + return false; + } + uv_fs_req_cleanup(&req); + + if ((ret = uv_listen((uv_stream_t *)&udsListen, MAX_CONNECTIONS_COUNT, AcceptUdsClient)) != 0) { + WRITE_LOG(LOG_WARN, "uds listen fail! ret:%d", ret); + return false; + } + return true; +} +#endif + bool HdcServerForClient::SetTCPListen() { char buffer[BUF_SIZE_DEFAULT] = { 0 }; @@ -154,6 +259,7 @@ int HdcServerForClient::Initial() WRITE_LOG(LOG_FATAL, "Module client initial failed"); return -1; } +#ifndef __OHOS__ if (!channelHostPort.size() || !channelHost.size() || !channelPort) { WRITE_LOG(LOG_FATAL, "Listen string initial failed"); return -2; // -2:err for Listen initial failed @@ -164,6 +270,23 @@ int HdcServerForClient::Initial() int listenError = -3; // -3:error for SetTCPListen failed return listenError; } +#else + if (!channelHostPort.size() || !channelHost.size() || !channelPort) { + WRITE_LOG(LOG_FATAL, "Listen string initial failed"); + } else { + bool b = SetTCPListen(); + if (!b) { + WRITE_LOG(LOG_FATAL, "SetTCPListen failed"); + } + } + bool ret = SetUdsListen(); + if (!ret) { + WRITE_LOG(LOG_FATAL, "SetUdsListen failed"); + int listenError = -3; + return listenError; + } +#endif + return 0; } @@ -512,6 +635,15 @@ bool HdcServerForClient::DoCommandLocal(HChannel hChannel, void *formatCommandIn ret = false; break; } +#ifdef HOST_OHOS + case CMD_SERVER_KILL: { + WRITE_LOG(LOG_FATAL, "CMD_SERVER_KILL command"); + ptrServer->SessionSoftReset(); + hChannel->isSuccess = true; + EchoClient(hChannel, MSG_OK, "Kill server finish"); + _exit(0); + } +#endif case CMD_CHECK_SERVER: { WRITE_LOG(LOG_DEBUG, "CMD_CHECK_SERVER command"); ReportServerVersion(hChannel); @@ -670,6 +802,33 @@ void HdcServerForClient::HandleRemote(HChannel hChannel, string ¶meters, Rem delete[](reinterpret_cast(argv)); } +#ifdef __OHOS__ +bool HdcServerForClient::IsServerTransfer(HChannel hChannel, uint16_t cmdFlag, string ¶meters) +{ + if (cmdFlag == CMD_FILE_INIT || cmdFlag== CMD_APP_INIT) { + HandleRemote(hChannel, parameters, RemoteType::REMOTE_FILE); + if (!hChannel->fromClient) { + EchoClient(hChannel, MSG_FAIL, "[E005200] Unsupport file command"); + return false; + } + } + return true; +} +#endif + +bool HdcServerForClient::HandleCommandJdwp(HChannel hChannel, uint16_t cmdFlag, + string ¶meters, int size) +{ + if (!SendToDaemon(hChannel, cmdFlag, + reinterpret_cast(const_cast(parameters.c_str())), size)) { + return false; + } + if (cmdFlag == CMD_SHELL_INIT) { + hChannel->interactiveShellMode = true; + } + return true; +} + bool HdcServerForClient::DoCommandRemote(HChannel hChannel, void *formatCommandInput) { StartTraceScope("HdcServerForClient::DoCommandRemote"); @@ -689,19 +848,18 @@ bool HdcServerForClient::DoCommandRemote(HChannel hChannel, void *formatCommandI case CMD_UNITY_ROOTRUN: case CMD_JDWP_TRACK: case CMD_JDWP_LIST: { - if (!SendToDaemon(hChannel, formatCommand->cmdFlag, - reinterpret_cast(const_cast(formatCommand->parameters.c_str())), sizeSend)) { - break; - } - ret = true; - if (formatCommand->cmdFlag == CMD_SHELL_INIT) { - hChannel->interactiveShellMode = true; - } + ret = HandleCommandJdwp(hChannel, formatCommand->cmdFlag, formatCommand->parameters, sizeSend); break; } case CMD_FILE_INIT: case CMD_FORWARD_INIT: - case CMD_APP_INIT: + case CMD_APP_INIT: { +#ifdef __OHOS__ + if (!IsServerTransfer(hChannel, formatCommand->cmdFlag, formatCommand->parameters)) { + return false; + } +#endif + } case CMD_APP_UNINSTALL: case CMD_UNITY_BUGREPORT_INIT: case CMD_APP_SIDELOAD: @@ -727,8 +885,15 @@ bool HdcServerForClient::DoCommand(HChannel hChannel, void *formatCommandInput, StartTraceScope("HdcServerForClient::DoCommand"); bool ret = false; TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput; +#ifdef __OHOS__ + if ((!hChannel->hChildWorkTCP.loop && !hChannel->hChildWorkUds.loop) || +#else if (!hChannel->hChildWorkTCP.loop || +#endif formatCommand->cmdFlag == CMD_FORWARD_REMOVE || +#ifdef HOST_OHOS + formatCommand->cmdFlag == CMD_SERVER_KILL || +#endif formatCommand->cmdFlag == CMD_SERVICE_START) { hChannel->commandFlag = formatCommand->cmdFlag; hChannel->commandParameters = formatCommand->parameters; @@ -789,6 +954,57 @@ HSession HdcServerForClient::FindAliveSessionFromDaemonMap(const HChannel hChann return hSession; } +#ifdef __OHOS__ +int HdcServerForClient::BindChannelToSession(HChannel hChannel, uint8_t *bufPtr, const int bytesIO) +{ + StartTraceScope("HdcServerForClient::BindChannelToSession"); + if (FindAliveSessionFromDaemonMap(hChannel) == nullptr) { + WRITE_LOG(LOG_FATAL, "Find no alive session channelId:%u", hChannel->channelId); + return ERR_SESSION_NOFOUND; + } + bool isClosing = false; + if (!hChannel->isUds) { + isClosing = uv_is_closing((const uv_handle_t *)&hChannel->hWorkTCP); + if (!isClosing && (hChannel->fdChildWorkTCP = Base::DuplicateUvSocket(&hChannel->hWorkTCP)) < 0) { + WRITE_LOG(LOG_FATAL, "Duplicate socket failed channelId:%u", hChannel->channelId); + return ERR_SOCKET_DUPLICATE; + } + } else { + isClosing = uv_is_closing((const uv_handle_t *)&hChannel->hWorkUds); + if (!isClosing && (hChannel->fdChildWorkTCP = Base::DuplicateUvPipe(&hChannel->hWorkUds)) < 0) { + WRITE_LOG(LOG_FATAL, "Duplicate pipe failed channelId:%u", hChannel->channelId); + return ERR_SOCKET_DUPLICATE; + } + } + + uv_close_cb funcWorkTcpClose = [](uv_handle_t *handle) -> void { + HChannel hChannel = (HChannel)handle->data; + --hChannel->ref; + }; + ++hChannel->ref; + if (!isClosing) { + if (!hChannel->isUds) { + uv_close((uv_handle_t *)&hChannel->hWorkTCP, funcWorkTcpClose); + } else { + uv_close((uv_handle_t *)&hChannel->hWorkUds, funcWorkTcpClose); + } + } + Base::DoNextLoop(loopMain, hChannel, [](const uint8_t flag, string &msg, const void *data) { + // Thread message can avoid using thread lock and improve program efficiency + // If not next loop call, ReadStream will thread conflict + HChannel hChannel = (HChannel)data; + auto thisClass = (HdcServerForClient *)hChannel->clsChannel; + HSession hSession = nullptr; + if ((hSession = thisClass->FindAliveSessionFromDaemonMap(hChannel)) == nullptr) { + WRITE_LOG(LOG_FATAL, "hSession nullptr channelId:%u", hChannel->channelId); + return; + } + auto ctrl = HdcSessionBase::BuildCtrlString(SP_ATTACH_CHANNEL, hChannel->channelId, nullptr, 0); + Base::SendToPollFd(hSession->ctrlFd[STREAM_MAIN], ctrl.data(), ctrl.size()); + }); + return RET_SUCCESS; +} +#else int HdcServerForClient::BindChannelToSession(HChannel hChannel, uint8_t *bufPtr, const int bytesIO) { StartTraceScope("HdcServerForClient::BindChannelToSession"); @@ -801,6 +1017,7 @@ int HdcServerForClient::BindChannelToSession(HChannel hChannel, uint8_t *bufPtr, WRITE_LOG(LOG_FATAL, "Duplicate socket failed channelId:%u", hChannel->channelId); return ERR_SOCKET_DUPLICATE; } + uv_close_cb funcWorkTcpClose = [](uv_handle_t *handle) -> void { HChannel hChannel = (HChannel)handle->data; --hChannel->ref; @@ -824,6 +1041,7 @@ int HdcServerForClient::BindChannelToSession(HChannel hChannel, uint8_t *bufPtr, }); return RET_SUCCESS; } +#endif bool HdcServerForClient::CheckAutoFillTarget(HChannel hChannel) { diff --git a/src/host/server_for_client.h b/src/host/server_for_client.h old mode 100755 new mode 100644 index 7c540efd4b5e74332799ecd242e85495e3a34e99..296d6a3111f96800d585945f6878ebbd360f8e25 --- a/src/host/server_for_client.h +++ b/src/host/server_for_client.h @@ -32,6 +32,10 @@ public: protected: private: +#ifdef __OHOS__ + static void AcceptUdsClient(uv_stream_t *server, int status); + bool SetUdsListen(); +#endif static void AcceptClient(uv_stream_t *server, int status); bool SetTCPListen(); int ReadChannel(HChannel hChannel, uint8_t *bufPtr, const int bytesIO) override; @@ -61,7 +65,14 @@ private: string GetErrorString(uint32_t errorCode); void PrintLastError(HChannel HChannel); bool CommandMatchDaemonFeature(uint16_t cmdFlag, const HDaemonInfo &hdi); +#ifdef __OHOS__ + bool IsServerTransfer(HChannel hChannel, uint16_t cmdFlag, string ¶meters); +#endif + bool HandleCommandJdwp(HChannel hChannel, uint16_t cmdFlag, string ¶meters, int size); +#ifdef __OHOS__ + uv_pipe_t udsListen; +#endif uv_tcp_t tcpListen; void *clsServer; const std::set FEATURE_CHECK_SET = { diff --git a/src/host/translate.cpp b/src/host/translate.cpp index 3946bcc32cc9bb03043d11ecefb204d48b73955f..8724a5d269f3f3af13c73d35b7d5afc0c7e27410 100644 --- a/src/host/translate.cpp +++ b/src/host/translate.cpp @@ -378,7 +378,13 @@ namespace TranslateCommand { } } else if (!strncmp(input.c_str(), CMDSTR_SERVICE_START.c_str(), CMDSTR_SERVICE_START.size())) { outCmd->cmdFlag = CMD_SERVICE_START; - } else if (!strncmp(input.c_str(), CMDSTR_CHECK_SERVER.c_str(), CMDSTR_CHECK_SERVER.size())) { + } +#ifdef HOST_OHOS + else if (!strncmp(input.c_str(), CMDSTR_SERVICE_KILL.c_str(), CMDSTR_SERVICE_KILL.size())) { + outCmd->cmdFlag = CMD_SERVER_KILL; + } +#endif + else if (!strncmp(input.c_str(), CMDSTR_CHECK_SERVER.c_str(), CMDSTR_CHECK_SERVER.size())) { outCmd->cmdFlag = CMD_CHECK_SERVER; } else if (!strncmp(input.c_str(), CMDSTR_CHECK_DEVICE.c_str(), CMDSTR_CHECK_DEVICE.size())) { outCmd->parameters = input.c_str() + CMDSTR_CHECK_DEVICE.size() + 1; // with ' '