diff --git a/test/BUILD.gn b/test/BUILD.gn index d43e3493366a5667c7ada6064a6f257bcfa1d3bf..627b32ee63532cff299afe4a38d0c0b3ed9c7b24 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2021-2022 Huawei Device Co., Ltd. +# Copyright (c) 2021-2023 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 @@ -11,8 +11,19 @@ # See the License for the specific language governing permissions and # limitations under the License. +declare_args() { + distributedhardware_function_test = false +} + group("test") { testonly = true deps = [ "fuzztest:fuzztest" ] + + if (distributedhardware_function_test) { + deps += [ + "injecttest/client:distributed_input_inject_client_test", + "injecttest/server:distributed_input_inject_server_test", + ] + } } diff --git a/test/injecttest/client/BUILD.gn b/test/injecttest/client/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..b9718c9a132f0446f9b9f46510ba331654bf4d7c --- /dev/null +++ b/test/injecttest/client/BUILD.gn @@ -0,0 +1,72 @@ +# Copyright (c) 2023 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/config/features.gni") +import("//build/test.gni") +import("//test/xts/tools/build/suite.gni") +import("../../../distributedinput.gni") + +module_out_path = "distributed_input/injecttest" + +## UnitTest distributed_input_inject_client_test {{{ +ohos_moduletest_suite("distributed_input_inject_client_test") { + module_out_path = module_out_path + + include_dirs = [ + "${innerkits_path}/include", + "${ipc_path}/include", + "${frameworks_path}/include", + "${service_common}/include", + "${common_path}/include", + "//third_party/json/include", + "${utils_path}/include", + "./include", + ] + + sources = [ + "./src/distributed_input_test_client.cpp", + "./src/socket_client.cpp", + "./src/socket_main_test.cpp", + ] + + cflags = [ + "-Dprivate=public", + "-Dprotected=public", + ] + + defines = [ + "HI_LOG_ENABLE", + "DH_LOG_TAG=\"dinputtestclt\"", + "LOG_DOMAIN=0xD004100", + ] + + deps = [ + "${innerkits_path}:libdinput_sdk", + "${utils_path}:libdinput_utils", + "//third_party/libevdev:libevdev", + ] + + external_deps = [ + "access_token:libaccesstoken_sdk", + "access_token:libnativetoken", + "access_token:libtoken_setproc", + "c_utils:utils", + "dsoftbus:softbus_client", + "eventhandler:libeventhandler", + "ipc:ipc_core", + ] + + subsystem_name = "distributedhardware" + part_name = "distributed_input" +} +## UnitTest distributed_input_inject_client_test }}} diff --git a/test/injecttest/client/Test.json b/test/injecttest/client/Test.json new file mode 100644 index 0000000000000000000000000000000000000000..3c926ce3f912bb2fdeaeea8da38ebcdb49348b08 --- /dev/null +++ b/test/injecttest/client/Test.json @@ -0,0 +1,21 @@ +{ + "description": "Config for disInput test cases", + "driver": { + "module-name": "distributed_input_inject_client_test", + "native-test-timeout": "120000", + "native-test-device-path": "/data/local/tmp", + "runtime-hint": "1s", + "type": "CppTest" + }, + "kits": [ + { + "post-push" : [ + "chmod -R 777 /data/local/tmp/*" + ], + "push": [ + "distributed_input_inject_client_test->/data/local/tmp/distributed_input_inject_client_test" + ], + "type": "PushKit" + } + ] +} \ No newline at end of file diff --git a/test/injecttest/client/include/distributed_input_test_client.h b/test/injecttest/client/include/distributed_input_test_client.h new file mode 100644 index 0000000000000000000000000000000000000000..c998c8cd5e0c26b5910327d962c696fd34e0c185 --- /dev/null +++ b/test/injecttest/client/include/distributed_input_test_client.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 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 DISTRIBUTED_INPUT_TEST_CLIENT_H +#define DISTRIBUTED_INPUT_TEST_CLIENT_H + +#include +#include "linux/uinput.h" + +#include "socket_client.h" + +namespace OHOS { +namespace DistributedHardware { +namespace DistributedInput { +class DistributedInputTestClient { +public: + DistributedInputTestClient(std::string ip); + ~DistributedInputTestClient(); + void MakeVirtualEvent(); +private: + SocketClient socketCli; + bool SetPhys(const std::string deviceName); + bool CreateNode(); + bool InjectEvent(input_event event); + bool CreateKey(); + void ProcRes(bool result); +private: + struct uinput_user_dev dev_ {}; + bool injectResult_ = false; + int32_t fd_ = -1; +}; +} +} +} +#endif \ No newline at end of file diff --git a/test/injecttest/client/include/socket_client.h b/test/injecttest/client/include/socket_client.h new file mode 100644 index 0000000000000000000000000000000000000000..c682055b1ce402fff0341ecbb3961576f0ad552f --- /dev/null +++ b/test/injecttest/client/include/socket_client.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 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 SOCKET_CLIENT_H +#define SOCKET_CLIENT_H + +#include +#include + +#include +#include +#include +#include +#include + +namespace OHOS { +namespace DistributedHardware { +namespace DistributedInput { +using ResCallback = std::function; +class SocketClient { +public: + int32_t Init(std::string ip); + int32_t Release(); + int32_t PushRequest(std::string msg); + void ParseRecvSvrMsg(std::string msg); + void RegisterResCallback(ResCallback cb); +private: + void DoRecvSvrRsp(); + void SendRequest(); + void DoSendRequest(std::string msg); + +private: + int32_t sock_cli; + fd_set rfds; + struct timeval tv; + int32_t retval; + int32_t maxfd; + +private: + std::mutex reqMtx_; + std::condition_variable reqQueueConVar_; + std::queue requestQueue_; + ResCallback resCallback_; +}; +} +} +} +#endif diff --git a/test/injecttest/client/src/distributed_input_test_client.cpp b/test/injecttest/client/src/distributed_input_test_client.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fc2070a3bce1479e92f6196c324979e7ca850dca --- /dev/null +++ b/test/injecttest/client/src/distributed_input_test_client.cpp @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2023 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 "distributed_input_test_client.h" + +#include +#include +#include +#include +#include +#include + +#include "linux/input-event-codes.h" + +#include "ipc_skeleton.h" +#include "nlohmann/json.hpp" +#include "nativetoken_kit.h" +#include "softbus_bus_center.h" +#include "token_setproc.h" + +#include "constants_dinput.h" +#include "dinput_errcode.h" +#include "dinput_log.h" +#include "dinput_utils_tool.h" +#include "idistributed_hardware_source.h" + +namespace OHOS { +namespace DistributedHardware { +namespace DistributedInput { +namespace { + const std::string DINPUT_PKG_NAME = "ohos.dhardware.dinput"; + const std::string INPUT_PATH = "/dev/uinput"; + constexpr int32_t WAIT_DH_SYNC_TIME = 5; + constexpr int32_t KEY_VALUE_DOWN = 1; + constexpr int32_t DEFAULT_ID_PARAM = 0000; + constexpr int32_t DEVICE_NAME_LEN = 16; +} + +DistributedInputTestClient::DistributedInputTestClient(std::string ip) +{ + DHLOGI("Ctor DistributedInputTestClient ip: %s", GetAnonyString(ip).c_str()); + socketCli.Init(ip); + socketCli.RegisterResCallback(std::bind(&DistributedInputTestClient::ProcRes, this, std::placeholders::_1)); +} + +DistributedInputTestClient::~DistributedInputTestClient() +{ + DHLOGI("Dctor DistributedInputTestClient"); + socketCli.Release(); +} + +bool DistributedInputTestClient::SetPhys(const std::string deviceName) +{ + std::string phys; + phys.append(deviceName); + + if (ioctl(fd_, UI_SET_PHYS, phys.c_str()) < 0) { + DHLOGE("DistributedInputTestClient SetPhys failed"); + return false; + } + return true; +} + +bool DistributedInputTestClient::CreateKey() +{ + const std::vector eventType { EV_KEY, EV_REL, EV_MSC }; + for (auto it : eventType) { + if (ioctl(fd_, UI_SET_EVBIT, it) < 0) { + DHLOGE("CreateKye ioctl(fd_, UI_SET_EVBIT, it) failed!"); + } + } + + const std::vector keys { + BTN_LEFT, BTN_RIGHT, BTN_MIDDLE, BTN_SIDE, BTN_EXTRA, BTN_FORWARD, BTN_BACK, BTN_TASK }; + for (auto it : keys) { + if (ioctl(fd_, UI_SET_KEYBIT, it) < 0) { + DHLOGE("CreateKye ioctl(fd_, UI_SET_KEYBIT, it) failed!"); + } + } + + const std::vector rels { REL_X, REL_Y, REL_WHEEL, REL_WHEEL_HI_RES }; + for (auto it : rels) { + if (ioctl(fd_, UI_SET_RELBIT, it) < 0) { + DHLOGE("CreateKye ioctl(fd_, UI_SET_RELBIT, it) failed!"); + } + } + + if (ioctl(fd_, UI_SET_MSCBIT, MSC_SCAN) < 0) { + DHLOGE("CreateKye ioctl(fd_, UI_SET_MSCBIT, it) failed!"); + } + return true; +} + +bool DistributedInputTestClient::CreateNode() +{ + fd_ = open(INPUT_PATH.c_str(), O_WRONLY | O_NONBLOCK); + if (fd_ < 0) { + DHLOGE("Failed to open uinput"); + return false; + } + + std::string deviceName_ = "virtual mouse"; + if (strncpy_s(dev_.name, sizeof(dev_.name), deviceName_.c_str(), deviceName_.size()) != EOK) { + DHLOGE("Failed to set device name"); + return false; + } + dev_.id.bustype = DEFAULT_ID_PARAM; + dev_.id.vendor = DEFAULT_ID_PARAM; + dev_.id.product = DEFAULT_ID_PARAM; + dev_.id.version = DEFAULT_ID_PARAM; + + if (!SetPhys(deviceName_)) { + DHLOGE("Failed to set PHYS!"); + return false; + } + + if (!CreateKey()) { + DHLOGE("Failed to CreateKey!"); + return false; + } + + if (write(fd_, &dev_, sizeof(dev_)) < 0) { + DHLOGE("Unable to set input device info"); + return false; + } + + if (ioctl(fd_, UI_DEV_CREATE) < 0) { + DHLOGE("fd = %d, ioctl(fd_, UI_DEV_CREATE) failed", fd_); + return false; + } + + DHLOGI("create fd %d", fd_); + char sysfsDeviceName[DEVICE_NAME_LEN] = {0}; + if (ioctl(fd_, UI_GET_SYSNAME(sizeof(sysfsDeviceName)), sysfsDeviceName) < 0) { + DHLOGE("Unable to get input device name"); + } + DHLOGI("get input device name: %s, fd: %d", sysfsDeviceName, fd_); + return true; +} + +bool DistributedInputTestClient::InjectEvent(input_event event) +{ + if (!CreateNode()) { + DHLOGE("create node fail"); + return false; + } + socketCli.PushRequest("open listen thread"); + sleep(WAIT_DH_SYNC_TIME); + + DHLOGI("InjectEvent Inject down event start %d", fd_); + if (write(fd_, &event, sizeof(event)) < static_cast(sizeof(event))) { + DHLOGE("could not inject event, removed? (fd: %d", fd_); + return false; + } + + DHLOGI("InjectEvent inject sync event start %d", fd_); + struct input_event syncEvent = { + .type = EV_SYN, + .code = 0, + .value = 0 + }; + if (write(fd_, &syncEvent, sizeof(syncEvent)) < static_cast(sizeof(syncEvent))) { + DHLOGE("could not inject syncEvent, removed? (fd: %d", fd_); + return false; + } + DHLOGI("InjectInputEvent end\n"); + return true; +} + +void DistributedInputTestClient::MakeVirtualEvent() +{ + DHLOGI("MakeVirtualEvent start"); + struct input_event event = { + .type = EV_KEY, + .code = BTN_LEFT, + .value = KEY_VALUE_DOWN + }; + InjectEvent(event); +} + +void DistributedInputTestClient::ProcRes(bool result) +{ + DHLOGI("ProcRes start source inject event result: %d", result); + injectResult_ = result; + return; +} +} +} +} \ No newline at end of file diff --git a/test/injecttest/client/src/socket_client.cpp b/test/injecttest/client/src/socket_client.cpp new file mode 100644 index 0000000000000000000000000000000000000000..58e6e69ac7d9930428c2bba80fc653a35b2cf1a2 --- /dev/null +++ b/test/injecttest/client/src/socket_client.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2023 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 "socket_client.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "dinput_errcode.h" +#include "dinput_log.h" +#include "dinput_utils_tool.h" +#include "nlohmann/json.hpp" + +namespace OHOS { +namespace DistributedHardware { +namespace DistributedInput { +namespace { + constexpr int32_t MYPORT = 7000; + constexpr int32_t BUFFER_SIZE = 4096; + constexpr int32_t MAX_MSG_LENGTH = 4096; + constexpr int32_t BUFF_MAX_LEN = 32 * 1024; + constexpr int32_t BLOCK_TIME = 10; + constexpr int32_t SOCKET_ERR = -1; + constexpr int32_t SOCKET_SUCCESS = 0; +} + +int32_t SocketClient::Init(std::string ip) +{ + DHLOGI("Init Socket Client"); + sock_cli = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in servaddr; + (void)memset_s(&servaddr, sizeof(servaddr), 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(MYPORT); + servaddr.sin_addr.s_addr = inet_addr(ip.c_str()); + + if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { + DHLOGE("Connect Socker Server failed"); + return SOCKET_ERR; + } + + int32_t rBuf = BUFF_MAX_LEN; + setsockopt(sock_cli, SOL_SOCKET, SO_RCVBUF, (const char*)&rBuf, sizeof(int32_t)); + int32_t sBuf = BUFF_MAX_LEN; + setsockopt(sock_cli, SOL_SOCKET, SO_SNDBUF, (const char*)&sBuf, sizeof(int32_t)); + + std::thread(&SocketClient::DoRecvSvrRsp, this).detach(); + std::thread(&SocketClient::SendRequest, this).detach(); + + return SOCKET_SUCCESS; +} + +int32_t SocketClient::Release() +{ + DHLOGI("Release Socket client, Close Client Conn"); + if (sock_cli != SOCKET_ERR) { + close(sock_cli); + sock_cli = SOCKET_ERR; + } + return SOCKET_SUCCESS; +} + +void SocketClient::SendRequest() +{ + while (true) { + std::unique_lock lock(reqMtx_); + reqQueueConVar_.wait(lock, [this] { + return !(this->requestQueue_.empty()); + }); + + if (!requestQueue_.empty()) { + std::string msg = requestQueue_.front(); + DHLOGI("Client Pop Msg: %s", msg.c_str()); + DoSendRequest(msg); + requestQueue_.pop(); + } + } +} + +void SocketClient::DoSendRequest(std::string msg) +{ + char buf[msg.length() + 1]; + int32_t ret = strcpy_s(buf, msg.length() + 1, msg.c_str()); + if (ret != EOK) { + DHLOGE("DoSendRequest strcpy_s failed"); + return; + } + DHLOGI("Client Send Message: %s", buf); + send(sock_cli, buf, strlen(buf), 0); +} + +void SocketClient::ParseRecvSvrMsg(std::string msg) +{ + DHLOGI("Client Recv Message: %s", GetAnonyString(msg).c_str()); + nlohmann::json jsonObj = nlohmann::json::parse(msg, nullptr, false); + if (jsonObj.find("injectResult") == jsonObj.end()) { + DHLOGE("server msg is not rsp msg"); + return; + } + bool injectResult = jsonObj.at("injectResult").get(); + DHLOGI("ParseRecvSvrMsg injectResult: %d", injectResult); + resCallback_(injectResult); +} + +void SocketClient::DoRecvSvrRsp() +{ + while (true) { + FD_ZERO(&rfds); + FD_SET(0, &rfds); + maxfd = 0; + FD_SET(sock_cli, &rfds); + if (maxfd < sock_cli) { + maxfd = sock_cli; + } + tv.tv_sec = BLOCK_TIME; + tv.tv_usec = 0; + retval = select(maxfd + 1, &rfds, NULL, NULL, &tv); + if (retval == SOCKET_ERR) { + DHLOGE("Socket Client select error"); + break; + } else if (retval == 0) { + continue; + } else { + if (FD_ISSET(sock_cli, &rfds) <= 0) { + DHLOGE("Socket Client FD_ISSET error"); + continue; + } + char recvbuf[BUFFER_SIZE]; + int32_t len = recv(sock_cli, recvbuf, sizeof(recvbuf), 0); + if (len == 0) { + DHLOGI("empty msg, drop it"); + continue; + } + std::string svrRsp(recvbuf, len); + DHLOGI("Receive Server Rsp: %s", GetAnonyString(svrRsp).c_str()); + std::cout << GetAnonyString(svrRsp) << std::endl; + ParseRecvSvrMsg(svrRsp); + (void)memset_s(recvbuf, sizeof(recvbuf), 0, sizeof(recvbuf)); + } + } +} + +int32_t SocketClient::PushRequest(std::string msg) +{ + DHLOGI("Client PushRequest: %s", GetAnonyString(msg).c_str()); + int32_t msgLen = msg.length(); + if (msgLen > MAX_MSG_LENGTH) { + DHLOGE("Msg too long, length: %d", msgLen); + return SOCKET_ERR; + } + + std::unique_lock lock(reqMtx_); + requestQueue_.push(msg); + reqQueueConVar_.notify_all(); + return SOCKET_SUCCESS; +} + +void SocketClient::RegisterResCallback(ResCallback cb) +{ + resCallback_ = cb; +} +} +} +} \ No newline at end of file diff --git a/test/injecttest/client/src/socket_main_test.cpp b/test/injecttest/client/src/socket_main_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dc61db8ddc7699cf7f4152296d651dec5709c20f --- /dev/null +++ b/test/injecttest/client/src/socket_main_test.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2023 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 + +#include "accesstoken_kit.h" +#include "nativetoken_kit.h" +#include "token_setproc.h" + +#include "distributed_input_test_client.h" +#include "socket_client.h" +#include "softbus_bus_center.h" +#include "softbus_common.h" + +using namespace testing::ext; +using namespace OHOS::DistributedHardware; +using namespace OHOS::Security::AccessToken; + +static constexpr int32_t PERMISSION_NUM = 2; +static constexpr int32_t ARGC_NUM = 2; +static constexpr int32_t TEST_WAIT_TIME = 5; + +class SocketMainTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + SocketMainTest(); +}; +void SocketMainTest::SetUpTestCase(void) +{ + const char *perms[PERMISSION_NUM]; + perms[0] = "ohos.permission.DISTRIBUTED_SOFTBUS_CENTER"; + perms[1] = "ohos.permission.DISTRIBUTED_DATASYNC"; + NativeTokenInfoParams infoInstance = { + .dcapsNum = 0, + .permsNum = PERMISSION_NUM, + .aclsNum = 0, + .dcaps = NULL, + .perms = perms, + .acls = NULL, + .processName = "dinput_function_test_service", + .aplStr = "system_core", + }; + uint64_t tokenId = GetAccessTokenId(&infoInstance); + SetSelfTokenID(tokenId); + sleep(1); + OHOS::Security::AccessToken::AccessTokenKit::ReloadNativeTokenInfo(); +} + +void SocketMainTest::TearDownTestCase(void) {} +void SocketMainTest::SetUp(void) {} +void SocketMainTest::TearDown(void) {} + +SocketMainTest::SocketMainTest(void) {} + +int32_t main(int32_t argc, char **argv) +{ + if (argc < ARGC_NUM) { + std::cout << "no param, please input ip" << std::endl; + return -1; + } + std::string ip = argv[1]; + OHOS::DistributedHardware::DistributedInput::DistributedInputTestClient inputTestClient(ip); + sleep(TEST_WAIT_TIME); + inputTestClient.MakeVirtualEvent(); + sleep(TEST_WAIT_TIME); + EXPECT_EQ(true, inputTestClient.injectResult_); + return 0; +} diff --git a/test/injecttest/server/BUILD.gn b/test/injecttest/server/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..d93a8e7e8236e5d2cfa4633919e55b23c4540408 --- /dev/null +++ b/test/injecttest/server/BUILD.gn @@ -0,0 +1,76 @@ +# Copyright (c) 2023 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/config/features.gni") +import("//build/test.gni") +import("//test/xts/tools/build/suite.gni") +import("../../../distributedinput.gni") + +module_out_path = "distributed_input/injecttest" + +## UnitTest distributed_input_inject_server_test {{{ +ohos_moduletest_suite("distributed_input_inject_server_test") { + module_out_path = module_out_path + + include_dirs = [ + "${innerkits_path}/include", + "${ipc_path}/include", + "${frameworks_path}/include", + "${service_common}/include", + "${common_path}/include", + "${utils_path}/include", + "./include", + "//third_party/json/include", + ] + + sources = [ + "./src/dinput_dbg_itf.cpp", + "./src/distributed_input_test_server.cpp", + "./src/socket_main_test.cpp", + "./src/socket_server.cpp", + ] + + cflags = [ + "-Wall", + "-Werror", + "-g3", + "-Dprivate=public", + "-Dprotected=public", + ] + + defines = [ + "HI_LOG_ENABLE", + "DH_LOG_TAG=\"dinputtestsvr\"", + "LOG_DOMAIN=0xD004100", + ] + + deps = [ + "${innerkits_path}:libdinput_sdk", + "${utils_path}:libdinput_utils", + "//third_party/libevdev:libevdev", + ] + + external_deps = [ + "access_token:libaccesstoken_sdk", + "access_token:libnativetoken", + "access_token:libtoken_setproc", + "c_utils:utils", + "dsoftbus:softbus_client", + "eventhandler:libeventhandler", + "ipc:ipc_core", + ] + + subsystem_name = "distributedhardware" + part_name = "distributed_input" +} +## UnitTest distributed_input_inject_server_test }}} diff --git a/test/injecttest/server/Test.json b/test/injecttest/server/Test.json new file mode 100644 index 0000000000000000000000000000000000000000..521583ea0aadfb50b2f9c782d4ba421d862924d1 --- /dev/null +++ b/test/injecttest/server/Test.json @@ -0,0 +1,21 @@ +{ + "description": "Config for disInput test cases", + "driver": { + "module-name": "distributed_input_inject_server_test", + "native-test-timeout": "120000", + "native-test-device-path": "/data/local/tmp", + "runtime-hint": "1s", + "type": "CppTest" + }, + "kits": [ + { + "post-push" : [ + "chmod -R 777 /data/local/tmp/*" + ], + "push": [ + "distributed_input_inject_server_test->/data/local/tmp/distributed_input_inject_server_test" + ], + "type": "PushKit" + } + ] +} \ No newline at end of file diff --git a/test/injecttest/server/include/dinput_dbg_itf.h b/test/injecttest/server/include/dinput_dbg_itf.h new file mode 100644 index 0000000000000000000000000000000000000000..703e612debf05fefac30e9469835c490b7ae5d0d --- /dev/null +++ b/test/injecttest/server/include/dinput_dbg_itf.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 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 OHOS_DINPUT_DB_ITF_H +#define OHOS_DINPUT_DB_ITF_H + +#include +#include + +#include "distributed_input_test_server.h" + +namespace OHOS { +namespace DistributedHardware { +namespace DistributedInput { +class DInputDBGItf { +public: + DInputDBGItf(); + int32_t Init(); +private: + std::shared_ptr dinputTestServerPtr_; +}; +} +} +} + +#endif \ No newline at end of file diff --git a/test/injecttest/server/include/distributed_input_test_server.h b/test/injecttest/server/include/distributed_input_test_server.h new file mode 100644 index 0000000000000000000000000000000000000000..f2ce93a5bca723d0b115dafed17510fabb967940 --- /dev/null +++ b/test/injecttest/server/include/distributed_input_test_server.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2023 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 DISTRIBUTED_INPUT_TEST_SERVER_H +#define DISTRIBUTED_INPUT_TEST_SERVER_H + +#include +#include +#include +#include +#include +#include + +#include + +#include "constants_dinput.h" +#include "distributed_input_kit.h" +#include "input_node_listener_stub.h" +#include "prepare_d_input_call_back_stub.h" +#include "unprepare_d_input_call_back_stub.h" +#include "start_d_input_call_back_stub.h" +#include "stop_d_input_call_back_stub.h" +#include "simulation_event_listener_stub.h" + +#include "socket_server.h" + +namespace OHOS { +namespace DistributedHardware { +namespace DistributedInput { +class DistributedInputTestServer { +public: + DistributedInputTestServer(); + ~DistributedInputTestServer(); + class TestPrepareDInputCallback : + public OHOS::DistributedHardware::DistributedInput::PrepareDInputCallbackStub { + public: + TestPrepareDInputCallback() = default; + virtual ~TestPrepareDInputCallback() = default; + void OnResult(const std::string& deviceId, const int32_t& status); + }; + class TestUnprepareDInputCallback : + public OHOS::DistributedHardware::DistributedInput::UnprepareDInputCallbackStub { + public: + TestUnprepareDInputCallback() = default; + virtual ~TestUnprepareDInputCallback() = default; + void OnResult(const std::string& deviceId, const int32_t& status); + }; + class TestStartStopDInputCallback : + public OHOS::DistributedHardware::DistributedInput::StartStopDInputsCallbackStub { + public: + TestStartStopDInputCallback() = default; + virtual ~TestStartStopDInputCallback() = default; + void OnResultDhids(const std::string &devId, const int32_t &status); + }; + class TestInputNodeListener : + public OHOS::DistributedHardware::DistributedInput::InputNodeListenerStub { + public: + TestInputNodeListener() = default; + virtual ~TestInputNodeListener() = default; + void OnNodeOnLine(const std::string srcDevId, const std::string sinkDevId, const std::string sinkNodeId, + const std::string nodeDesc); + void OnNodeOffLine(const std::string srcDevId, const std::string sinkDevId, const std::string sinkNodeId); + }; + class TestSimulationEventListener : + public OHOS::DistributedHardware::DistributedInput::SimulationEventListenerStub { + public: + TestSimulationEventListener() = default; + virtual ~TestSimulationEventListener() = default; + int32_t OnSimulationEvent(uint32_t type, uint32_t code, int32_t value); + }; + +public: + void ProcRequest(std::string msg); + +private: + void GetRemoteDeviceId(); + void ListenerEvent(); + + OHOS::sptr inputNodeListener_; + OHOS::sptr simEventListener_; + + std::shared_ptr socketServerPtr_ = nullptr; + std::string remoteDevId_ = ""; + static std::vector dhIds_; + static std::mutex dhIdsMutex_; + std::atomic testResult_ = false; +}; +} +} +} +#endif \ No newline at end of file diff --git a/test/injecttest/server/include/socket_server.h b/test/injecttest/server/include/socket_server.h new file mode 100644 index 0000000000000000000000000000000000000000..4128e35ee4fe6cc5137779c36e7d769273631d48 --- /dev/null +++ b/test/injecttest/server/include/socket_server.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023 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 SOCKET_SERVER_H +#define SOCKET_SERVER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace OHOS { +namespace DistributedHardware { +namespace DistributedInput { +using RequestCallback = std::function; +class SocketServer { +public: + void Init(); + void Release(); + void PushResponse(std::string msg); + void RegisterRequestCallback(RequestCallback cb); +private: + void GetConn(); + void GetData(); + void GetDataByFd(int32_t fd); + void SendMessage(); + void DoSendMessage(std::string msg); + void DoSendMessagePure(std::string msg, int32_t conn); + + void ProcRequest(); +private: + int32_t s; + struct sockaddr_in servaddr; + socklen_t len; + std::list li; + + RequestCallback reqCallback_; + +private: + std::mutex reqMtx_; + std::mutex tmpMsgMtx_; + std::mutex rspMtx_; + + std::condition_variable reqQueueConVar_; + std::queue requestQueue_; + std::condition_variable rspQueueConVar_; + std::queue responseQueue_; + std::vector tmpMsgs_; +}; +} +} +} +#endif \ No newline at end of file diff --git a/test/injecttest/server/src/dinput_dbg_itf.cpp b/test/injecttest/server/src/dinput_dbg_itf.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f3f86690373247f57d05764f58002b68f27169f0 --- /dev/null +++ b/test/injecttest/server/src/dinput_dbg_itf.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 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 "dinput_dbg_itf.h" + +#include "dinput_log.h" +#include "distributed_input_test_server.h" + +namespace OHOS { +namespace DistributedHardware { +namespace DistributedInput { +DInputDBGItf::DInputDBGItf() +{ + DHLOGI("Ctor DInputDBGItf"); +} +int32_t DInputDBGItf::Init() +{ + DHLOGI("Init DInputDBGItf"); + dinputTestServerPtr_ = std::make_shared(); + return 0; +} +} +} +} \ No newline at end of file diff --git a/test/injecttest/server/src/distributed_input_test_server.cpp b/test/injecttest/server/src/distributed_input_test_server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..401526aa4b541679816846a0d4686c97b74f0818 --- /dev/null +++ b/test/injecttest/server/src/distributed_input_test_server.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2023 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 "distributed_input_test_server.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include "ipc_skeleton.h" +#include "linux/input-event-codes.h" +#include "nlohmann/json.hpp" +#include "nativetoken_kit.h" +#include "token_setproc.h" + +#include "dinput_errcode.h" +#include "dinput_log.h" +#include "dinput_utils_tool.h" +#include "softbus_bus_center.h" + +namespace OHOS { +namespace DistributedHardware { +namespace DistributedInput { +static std::shared_ptr socketServerStaticPtr = nullptr; +namespace { + const std::string DINPUT_PKG_NAME = "ohos.dhardware.dinput"; + const std::string DINPUT_DEVICE_PATH = "/dev/input/event16"; + constexpr int32_t WAIT_DH_SYNC_TIME = 2; + constexpr int32_t KEY_VALUE_DOWN = 1; + constexpr int32_t DINPUT_OK = 0; + constexpr int32_t DINPUT_ERR = -1; + constexpr int32_t POLL_NFD = 1; +} + +std::vector DistributedInputTestServer::dhIds_ = {}; +std::mutex DistributedInputTestServer::dhIdsMutex_; + +void DistributedInputTestServer::TestPrepareDInputCallback::OnResult(const std::string& deviceId, + const int32_t& status) +{ + DHLOGI("TestPrepareDInputCallback::OnResult: deviceId = %s, status = %d", + GetAnonyString(deviceId).c_str(), status); +} + +void DistributedInputTestServer::TestUnprepareDInputCallback::OnResult(const std::string& deviceId, + const int32_t& status) +{ + DHLOGI("TestUnprepareDInputCallback::OnResult: deviceId = %s, status = %d", + GetAnonyString(deviceId).c_str(), status); +} + +void DistributedInputTestServer::TestStartStopDInputCallback::OnResultDhids(const std::string &devId, + const int32_t &status) +{ + DHLOGI("DistributedInputTestServer::TestStartStopDInputCallback::OnResult: devId = %s, status = %d", + GetAnonyString(devId).c_str(), status); +} + +void DistributedInputTestServer::TestInputNodeListener::OnNodeOnLine(const std::string srcDevId, + const std::string sinkDevId, const std::string sinkNodeId, const std::string nodeDesc) +{ + nlohmann::json jsonStr; + jsonStr["srcDevId"] = srcDevId; + jsonStr["sinkDevId"] = sinkDevId; + jsonStr["sinkNodeId"] = sinkNodeId; + jsonStr["nodeDesc"] = nodeDesc; + std::string msg = jsonStr.dump(); + DHLOGI("TestInputNodeListener::OnNodeOnline: %s", GetAnonyString(msg).c_str()); + if (socketServerStaticPtr == nullptr) { + DHLOGE("socketServerStaticPtr is null"); + return; + } + socketServerStaticPtr->PushResponse(msg); + std::lock_guard lock(DistributedInputTestServer::dhIdsMutex_); + DistributedInputTestServer::dhIds_.emplace_back(sinkNodeId); +} + +void DistributedInputTestServer::TestInputNodeListener::OnNodeOffLine(const std::string srcDevId, + const std::string sinkDevId, const std::string sinkNodeId) +{ + std::string rsp = "TestInputNodeListener::OnNodeOffLine\n"; + DHLOGI("TestInputNodeListener::OnNodeOffLine: %s", rsp.c_str()); + if (socketServerStaticPtr == nullptr) { + DHLOGE("socketServerStaticPtr is null"); + return; + } + socketServerStaticPtr->PushResponse(rsp); +} + +int32_t DistributedInputTestServer::TestSimulationEventListener::OnSimulationEvent(uint32_t type, + uint32_t code, int32_t value) +{ + nlohmann::json jsonStr; + jsonStr["eventType"] = type; + jsonStr["eventCode"] = code; + jsonStr["eventValue"] = value; + std::string msg = jsonStr.dump(); + DHLOGI("TestSimulationEventListener::OnSimulationEvent: %s", msg.c_str()); + if (socketServerStaticPtr == nullptr) { + DHLOGE("socketServerStaticPtr is null"); + return DINPUT_ERR; + } + socketServerStaticPtr->PushResponse(msg); + return DINPUT_OK; +} + +void DistributedInputTestServer::GetRemoteDeviceId() +{ + NodeBasicInfo *info = nullptr; + int32_t infoNum = 0; + auto ret = GetAllNodeDeviceInfo(DINPUT_PKG_NAME.c_str(), &info, &infoNum); + if (ret != DINPUT_OK) { + DHLOGE("get remote device id fail."); + return; + } + remoteDevId_ = info->networkId; +} + +DistributedInputTestServer::DistributedInputTestServer():inputNodeListener_(new TestInputNodeListener()), + simEventListener_(new TestSimulationEventListener()), socketServerPtr_(std::make_shared()) +{ + DHLOGI("Init Socker Server"); + GetRemoteDeviceId(); + socketServerPtr_->Init(); + socketServerPtr_->RegisterRequestCallback(std::bind(&DistributedInputTestServer::ProcRequest, + this, std::placeholders::_1)); + socketServerStaticPtr = socketServerPtr_; + + int32_t ret = DistributedInputKit::RegisterInputNodeListener(inputNodeListener_); + DHLOGI("Register Input Node Listener %s, ret: %d", (ret == 0 ? "success" : "error"), ret); + ret = DistributedInputKit::RegisterSimulationEventListener(simEventListener_); + DHLOGI("Register SimulationEvent Listener %s, ret: %d", (ret == 0 ? "success" : "error"), ret); + auto prepareCb = new(std::nothrow) TestPrepareDInputCallback(); + DistributedInputKit::PrepareRemoteInput(remoteDevId_, prepareCb); +} + +void DistributedInputTestServer::ListenerEvent() +{ + DHLOGE("ListenerEvent start"); + struct input_event event; + struct pollfd pfd[1]; + int32_t fd = open(DINPUT_DEVICE_PATH.c_str(), O_RDONLY); + if (fd < 0) { + DHLOGE("failed to open device: %s", DINPUT_DEVICE_PATH.c_str()); + } + pfd[0].fd = fd; + pfd[0].events = POLLIN; + while (true) { + if (poll(pfd, POLL_NFD, -1) > 0) { + int32_t len = read(fd, &event, sizeof(event)); + if (len < 0) { + continue; + } + DHLOGI("Event: type %d, code: %d, value: %d\n", event.type, event.code, event.value); + if (event.type == EV_KEY && event.code == BTN_LEFT && event.value == KEY_VALUE_DOWN) { + nlohmann::json jsonStr; + jsonStr["injectResult"] = true; + std::string msg = jsonStr.dump(); + this->testResult_.store(true); + socketServerStaticPtr->PushResponse(msg); + } + } + } +} + +DistributedInputTestServer::~DistributedInputTestServer() +{ + DHLOGI("DistributedInputTestServer destruction"); + auto stopCb = new(std::nothrow) TestStartStopDInputCallback(); + DistributedInputKit::StopRemoteInput(remoteDevId_, dhIds_, stopCb); + auto unprepareCb = new(std::nothrow) TestUnprepareDInputCallback(); + DistributedInputKit::UnprepareRemoteInput(remoteDevId_, unprepareCb); +} + +void DistributedInputTestServer::ProcRequest(std::string msg) +{ + DHLOGI("DistributedInputTestServer ProcRequest"); + sleep(WAIT_DH_SYNC_TIME); + std::thread(&DistributedInputTestServer::ListenerEvent, this).detach(); + auto startCb = new(std::nothrow) TestStartStopDInputCallback(); + DistributedInputKit::StartRemoteInput(remoteDevId_, dhIds_, startCb); +} +} +} +} \ No newline at end of file diff --git a/test/injecttest/server/src/socket_main_test.cpp b/test/injecttest/server/src/socket_main_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..10e1aa4e763d63450598cc35bc8d674cd9e2e16f --- /dev/null +++ b/test/injecttest/server/src/socket_main_test.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2023 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 +#include "dinput_dbg_itf.h" +#include "socket_server.h" + +#include "accesstoken_kit.h" +#include "nativetoken_kit.h" +#include "token_setproc.h" + +#include "softbus_bus_center.h" +#include "softbus_common.h" + +using namespace testing::ext; +using namespace OHOS::DistributedHardware; +using namespace OHOS::Security::AccessToken; + +static constexpr int32_t PERMISSION_NUM = 2; + +class SocketMainTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + SocketMainTest(); +}; +void SocketMainTest::SetUpTestCase(void) +{ + const char *perms[PERMISSION_NUM]; + perms[0] = "ohos.permission.DISTRIBUTED_SOFTBUS_CENTER"; + perms[1] = "ohos.permission.DISTRIBUTED_DATASYNC"; + NativeTokenInfoParams infoInstance = { + .dcapsNum = 0, + .permsNum = PERMISSION_NUM, + .aclsNum = 0, + .dcaps = NULL, + .perms = perms, + .acls = NULL, + .processName = "dinput_function_test_service", + .aplStr = "system_core", + }; + uint64_t tokenId = GetAccessTokenId(&infoInstance); + SetSelfTokenID(tokenId); + sleep(1); + OHOS::Security::AccessToken::AccessTokenKit::ReloadNativeTokenInfo(); +} + +void SocketMainTest::TearDownTestCase(void) {} +void SocketMainTest::SetUp(void) {} +void SocketMainTest::TearDown(void) {} + +SocketMainTest::SocketMainTest(void) {} + +HWTEST_F(SocketMainTest, SocketMainTest_0001, TestSize.Level1) +{ + OHOS::DistributedHardware::DistributedInput::DInputDBGItf dbgItf; + dbgItf.Init(); + while (!dbgItf.dinputTestServerPtr_->testResult_.load()) {} + EXPECT_EQ(true, dbgItf.dinputTestServerPtr_->testResult_.load()); +} \ No newline at end of file diff --git a/test/injecttest/server/src/socket_server.cpp b/test/injecttest/server/src/socket_server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..204811ab7dd8467ebcab2146911dad35d3c0add3 --- /dev/null +++ b/test/injecttest/server/src/socket_server.cpp @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2023 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 "socket_server.h" + +#include "unistd.h" + +#include +#include +#include +#include +#include + +#include "dinput_errcode.h" +#include "dinput_log.h" +#include "dinput_utils_tool.h" + +namespace OHOS { +namespace DistributedHardware { +namespace DistributedInput { +namespace { + constexpr int32_t PORT = 7000; + constexpr int32_t MAX_MSG_LENGTH = 4096; + constexpr int32_t ESTABLISHED_MAX = 20; + constexpr int32_t BUFF_MAX_LEN = 32 * 1024; + constexpr int32_t SEND_MSG_SPACE = 100; + constexpr int32_t BLOCK_TIME = 10; + constexpr int32_t SOCKET_ERR = -1; +} + +void SocketServer::Init() +{ + DHLOGI("Init DBGSvr"); + s = socket(AF_INET, SOCK_STREAM, 0); + (void)memset_s(&servaddr, sizeof(servaddr), 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(PORT); + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); + if (bind(s, (struct sockaddr *)&servaddr, sizeof(servaddr)) == SOCKET_ERR) { + DHLOGE("Bind Socket Server error"); + return; + } + if (listen(s, ESTABLISHED_MAX) == SOCKET_ERR) { + DHLOGE("Listener Socket Server error"); + return; + } + len = sizeof(servaddr); + + int32_t rBuf = BUFF_MAX_LEN; + setsockopt(s, SOL_SOCKET, SO_RCVBUF, (const char*)&rBuf, sizeof(int32_t)); + int32_t sBuf = BUFF_MAX_LEN; + setsockopt(s, SOL_SOCKET, SO_SNDBUF, (const char*)&sBuf, sizeof(int32_t)); + + std::thread(&SocketServer::GetConn, this).detach(); + std::thread(&SocketServer::SendMessage, this).detach(); + std::thread(&SocketServer::GetData, this).detach(); + std::thread(&SocketServer::ProcRequest, this).detach(); +} + +void SocketServer::GetConn() +{ + while (true) { + int32_t conn = accept(s, (struct sockaddr *)&servaddr, &len); + li.push_back(conn); + DHLOGI("receive client connect, fd: %d\n", conn); + std::lock_guard lock(tmpMsgMtx_); + if (tmpMsgs_.size() != 0) { + DHLOGI("Send Old msg"); + for (auto &msg : tmpMsgs_) { + DoSendMessagePure(msg, conn); + std::this_thread::sleep_for(std::chrono::milliseconds(SEND_MSG_SPACE)); + } + } + tmpMsgs_.clear(); + } +} + +void SocketServer::GetDataByFd(int32_t fd) +{ + struct timeval tv; + tv.tv_sec = BLOCK_TIME; + tv.tv_usec = 0; + fd_set rfds; + FD_ZERO(&rfds); + int32_t maxfd = 0; + int32_t retval = 0; + FD_SET(fd, &rfds); + if (maxfd < fd) { + maxfd = fd; + } + retval = select(maxfd + 1, &rfds, NULL, NULL, &tv); + if (retval == SOCKET_ERR) { + DHLOGE("Server select error, ret: %d", retval); + } else if (retval == 0) { + DHLOGI("not message"); + } else { + char buf[MAX_MSG_LENGTH]; + (void)memset_s(buf, sizeof(buf), 0, sizeof(buf)); + int32_t len = recv(fd, buf, sizeof(buf), 0); + DHLOGI("Server Recv Msg: %s, len: %d", buf, len); + if (len > 0) { + std::string msg(buf, len); + std::lock_guard lock(reqMtx_); + requestQueue_.push(msg); + reqQueueConVar_.notify_all(); + } + } +} + +void SocketServer::GetData() +{ + while (true) { + std::list::iterator it; + for (it = li.begin(); it != li.end(); ++it) { + GetDataByFd(*it); + } + sleep(1); + } +} + +void SocketServer::SendMessage() +{ + while (true) { + std::unique_lock lock(rspMtx_); + rspQueueConVar_.wait(lock, [this] { + return !(this->responseQueue_.empty()); + }); + + if (!responseQueue_.empty()) { + std::string msg = responseQueue_.front(); + DHLOGI("Pos Rsp Msg: %s", msg.c_str()); + DoSendMessage(msg); + responseQueue_.pop(); + std::this_thread::sleep_for(std::chrono::milliseconds(SEND_MSG_SPACE)); + } + } +} + +void SocketServer::ProcRequest() +{ + while (true) { + std::unique_lock lock(reqMtx_); + reqQueueConVar_.wait(lock, [this] { + return !(this->requestQueue_.empty()); + }); + if (!requestQueue_.empty()) { + std::string msg = requestQueue_.front(); + if (reqCallback_ != nullptr) { + reqCallback_(msg); + } else { + DHLOGE("reqCallback_ is null"); + } + requestQueue_.pop(); + } + } +} + +void SocketServer::DoSendMessage(std::string msg) +{ + DHLOGI("Server Send Message: %s", GetAnonyString(msg).c_str()); + char buf[msg.length() + 1]; + int32_t ret = strcpy_s(buf, msg.length() + 1, msg.c_str()); + if (ret != EOK) { + DHLOGE("DoSendMessage strcpy_s failed"); + return; + } + + if (li.size() == 0) { + DHLOGI("No client, save it"); + std::lock_guard lock(tmpMsgMtx_); + tmpMsgs_.push_back(msg); + } + + std::list::iterator it; + for (it = li.begin(); it != li.end(); ++it) { + send(*it, buf, sizeof(buf), 0); + } +} + +void SocketServer::DoSendMessagePure(std::string msg, int32_t conn) +{ + DHLOGI("Server Send Message Pure: %s", GetAnonyString(msg).c_str()); + char buf[msg.length() + 1]; + int32_t ret = strcpy_s(buf, msg.length() + 1, msg.c_str()); + if (ret != EOK) { + DHLOGE("DoSendMessagePure strcpy_s failed"); + return; + } + + send(conn, buf, sizeof(buf), 0); +} + +void SocketServer::PushResponse(std::string msg) +{ + DHLOGI("PushRespones: %s", GetAnonyString(msg).c_str()); + int32_t msgLen = msg.length(); + if (msgLen > MAX_MSG_LENGTH) { + DHLOGE("Msg too long, length: %d", msgLen); + return; + } + + std::unique_lock lock(rspMtx_); + responseQueue_.push(msg); + rspQueueConVar_.notify_all(); +} + +void SocketServer::Release() +{ + DHLOGI("Close connection"); + std::list::iterator it; + for (it = li.begin(); it != li.end(); ++it) { + close(*it); + } + li.clear(); + + DHLOGI("Close socket fd"); + if (s != SOCKET_ERR) { + close(s); + s = SOCKET_ERR; + } +} + +void SocketServer::RegisterRequestCallback(RequestCallback cb) +{ + reqCallback_ = cb; +} +} +} +} \ No newline at end of file