From 962e7dbf95bd50310ff1c769c622ae2b045761bf Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Mon, 22 Feb 2021 11:54:40 +0900 Subject: [PATCH 01/16] Release version 1.8.0 Changes: - Fix Write() implemenation - Support daemon proxy Change-Id: If8b5fdcb1fa9b2f67161b1124b06d07849b72324 Signed-off-by: Hwankyu Jhun --- packaging/rpc-port.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/rpc-port.spec b/packaging/rpc-port.spec index e62adfd..d898d41 100644 --- a/packaging/rpc-port.spec +++ b/packaging/rpc-port.spec @@ -1,6 +1,6 @@ Name: rpc-port Summary: RPC Port library -Version: 1.7.8 +Version: 1.8.0 Release: 0 Group: Application Framework/Libraries License: Apache-2.0 -- 2.7.4 From 562f8f294546b490dfb2ab2c0c12d43067f1651e Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Thu, 11 Mar 2021 14:07:28 +0900 Subject: [PATCH 02/16] Fix rpc-port-parcel implementation related to bundle Parcel APIs related to Bundle API will be removed. rpc_port_parcel_write_bundle() modifies to use use parcel_write_string() instead of parcel_write_bundle(). rpc_port_parcel_read_bundle() modifies to use parcel_read_string() instead of parcel_read_bundle(). Change-Id: Iad0b6e347bb72197ebeffd1a630862a5eb8ffbbc Signed-off-by: Hwankyu Jhun --- src/rpc-port-parcel.cc | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/rpc-port-parcel.cc b/src/rpc-port-parcel.cc index e934efb..2276a77 100644 --- a/src/rpc-port-parcel.cc +++ b/src/rpc-port-parcel.cc @@ -18,6 +18,8 @@ #include #include +#include + #include "log-private.hh" #include "port-internal.hh" #include "rpc-port-parcel.h" @@ -203,8 +205,13 @@ RPC_API int rpc_port_parcel_write_bundle(rpc_port_parcel_h h, bundle* b) { if (h == nullptr || b == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; + bundle_raw* raw = nullptr; + int len = 0; + bundle_encode(b, &raw, &len); + auto ptr = std::unique_ptr(raw, std::free); + parcel_h parcel = static_cast(h); - parcel_write_bundle(parcel, b); + parcel_write_string(parcel, reinterpret_cast(raw)); return RPC_PORT_ERROR_NONE; } @@ -334,10 +341,14 @@ RPC_API int rpc_port_parcel_read_bundle(rpc_port_parcel_h h, bundle** b) { return RPC_PORT_ERROR_INVALID_PARAMETER; parcel_h parcel = static_cast(h); - int ret = parcel_read_bundle(parcel, b); + char* raw = nullptr; + int ret = parcel_read_string(parcel, &raw); if (ret != PARCEL_ERROR_NONE) { - _E("parcel_read_bundle() is failed. error(%d)", ret); + _E("parcel_read_string() is failed. error(%d)", ret); *b = bundle_create(); + } else { + *b = bundle_decode(reinterpret_cast(raw), strlen(raw)); + std::free(raw); } return RPC_PORT_ERROR_NONE; -- 2.7.4 From 98ce23d7fa272cd6f2cdc0541de94bfc2ca7cead Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Thu, 11 Mar 2021 17:07:53 +0900 Subject: [PATCH 03/16] Release version 1.8.1 Changes: - Fix rpc-port-parcel implementation related to bundle Change-Id: I1df202fef2f0a491e6496f3dc00bf58f84ae4c65 Signed-off-by: Hwankyu Jhun --- packaging/rpc-port.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/rpc-port.spec b/packaging/rpc-port.spec index d898d41..3ead789 100644 --- a/packaging/rpc-port.spec +++ b/packaging/rpc-port.spec @@ -1,6 +1,6 @@ Name: rpc-port Summary: RPC Port library -Version: 1.8.0 +Version: 1.8.1 Release: 0 Group: Application Framework/Libraries License: Apache-2.0 -- 2.7.4 From 325690185da46785a30a1b4cb64322d6446ef5cd Mon Sep 17 00:00:00 2001 From: jusung Date: Fri, 19 Mar 2021 13:28:47 +0900 Subject: [PATCH 04/16] Fix memory leak Change-Id: I37ca69f7eb682a4c7a94614b462dff4e410df3f4 Signed-off-by: jusung --- src/rpc-port-parcel.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/rpc-port-parcel.cc b/src/rpc-port-parcel.cc index 2276a77..625bbd9 100644 --- a/src/rpc-port-parcel.cc +++ b/src/rpc-port-parcel.cc @@ -84,8 +84,10 @@ RPC_API int rpc_port_parcel_create_from_port(rpc_port_parcel_h* h, parcel_h parcel = nullptr; int ret = parcel_create(&parcel); - if (ret != PARCEL_ERROR_NONE) + if (ret != PARCEL_ERROR_NONE) { + delete[] buf; return RPC_PORT_ERROR_IO_ERROR; + } parcel_burst_write(parcel, buf, len); delete[] buf; -- 2.7.4 From 8c731e5dcbe2371a21d07130cc978613b432b012 Mon Sep 17 00:00:00 2001 From: jusung Date: Fri, 19 Mar 2021 13:33:01 +0900 Subject: [PATCH 05/16] Release version 1.8.2 Changes: - Fix memory leak Signed-off-by: jusung Change-Id: I974d991f2b21c78b14cbb57e249837f367e4bf1c --- packaging/rpc-port.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/rpc-port.spec b/packaging/rpc-port.spec index 3ead789..cef1a16 100644 --- a/packaging/rpc-port.spec +++ b/packaging/rpc-port.spec @@ -1,6 +1,6 @@ Name: rpc-port Summary: RPC Port library -Version: 1.8.1 +Version: 1.8.2 Release: 0 Group: Application Framework/Libraries License: Apache-2.0 -- 2.7.4 From ab55982c0757a4d99ee1dced0d8a63c8cc5815fa Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Fri, 18 Jun 2021 18:38:55 +0900 Subject: [PATCH 06/16] Use Unix Domain Socket instead of Socket Pair To remove DBus dependency, the rpc-port uses Unix Domain Socket. While calling aul_rpc_port_create(), AMD creates the file descriptor. And then, AMD sends the fd to the stub. The stub uses the fd to manage the connection. Requires: - https://review.tizen.org/gerrit/#/c/platform/core/appfw/aul-1/+/259865/ - https://review.tizen.org/gerrit/#/c/platform/core/appfw/amd/+/259971/ Change-Id: I6e80ac3469ecb1eeec29485e0ac3556fc895df0d Signed-off-by: Hwankyu Jhun --- CMakeLists.txt | 115 ++- cmake/Modules/ApplyPkgConfig.cmake | 35 + include/rpc-port-internal.h | 28 +- include/rpc-port-parcel-internal.h | 9 +- include/rpc-port-parcel.h | 6 +- include/rpc-port.h | 6 +- packaging/rpc-port.spec | 16 +- src/CMakeLists.txt | 32 + src/ac-internal.cc | 78 +- src/ac-internal.hh | 23 +- src/aul-internal.cc | 87 ++ src/aul-internal.hh | 40 + src/client-socket-internal.cc | 223 +++++ src/client-socket-internal.hh | 53 ++ src/debug-port-internal.cc | 2 +- src/debug-port-internal.hh | 2 +- src/exception-internal.cc | 44 + src/exception-internal.hh | 48 ++ src/fdbroker-internal.cc | 957 --------------------- src/fdbroker-internal.hh | 176 ---- src/log-private.hh | 2 +- src/peer-cred-internal.cc | 58 ++ src/peer-cred-internal.hh | 43 + src/port-internal.cc | 24 +- src/port-internal.hh | 21 +- src/proxy-internal.cc | 705 +++++++++++---- src/proxy-internal.hh | 85 +- src/request-internal.cc | 54 ++ src/request-internal.hh | 49 ++ src/response-internal.cc | 43 + src/response-internal.hh | 44 + src/rpc-port-internal.cc | 45 + src/rpc-port-parcel.cc | 8 +- src/rpc-port.cc | 49 +- src/server-socket-internal.cc | 78 ++ src/server-socket-internal.hh | 43 + src/shared-queue-internal.hh | 2 +- src/stub-internal.cc | 332 +++++-- src/stub-internal.hh | 63 +- test/CMakeLists.txt | 1 + test/unit_tests/CMakeLists.txt | 27 + {unit_tests/src => test/unit_tests}/main.cc | 0 test/unit_tests/mock/aul_mock.cc | 82 ++ test/unit_tests/mock/aul_mock.hh | 60 ++ test/unit_tests/mock/mock_hook.hh | 42 + test/unit_tests/mock/module_mock.hh | 25 + test/unit_tests/mock/test_fixture.cc | 21 + test/unit_tests/mock/test_fixture.hh | 54 ++ .../unit_tests}/rpc_port_parcel_test.cc | 0 .../src => test/unit_tests}/rpc_port_test.cc | 315 ++++++- unit_tests/CMakeLists.txt | 33 - utils/CMakeLists.txt | 49 +- utils/{src => }/debug-port.cc | 0 utils/{src => }/debug-port.hh | 0 utils/{src => }/log-private.hh | 0 utils/{src => }/logger.cc | 0 utils/{src => }/logger.hh | 0 utils/{src => }/main.cc | 0 utils/{src => }/message.cc | 0 utils/{src => }/message.hh | 0 utils/{src => }/options.cc | 0 utils/{src => }/options.hh | 0 62 files changed, 2704 insertions(+), 1733 deletions(-) create mode 100644 cmake/Modules/ApplyPkgConfig.cmake create mode 100644 src/CMakeLists.txt create mode 100644 src/aul-internal.cc create mode 100644 src/aul-internal.hh create mode 100644 src/client-socket-internal.cc create mode 100644 src/client-socket-internal.hh create mode 100644 src/exception-internal.cc create mode 100644 src/exception-internal.hh delete mode 100644 src/fdbroker-internal.cc delete mode 100644 src/fdbroker-internal.hh create mode 100644 src/peer-cred-internal.cc create mode 100644 src/peer-cred-internal.hh create mode 100644 src/request-internal.cc create mode 100644 src/request-internal.hh create mode 100644 src/response-internal.cc create mode 100644 src/response-internal.hh create mode 100644 src/rpc-port-internal.cc create mode 100644 src/server-socket-internal.cc create mode 100644 src/server-socket-internal.hh create mode 100644 test/CMakeLists.txt create mode 100644 test/unit_tests/CMakeLists.txt rename {unit_tests/src => test/unit_tests}/main.cc (100%) create mode 100644 test/unit_tests/mock/aul_mock.cc create mode 100644 test/unit_tests/mock/aul_mock.hh create mode 100644 test/unit_tests/mock/mock_hook.hh create mode 100644 test/unit_tests/mock/module_mock.hh create mode 100644 test/unit_tests/mock/test_fixture.cc create mode 100644 test/unit_tests/mock/test_fixture.hh rename {unit_tests/src => test/unit_tests}/rpc_port_parcel_test.cc (100%) rename {unit_tests/src => test/unit_tests}/rpc_port_test.cc (54%) delete mode 100644 unit_tests/CMakeLists.txt rename utils/{src => }/debug-port.cc (100%) rename utils/{src => }/debug-port.hh (100%) rename utils/{src => }/log-private.hh (100%) rename utils/{src => }/logger.cc (100%) rename utils/{src => }/logger.hh (100%) rename utils/{src => }/main.cc (100%) rename utils/{src => }/message.cc (100%) rename utils/{src => }/message.hh (100%) rename utils/{src => }/options.cc (100%) rename utils/{src => }/options.hh (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f93a11..78dbd01 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,72 +1,67 @@ -PROJECT(rpc-port CXX) -SET(this_target rpc-port) +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) -INCLUDE_DIRECTORIES ( - ${CMAKE_SOURCE_DIR}/include - ${CMAKE_SOURCE_DIR}/src - ) +PROJECT(rpc-port) -SET(${this_target}_requires "dlog bundle glib-2.0 gio-2.0 aul capi-base-common pkgmgr-info gio-unix-2.0 cynara-client cynara-creds-gdbus uuid parcel") +ADD_DEFINITIONS("-DFULLVER=\"${FULLVER}\"") -INCLUDE(FindPkgConfig) -pkg_check_modules(${this_target} REQUIRED ${${this_target}_requires}) - -FOREACH(flag ${${this_target}_CFLAGS}) - SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") -ENDFOREACH(flag) +SET(CMAKE_INSTALL_PREFIX /usr) +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) +SET(PC_NAME "rpc-port") +SET(PC_REQUIRED "capi-base-common") +SET(PC_VERSION ${FULLVER}) +SET(PC_LDFLAGS "-lrpc-port") -SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wall" ) - -## SET C COMPILER FLAGS -SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall -Werror -fvisibility=hidden") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-zdefs") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden") SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") +SET(CMAKE_C_FLAGS_RELEASE "-O2") -## SET CPP COMPILER FLAGS -SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} -fvisibility=hidden -std=c++11") - -## Create Library -AUX_SOURCE_DIRECTORY(src SOURCES) -ADD_LIBRARY(${this_target} SHARED ${SOURCES}) - -## SET LINKER FLAGS -SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed -Wl,--no-undefined -Wl,--rpath=${LIB_INSTALL_DIR}") - -TARGET_LINK_LIBRARIES(${this_target} ${${this_target}_LDFLAGS}) - -SET_TARGET_PROPERTIES(${this_target} - PROPERTIES - VERSION ${FULLVER} - SOVERSION ${MAJORVER} - CLEAN_DIRECT_OUTPUT 1 - ) - -# pkgconfig file -SET(PC_NAME ${this_target}) -SET(VERSION ${FULLVER}) -SET(PC_REQUIRED ${${this_target}_requires}) +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_C_FLAGS} -std=c++14") +SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") +SET(CMAKE_CXX_FLAGS_RELEASE "-O2") -## OUTPUT PATHS -SET(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/cmake_build_tmp/output) +SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/") -CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/${this_target}.pc.in ${CMAKE_SOURCE_DIR}/${this_target}.pc @ONLY) -INSTALL(FILES ${CMAKE_SOURCE_DIR}/${this_target}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) +SET(TARGET_RPC_PORT "rpc-port") +SET(TARGET_RPC_PORT_UNITTESTS "rpc-port_unittests") +SET(TARGET_RPC_PORT_UTIL "rpc-port-util") -INSTALL(TARGETS ${this_target} DESTINATION ${LIB_INSTALL_DIR}) - -INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/include/ DESTINATION include/rpc-port FILES_MATCHING PATTERN "*.h") -INSTALL(DIRECTORY ${LIBRARY_OUTPUT_PATH}/ DESTINATION ${LIB_INSTALL_DIR} FILES_MATCHING PATTERN "*.so*") - -CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/conf/rpc-port.conf.in ${CMAKE_SOURCE_DIR}/conf/rpc-port.conf @ONLY) -INSTALL(FILES ${CMAKE_SOURCE_DIR}/conf/rpc-port.conf DESTINATION /etc/dbus-1/system.d) - -IF(NOT DEFINED MINIMUM_BUILD) ENABLE_TESTING() -SET(RPC_PORT_UNITTESTS rpc-port_unittests) -ADD_TEST(NAME ${RPC_PORT_UNITTESTS} COMMAND ${RPC_PORT_UNITTESTS} - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/unit_tests) - -ADD_SUBDIRECTORY(unit_tests) -ADD_DEPENDENCIES(${RPC_PORT_UNITTESTS} rpc-port) -ENDIF(NOT DEFINED MINIMUM_BUILD) +ADD_TEST(NAME ${TARGET_RPC_PORT_UNITTESTS} + COMMAND ${TARGET_RPC_PORT_UNITTESTS} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/test/unit_tests) +INCLUDE(FindPkgConfig) +INCLUDE(ApplyPkgConfig) + +PKG_CHECK_MODULES(AUL_DEPS REQUIRED aul) +PKG_CHECK_MODULES(BUNDLE_DEPS REQUIRED bundle) +PKG_CHECK_MODULES(CAPI_BASE_COMMON_DEPS REQUIRED capi-base-common) +PKG_CHECK_MODULES(CYNARA_CLIENT_DEPS REQUIRED cynara-client) +PKG_CHECK_MODULES(CYNARA_CREDS_SOCKET_DEPS REQUIRED cynara-creds-socket) +PKG_CHECK_MODULES(DLOG_DEPS REQUIRED dlog) +PKG_CHECK_MODULES(GIO_DEPS REQUIRED gio-2.0) +PKG_CHECK_MODULES(GIO_UNIX_DEPS REQUIRED gio-unix-2.0) +PKG_CHECK_MODULES(GLIB_DEPS REQUIRED glib-2.0) +PKG_CHECK_MODULES(GMOCK_DEPS REQUIRED gmock) +PKG_CHECK_MODULES(LIBTZPLATFORM_CONFIG_DEPS REQUIRED libtzplatform-config) +PKG_CHECK_MODULES(PARCEL_DEPS REQUIRED parcel) +PKG_CHECK_MODULES(PKGMGR_INFO_DEPS REQUIRED pkgmgr-info) +PKG_CHECK_MODULES(UUID_DEPS REQUIRED uuid) + +ADD_SUBDIRECTORY(src) ADD_SUBDIRECTORY(utils) +ADD_SUBDIRECTORY(test) + +CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/${TARGET_RPC_PORT}.pc.in + ${CMAKE_SOURCE_DIR}/${TARGET_RPC_PORT}.pc @ONLY) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/${TARGET_RPC_PORT}.pc + DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) + +CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/conf/${TARGET_RPC_PORT}.conf.in + ${CMAKE_SOURCE_DIR}/conf/${TARGET_RPC_PORT}.conf @ONLY) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/conf/${TARGET_RPC_PORT}.conf + DESTINATION /etc/dbus-1/system.d) diff --git a/cmake/Modules/ApplyPkgConfig.cmake b/cmake/Modules/ApplyPkgConfig.cmake new file mode 100644 index 0000000..f4a262e --- /dev/null +++ b/cmake/Modules/ApplyPkgConfig.cmake @@ -0,0 +1,35 @@ +# Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# +# This function applies external (out of source tree) dependencies +# to given target. Arguments are: +# TARGET - valid cmake target +# PRIVACY - dependency can be inherited by dependent targets or not: +# PUBLIC - this should be used by default, cause compile/link flags passing +# PRIVATE - do not passes any settings to dependent targets, +# may be usefull for static libraries from the inside of the project +# Argument ARGV2 and following are supposed to be names of checked pkg config +# packages. This function will use variables created by check_pkg_modules(). +# - ${DEP_NAME}_LIBRARIES +# - ${DEP_NAME}_INCLUDE_DIRS +# - ${DEP_NAME}_CFLAGS +# +FUNCTION(APPLY_PKG_CONFIG TARGET PRIVACY) + MATH(EXPR DEST_INDEX "${ARGC}-1") + FOREACH(I RANGE 2 ${DEST_INDEX}) + IF(NOT ${ARGV${I}}_FOUND) + MESSAGE(FATAL_ERROR "Not found dependency - ${ARGV${I}}_FOUND") + ENDIF(NOT ${ARGV${I}}_FOUND) + TARGET_LINK_LIBRARIES(${TARGET} ${PRIVACY} "${${ARGV${I}}_LIBRARIES}") + TARGET_INCLUDE_DIRECTORIES(${TARGET} ${PRIVACY} SYSTEM "${${ARGV${I}}_INCLUDE_DIRS}") + STRING(REPLACE ";" " " CFLAGS_STR "${${ARGV${I}}_CFLAGS}") + SET(CFLAGS_LIST ${CFLAGS_STR}) + SEPARATE_ARGUMENTS(CFLAGS_LIST) + FOREACH(OPTION ${CFLAGS_LIST}) + TARGET_COMPILE_OPTIONS(${TARGET} ${PRIVACY} ${OPTION}) + ENDFOREACH(OPTION) + SET_TARGET_PROPERTIES(${TARGET} PROPERTIES SKIP_BUILD_RPATH true) + ENDFOREACH(I RANGE 2 ${DEST_INDEX}) +ENDFUNCTION(APPLY_PKG_CONFIG TARGET PRIVACY) diff --git a/include/rpc-port-internal.h b/include/rpc-port-internal.h index b370e0a..4ac06ca 100644 --- a/include/rpc-port-internal.h +++ b/include/rpc-port-internal.h @@ -1,14 +1,14 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd All Rights Reserved * - * Licensed under the Apache License, Version 2.0 (the License); + * 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, + * 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. @@ -17,21 +17,33 @@ #ifndef __TIZEN_APPFW_RPC_PORT_INTERNAL_INCLUDE_H__ #define __TIZEN_APPFW_RPC_PORT_INTERNAL_INCLUDE_H__ +#include +#include + #include #ifdef __cplusplus extern "C" { #endif -int rpc_port_proxy_create_mockup(rpc_port_proxy_h *h); +/** + * @brief Sets the target user ID. + * @since_tizen 6.5 + * + * @param[in] target_uid The target user ID + */ +void rpc_port_set_target_uid(uid_t target_uid); -int rpc_port_stub_create_mockup(rpc_port_stub_h *h, const char *port_name); +/** + * @brief Gets the target user ID. + * @since_tizen 6.5 + * + * @return @c the target user ID + */ +uid_t rpc_port_get_target_uid(void); #ifdef __cplusplus } #endif #endif /* __TIZEN_APPFW_RPC_PORT_INTERNAL_INCLUDE_H__ */ - - - diff --git a/include/rpc-port-parcel-internal.h b/include/rpc-port-parcel-internal.h index a4f8323..81e18c3 100644 --- a/include/rpc-port-parcel-internal.h +++ b/include/rpc-port-parcel-internal.h @@ -1,14 +1,14 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd All Rights Reserved * - * Licensed under the Apache License, Version 2.0 (the License); + * 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, + * 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. @@ -36,6 +36,3 @@ int rpc_port_parcel_from_array(rpc_port_parcel_h h, const void *array, #endif #endif /* __TIZEN_APPFW_RPC_PORT_PARCEL_INTERNAL_INCLUDE_H__ */ - - - diff --git a/include/rpc-port-parcel.h b/include/rpc-port-parcel.h index 202086b..3b39802 100644 --- a/include/rpc-port-parcel.h +++ b/include/rpc-port-parcel.h @@ -1,14 +1,14 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2018 - 2021 Samsung Electronics Co., Ltd All Rights Reserved * - * Licensed under the Apache License, Version 2.0 (the License); + * 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, + * 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. diff --git a/include/rpc-port.h b/include/rpc-port.h index 93c9983..86b175d 100644 --- a/include/rpc-port.h +++ b/include/rpc-port.h @@ -1,14 +1,14 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2018 - 2021 Samsung Electronics Co., Ltd All Rights Reserved * - * Licensed under the Apache License, Version 2.0 (the License); + * 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, + * 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. diff --git a/packaging/rpc-port.spec b/packaging/rpc-port.spec index cef1a16..e13591a 100644 --- a/packaging/rpc-port.spec +++ b/packaging/rpc-port.spec @@ -7,17 +7,18 @@ License: Apache-2.0 Source0: %{name}-%{version}.tar.gz Source1001: %{name}.manifest BuildRequires: cmake -BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(aul) BuildRequires: pkgconfig(bundle) +BuildRequires: pkgconfig(cynara-client) +BuildRequires: pkgconfig(cynara-creds-socket) +BuildRequires: pkgconfig(dlog) BuildRequires: pkgconfig(glib-2.0) -BuildRequires: pkgconfig(aul) +BuildRequires: pkgconfig(gmock) +BuildRequires: pkgconfig(libtzplatform-config) +BuildRequires: pkgconfig(parcel) BuildRequires: pkgconfig(pkgmgr) BuildRequires: pkgconfig(pkgmgr-info) -BuildRequires: pkgconfig(gmock) -BuildRequires: pkgconfig(cynara-client) -BuildRequires: pkgconfig(cynara-creds-gdbus) BuildRequires: pkgconfig(uuid) -BuildRequires: pkgconfig(parcel) %if 0%{?gcov:1} BuildRequires: lcov @@ -87,7 +88,8 @@ find . -name '*.gcno' -exec cp '{}' gcov-obj ';' %endif %check -ctest --output-on-failure %{?_smp_mflags} +export LD_LIBRARY_PATH="../../src" +ctest -V %{?_smp_mflags} %if 0%{?gcov:1} lcov -c --ignore-errors graph --no-external -q -d . -o rpc-port.info genhtml rpc-port.info -o rpc-port.out diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..1061211 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,32 @@ +AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} RPC_PORT_SRCS) + +ADD_LIBRARY(${TARGET_RPC_PORT} SHARED ${RPC_PORT_SRCS}) +SET_TARGET_PROPERTIES(${TARGET_RPC_PORT} PROPERTIES SOVERSION ${MAJORVER}) +SET_TARGET_PROPERTIES(${TARGET_RPC_PORT} PROPERTIES VERSION ${FULLVER}) + +TARGET_INCLUDE_DIRECTORIES(${TARGET_RPC_PORT} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../ + ${CMAKE_CURRENT_SOURCE_DIR}/../include) + +APPLY_PKG_CONFIG(${TARGET_RPC_PORT} PUBLIC + AUL_DEPS + BUNDLE_DEPS + CYNARA_CLIENT_DEPS + CYNARA_CREDS_SOCKET_DEPS + DLOG_DEPS + GIO_DEPS + GIO_UNIX_DEPS + GLIB_DEPS + LIBTZPLATFORM_CONFIG_DEPS + PARCEL_DEPS + PKGMGR_INFO_DEPS + UUID_DEPS +) + +INSTALL(TARGETS ${TARGET_RPC_PORT} DESTINATION ${LIB_INSTALL_DIR}) +INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../include/ + DESTINATION include/rpc-port + FILES_MATCHING + PATTERN "*.h" +) diff --git a/src/ac-internal.cc b/src/ac-internal.cc index 194f9fa..a0b5e7a 100644 --- a/src/ac-internal.cc +++ b/src/ac-internal.cc @@ -1,34 +1,36 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd All Rights Reserved * - * Licensed under the Apache License, Version 2.0 (the License); + * 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, + * 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 _GNU_SOURCE -#define _GNU_SOURCE -#endif - #include +#include +#include #include #include -#include -#include #include "ac-internal.hh" +#include "aul-internal.hh" #include "log-private.hh" namespace rpc_port { namespace internal { +namespace { + +constexpr const uid_t kRegularUidMin = 5000; + +} // namespace void AccessController::AddPrivilege(std::string privilege) { privileges_.push_back(std::move(privilege)); @@ -48,19 +50,17 @@ int AccessController::CheckPrivilege(const Cynara& c) { return 0; } -int AccessController::CheckTrusted(const char* sender_appid) { - if (appid_.empty()) { - char appid[255]; - if (aul_app_get_appid_bypid(getpid(), appid, sizeof(appid)) < 0) - return -1; +int AccessController::CheckTrusted(const std::string& sender_appid) { + if (getuid() < kRegularUidMin) + return 0; - appid_ = appid; - } + if (appid_.empty()) + appid_ = Aul::GetAppId(getpid()); - _D("CheckCertificate : %s :: %s", appid_.c_str(), sender_appid); + _D("CheckCertificate : %s :: %s", appid_.c_str(), sender_appid.c_str()); pkgmgrinfo_cert_compare_result_type_e res; int ret = pkgmgrinfo_pkginfo_compare_usr_app_cert_info(appid_.c_str(), - sender_appid, getuid(), &res); + sender_appid.c_str(), getuid(), &res); if (ret < 0) { _E("CheckCertificate() Failed"); return -1; @@ -73,23 +73,20 @@ int AccessController::CheckTrusted(const char* sender_appid) { return 0; } -int AccessController::Check(GDBusConnection* connection, const char* sender, - const char* sender_appid) { - Cynara c; - int ret = 0; - - if (c.FetchCredsFromDBus(connection, sender) != 0) +int AccessController::Check(int fd, const std::string& sender_appid) { + Cynara cynara; + int ret = cynara.FetchCredsFromSocket(fd); + if (ret != 0) return -1; if (!privileges_.empty()) { - ret = CheckPrivilege(c); - if (ret) + ret = CheckPrivilege(cynara); + if (ret != 0) return ret; } - if (trusted_) { + if (trusted_) ret = CheckTrusted(sender_appid); - } return ret; } @@ -114,27 +111,30 @@ AccessController::Cynara::Cynara() AccessController::Cynara::~Cynara() = default; -int AccessController::Cynara::FetchCredsFromDBus(GDBusConnection* connection, - const char* sender) { +int AccessController::Cynara::FetchCredsFromSocket(int fd) { char* user = nullptr; - int ret = cynara_creds_gdbus_get_user(connection, sender, USER_METHOD_DEFAULT, - &user); + int ret = cynara_creds_socket_get_user(fd, USER_METHOD_DEFAULT, &user); if (ret != CYNARA_API_SUCCESS) { - _E("cynara_creds_gdbus_get_user() is failed : %d", ret); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE + char buf[128] = { 0, }; + cynara_strerror(ret, buf, sizeof(buf)); + _E("cynara_creds_socket_get_user() is failed. fd(%d), error(%d:%s)", + fd, ret, buf); + return -1; } user_.reset(user); char* client = nullptr; - ret = cynara_creds_gdbus_get_client(connection, sender, CLIENT_METHOD_DEFAULT, - &client); + ret = cynara_creds_socket_get_client(fd, CLIENT_METHOD_DEFAULT, &client); if (ret != CYNARA_API_SUCCESS) { - _E("cynara_creds_gdbus_get_client() is failed : %d", ret); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE + char buf[128] = { 0, }; + cynara_strerror(ret, buf, sizeof(buf)); + _E("cynara_creds_socket_get_client() is failed. fd(%d), error(%d:%s)", + fd, ret, buf); + return -1; } client_.reset(client); - _D("cred client : %s, cred user : %s", client_.get(), user_.get()); + _D("Cred client(%s), user(%s)", client_.get(), user_.get()); return 0; } diff --git a/src/ac-internal.hh b/src/ac-internal.hh index e870ec3..051a56d 100644 --- a/src/ac-internal.hh +++ b/src/ac-internal.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,18 +14,18 @@ * limitations under the License. */ -#ifndef AC_INTERNAL_H_ -#define AC_INTERNAL_H_ +#ifndef AC_INTERNAL_HH_ +#define AC_INTERNAL_HH_ -#include +#include #include #include -#include +#include -#include -#include #include #include +#include +#include namespace rpc_port { namespace internal { @@ -36,8 +36,7 @@ class AccessController { void AddPrivilege(std::string privilege); void SetTrusted(const bool trusted); - int Check(GDBusConnection* connection, const char* sender, - const char* sender_appid); + int Check(int fd, const std::string& sender_appid); private: class Cynara { @@ -45,7 +44,7 @@ class AccessController { Cynara(); ~Cynara(); - int FetchCredsFromDBus(GDBusConnection* connection, const char* sender); + int FetchCredsFromSocket(int fd); int Check(const std::string& privilege) const; private: @@ -55,7 +54,7 @@ class AccessController { }; int SetCache(const std::string& sender); - int CheckTrusted(const char* sender_appid); + int CheckTrusted(const std::string& sender_appid); int CheckPrivilege(const Cynara& c); private: @@ -68,4 +67,4 @@ class AccessController { } // namespace internal } // namespace rpc_port -#endif // AC_INTERNAL_H_ +#endif // AC_INTERNAL_HH_ diff --git a/src/aul-internal.cc b/src/aul-internal.cc new file mode 100644 index 0000000..0dca700 --- /dev/null +++ b/src/aul-internal.cc @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2021 Samsung Electronics 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 + +#include + +#include "aul-internal.hh" +#include "include/rpc-port.h" +#include "log-private.hh" + +namespace rpc_port { +namespace internal { + +std::string Aul::GetAppId(int pid) { + char app_id[256] = { 0, }; + int ret = aul_app_get_appid_bypid(pid, app_id, sizeof(app_id)); + if (ret != AUL_R_OK) { + _E("aul_app_get_appid_bypid() is failed. pid(%d), error(%d)", pid, ret); + return "Daemon"; + } + + return std::string(app_id); +} + +std::string Aul::GetPortPath(const std::string& app_id, + const std::string& port_name, uid_t uid) { + char* port_path = nullptr; + int ret = aul_rpc_port_usr_get_path(app_id.c_str(), port_name.c_str(), uid, + &port_path); + if (ret != AUL_R_OK) { + _E("aul_rpc_port_usr_get_path() is failed. error(%d)", ret); + return {}; + } + + std::unique_ptr ptr(port_path, std::free); + return std::string(port_path); +} + +int Aul::PrepareStub(const std::string& app_id, const std::string& port_name, + uid_t uid) { + int ret = aul_rpc_port_usr_prepare_stub(app_id.c_str(), port_name.c_str(), + uid); + if (ret != AUL_R_OK) { + _E("aul_rpc_port_usr_prepare_stub() is failed. error(%d)", ret); + if (ret == AUL_R_EILLACC) + return RPC_PORT_ERROR_PERMISSION_DENIED; + + return RPC_PORT_ERROR_IO_ERROR; + } + + return RPC_PORT_ERROR_NONE; +} + +bool Aul::ExistPort(const std::string& app_id, const std::string& port_name, + uid_t uid) { + bool exist = false; + int ret = aul_rpc_port_usr_exist(app_id.c_str(), port_name.c_str(), uid, + &exist); + if (ret != AUL_R_OK) + _W("aul_rpc_port_usr_exist() is failed. error(%d)", ret); + + return exist; +} + +void Aul::NotifyRpcFinished() { + int ret = aul_rpc_port_notify_rpc_finished(); + if (ret != AUL_R_OK) + _W("aul_rpc_port_notify_rpc_finished() is failed. error(%d)", ret); +} + +} // namespace internal +} // namespace rpc_port diff --git a/src/aul-internal.hh b/src/aul-internal.hh new file mode 100644 index 0000000..4859109 --- /dev/null +++ b/src/aul-internal.hh @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 Samsung Electronics 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 AUL_INTERNAL_HH_ +#define AUL_INTERNAL_HH_ + +#include + +namespace rpc_port { +namespace internal { + +class Aul { + public: + static std::string GetAppId(int pid); + static std::string GetPortPath(const std::string& app_id, + const std::string& port_name, uid_t uid); + static int PrepareStub(const std::string& app_id, + const std::string& port_name, uid_t uid); + static bool ExistPort(const std::string& app_id, const std::string& port_name, + uid_t uid); + static void NotifyRpcFinished(); +}; + +} // namespace internal +} // namespace rpc_port + +#endif // AUL_INTERNAL_HH_ diff --git a/src/client-socket-internal.cc b/src/client-socket-internal.cc new file mode 100644 index 0000000..4fbb344 --- /dev/null +++ b/src/client-socket-internal.cc @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2021 Samsung Electronics 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 +#include +#include +#include +#include +#include + +#include "client-socket-internal.hh" +#include "exception-internal.hh" +#include "log-private.hh" + +namespace rpc_port { +namespace internal { + +ClientSocket::ClientSocket() { + fd_ = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd_ < 0) { + fd_ = -errno; + _E("socket() is failed. errno(%d)", errno); + THROW(fd_); + } +} + +ClientSocket::ClientSocket(int fd) : fd_(fd) { +} + +ClientSocket::~ClientSocket() { + if (!IsClosed()) + Close(); +} + +void ClientSocket::Close() { + if (fd_ > -1) { + close(fd_); + fd_ = -1; + } +} + +int ClientSocket::Connect(const std::string& endpoint) { + int flag = fcntl(GetFd(), F_GETFL, 0); + fcntl(GetFd(), F_SETFL, flag | O_NONBLOCK); + + struct sockaddr_un sockaddr = { 0, }; + sockaddr.sun_family = AF_UNIX; + snprintf(sockaddr.sun_path, sizeof(sockaddr.sun_path), "%s", + endpoint.c_str()); + struct sockaddr* sockaddr_ptr = reinterpret_cast(&sockaddr); + socklen_t len = sizeof(sockaddr); + int ret = connect(GetFd(), sockaddr_ptr, len); + fcntl(GetFd(), F_SETFL, flag); + if (ret < 0) { + ret = -errno; + _E("connect() is failed. errno(%d)", errno); + return ret; + } + + return 0; +} + +int ClientSocket::Send(const void* buf, unsigned int size) { + const unsigned char* buffer = static_cast(buf); + size_t len = size; + while (len) { + ssize_t bytes = send(GetFd(), buffer, len, MSG_NOSIGNAL); + if (bytes < 0) { + int ret = -errno; + _E("send() is failed. fd(%d), errno(%d)", GetFd(), errno); + return ret; + } + + len -= bytes; + buffer += bytes; + } + + return 0; +} + +int ClientSocket::Receive(void* buf, unsigned int size) { + unsigned char* buffer = static_cast(buf); + size_t len = size; + while (len) { + ssize_t bytes = read(GetFd(), buffer, len); + if (bytes == 0) { + _W("EOF. fd(%d)", GetFd()); + return -EIO; + } + + if (bytes < 0) + return -errno; + + len -= bytes; + buffer += bytes; + } + + return 0; +} + +int ClientSocket::GetReceiveBufferSize() { + int value; + socklen_t len = sizeof(int); + int ret = getsockopt(GetFd(), SOL_SOCKET, SO_RCVBUF, + reinterpret_cast(&value), &len); + if (ret < 0) { + ret = -errno; + _E("getsockopt() is failed. errno(%d)", errno); + return ret; + } + + return value; +} + +int ClientSocket::GetSendBufferSize() { + int value; + socklen_t len = sizeof(int); + int ret = getsockopt(GetFd(), SOL_SOCKET, SO_SNDBUF, + reinterpret_cast(&value), &len); + if (ret < 0) { + ret = -errno; + _E("getsockopt() is failed. errno(%d)", errno); + return ret; + } + + return value; +} + +int ClientSocket::GetReceiveTimeout() { + struct timeval timeout = { 0, }; + socklen_t len = sizeof(struct timeval); + int ret = getsockopt(GetFd(), SOL_SOCKET, SO_RCVTIMEO, + reinterpret_cast(&timeout), &len); + if (ret < 0) { + ret = -errno; + _E("getsockopt() is failed. errno(%d)", errno); + return ret; + } + + int value = timeout.tv_sec * 1000 + timeout.tv_usec / 1000; + return value; +} + +void ClientSocket::SetReceiveBufferSize(int size) { + socklen_t len = sizeof(size); + int ret = setsockopt(GetFd(), SOL_SOCKET, SO_RCVBUF, &size, len); + if (ret < 0) { + ret = -errno; + _E("setsockopt() is failed. errno(%d)", errno); + THROW(ret); + } +} + +void ClientSocket::SetSendBufferSize(int size) { + socklen_t len = sizeof(size); + int ret = setsockopt(GetFd(), SOL_SOCKET, SO_SNDBUF, &size, len); + if (ret < 0) { + ret = -errno; + _E("setsockopt() is failed. errno(%d)", errno); + THROW(ret); + } +} + +void ClientSocket::SetReceiveTimeout(int timeout) { + if (timeout == INT_MAX) + return; + + if (timeout == -1) + timeout = 5000; + + if (timeout < 0) { + _E("Invalid parameter"); + THROW(-EINVAL); + } + + struct timeval tv = { + .tv_sec = static_cast(timeout / 1000), + .tv_usec = static_cast((timeout % 1000) * 1000) + }; + socklen_t len = sizeof(struct timeval); + int ret = setsockopt(GetFd(), SOL_SOCKET, SO_RCVTIMEO, &tv, len); + if (ret < 0) { + ret = -errno; + _E("setsockopt() is failed. errno(%d)", errno); + THROW(ret); + } +} + +bool ClientSocket::IsClosed() { + return fd_ < 0 ? true : false; +} + +int ClientSocket::GetFd() const { + return fd_; +} + +int ClientSocket::RemoveFd() { + int fd = fd_; + fd_ = -1; + return fd; +} + +void ClientSocket::SetNonblock() { + int flag = fcntl(GetFd(), F_GETFL, 0); + fcntl(GetFd(), F_SETFL, flag | O_NONBLOCK); +} + +} // namespace internal +} // namespace rpc_port diff --git a/src/client-socket-internal.hh b/src/client-socket-internal.hh new file mode 100644 index 0000000..de7e960 --- /dev/null +++ b/src/client-socket-internal.hh @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021 Samsung Electronics 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 CLIENT_SOCKET_INTERNAL_HH_ +#define CLIENT_SOCKET_INTERNAL_HH_ + +#include + +namespace rpc_port { +namespace internal { + +class ClientSocket { + public: + ClientSocket(); + ClientSocket(int fd); + virtual ~ClientSocket(); + + void Close(); + int Connect(const std::string& endpoint); + int Send(const void* buf, unsigned int size); + int Receive(void* buf, unsigned int size); + int GetReceiveBufferSize(); + int GetSendBufferSize(); + int GetReceiveTimeout(); + void SetReceiveBufferSize(int size); + void SetSendBufferSize(int size); + void SetReceiveTimeout(int timeout); + bool IsClosed(); + int GetFd() const; + int RemoveFd(); + void SetNonblock(); + + private: + int fd_; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // CLIENT_SOCKET_INTERNAL_HH_ diff --git a/src/debug-port-internal.cc b/src/debug-port-internal.cc index debd51e..0d89d5f 100644 --- a/src/debug-port-internal.cc +++ b/src/debug-port-internal.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 - 2021 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/debug-port-internal.hh b/src/debug-port-internal.hh index caff4ac..27eb66b 100644 --- a/src/debug-port-internal.hh +++ b/src/debug-port-internal.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 - 2021 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/exception-internal.cc b/src/exception-internal.cc new file mode 100644 index 0000000..0ee27f0 --- /dev/null +++ b/src/exception-internal.cc @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021 Samsung Electronics 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 "exception-internal.hh" + +namespace rpc_port { +namespace internal { + +Exception::Exception(int error_code, const std::string& file, int line) + : error_code_(error_code), + message_(std::move(GetErrorMessage(error_code_, file, line))) { +} + +Exception::~Exception() = default; + +const char* Exception::what() const noexcept { + return message_.c_str(); +} + +int Exception::GetErrorCode() { + return error_code_; +} + +std::string Exception::GetErrorMessage(int error_code, const std::string& file, + int line) { + return file.substr(file.find_last_of("/") + 1) + ":" + std::to_string(line) + + " error_code: " + std::to_string(error_code); +} + +} // namespace internal +} // namespace rpc_port diff --git a/src/exception-internal.hh b/src/exception-internal.hh new file mode 100644 index 0000000..4f52240 --- /dev/null +++ b/src/exception-internal.hh @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 Samsung Electronics 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 EXCEPTION_INTERNAL_HH_ +#define EXCEPTION_INTERNAL_HH_ + +#include +#include + +#define THROW(error_code) throw Exception(error_code, __FUNCTION__, __LINE__) + +namespace rpc_port { +namespace internal { + +class Exception : public std::exception { + public: + explicit Exception(int error_code, const std::string& file, int line); + virtual ~Exception(); + + virtual const char* what() const noexcept; + int GetErrorCode(); + + private: + static std::string GetErrorMessage(int error_code, const std::string& file, + int line); + + private: + int error_code_; + std::string message_; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // EXCEPTION_INTERNAL_HH_ diff --git a/src/fdbroker-internal.cc b/src/fdbroker-internal.cc deleted file mode 100644 index 481a054..0000000 --- a/src/fdbroker-internal.cc +++ /dev/null @@ -1,957 +0,0 @@ -/* - * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved - * - * 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 _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include -#include -#include -#include -#include - -#include - -#include "fdbroker-internal.hh" -#include "log-private.hh" - -#define EILLEGALACCESS 127 - -#define DBUS_SERVICE_DBUS "org.freedesktop.DBus" -#define DBUS_PATH_DBUS "/org/freedesktop/DBus" -#define DBUS_INTERFACE_DBUS "org.freedesktop.DBus" -#define RPC_PORT_OBJECT_PATH "/org/tizen/rpcport" -#define RPC_PORT_INTERFACE_PREFIX "org.tizen.rpcport._" - -namespace rpc_port { -namespace internal { - -GDBusConnection* FdBroker::GetConnection() { - if (gdbus_conn_ == nullptr) { - GError* error = nullptr; - gdbus_conn_ = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error); - if (gdbus_conn_ == nullptr) { - _E("g_bus_get_sync() is failed. error(%s)", - error ? error->message : "Unknown"); - g_clear_error(&error); - return nullptr; - } - } - - return gdbus_conn_; -} - -// LCOV_EXCL_START -FdBroker::DBusMock& FdBroker::DBusMock::GetInst() { - static DBusMock mock; - - return mock; -} -// LCOV_EXCL_STOP - -// LCOV_EXCL_START -int FdBroker::DBusMock::Send(const std::string& sender, - const std::string& port, int fds[2]) { - if (port == "wrong_port") - return -EILLEGALACCESS; - if (ports_.find(port) == ports_.end()) - return -1; - - ports_[port]->OnFdReceived(sender, fds); - return 0; -} -// LCOV_EXCL_STOP - -// LCOV_EXCL_START -int FdBroker::DBusMock::AddListener(const std::string& port, - FdBroker::IEventListener* listener) { - if (ports_.find(port) != ports_.end()) - return -1; - - ports_[port] = listener; - return 0; -} -// LCOV_EXCL_STOP - -// LCOV_EXCL_START -int FdBroker::DBusMock::Watch(FdBroker::IEventWatcher* watcher, - const std::string& target_appid, - const std::string& port_name) { - watcher->OnPortAppeared(); - return 0; -} -// LCOV_EXCL_STOP - -// LCOV_EXCL_START -void FdBroker::DBusMock::Dispose() { - ports_.clear(); -} -// LCOV_EXCL_STOP - -FdBroker::SocketPair::SocketPair(bool mock) - : mock_(mock) { - socks_[SENDER] = 0; - socks_[RECEIVER] = 0; -} - -FdBroker::SocketPair::~SocketPair() { - if (socks_[SENDER] > 0) - close(socks_[SENDER]); - if (socks_[RECEIVER] > 0) - close(socks_[RECEIVER]); -} - -int FdBroker::SocketPair::Request(const std::string& target_appid, - const std::string& port_name) { - if (mock_) { - return socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, socks_); // LCOV_EXCL_LINE - } - - if (aul_rpc_port_create_socket_pair(target_appid.c_str(), - port_name.c_str(), &socks_) != AUL_R_OK) { - _E("error create socket pair"); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - return 0; -} - -int FdBroker::SocketPair::Get(Type t) const { - return socks_[t]; -} - -int FdBroker::SocketPair::Detach(Type t) { - int fd = socks_[t]; - - socks_[t] = 0; - return fd; -} - -FdBroker::FdList::FdList() { - fd_list_ = g_unix_fd_list_new(); -} - -FdBroker::FdList::~FdList() { - g_object_unref(fd_list_); -} - -int FdBroker::FdList::Add(int fd) { - GError* err = nullptr; - - g_unix_fd_list_append(fd_list_, fd, &err); - close(fd); - - if (err != NULL) { - _E("g_unix_fd_list_append [%s]", err->message); // LCOV_EXCL_LINE - g_error_free(err); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - return 0; -} - -GUnixFDList* FdBroker::FdList::GetRaw() { - return fd_list_; -} - -FdBroker::FdBroker(bool mock) : mock_(mock) { -} - -FdBroker::~FdBroker() { - Cancel(); - - if (gdbus_conn_) - g_object_unref(gdbus_conn_); -} - -void FdBroker::Cancel() { - std::lock_guard lock(GetMutex()); - LOGI("FdBroker::Cancel!"); - - if (cancellable_) { - _W("Cancel the send request"); - g_cancellable_cancel(cancellable_); - g_object_unref(cancellable_); - cancellable_ = nullptr; - } - - if (res_data_) { - DestroyWeakPtr(res_data_); - res_data_ = nullptr; - } - - UnsetConnTimer(); - - if (watcher_id_ > 0) { - g_bus_unwatch_name(watcher_id_); - watcher_id_ = 0; - } - - if (registration_id_ > 0) { - g_dbus_connection_unregister_object(GetConnection(), registration_id_); - registration_id_ = 0; - } - - if (mock_) { - DBusMock::GetInst().Dispose(); // LCOV_EXCL_LINE - } -} - -std::string FdBroker::GetInterfaceName(const std::string& target_appid, - const std::string& port_name) { - std::string interface_name = target_appid + "_" + port_name; - char c_buf[interface_name.length() * 2 + 1]; - char* temp = &c_buf[0]; - memset(c_buf, 0, sizeof(c_buf)); - for (unsigned int index = 0; index < interface_name.length(); index++) { - snprintf(temp, 3, "%02x", interface_name[index]); - temp += 2; - } - - return RPC_PORT_INTERFACE_PREFIX + std::string(c_buf); -} - -int FdBroker::Send(const std::string& target_appid, - const std::string& port_name, - int (*fds)[2]) { - std::string interface_name = GetInterfaceName(target_appid, port_name); - GDBusMessage* msg; - SocketPair main_sock_pair(mock_); - SocketPair delegate_sock_pair(mock_); - FdList fd_list; - - if (main_sock_pair.Request(target_appid, port_name) != 0) - return -1; - if (delegate_sock_pair.Request(target_appid, port_name) != 0) - return -1; - - if (mock_) { - // LCOV_EXCL_START - int send_fds[2]; - send_fds[0] = main_sock_pair.Detach(SocketPair::RECEIVER); - send_fds[1] = delegate_sock_pair.Detach(SocketPair::RECEIVER); - int ret = DBusMock::GetInst().Send("TestApp", port_name, send_fds); - if (ret < 0) - return ret; - - (*fds)[0] = main_sock_pair.Detach(SocketPair::SENDER); - (*fds)[1] = delegate_sock_pair.Detach(SocketPair::SENDER); - watcher_->OnPortConnected(); - return (*fds)[0]; - // LCOV_EXCL_STOP - } - - if (fd_list.Add(main_sock_pair.Detach(SocketPair::RECEIVER)) != 0) - return -1; - if (fd_list.Add(delegate_sock_pair.Detach(SocketPair::RECEIVER)) != 0) - return -1; - - msg = g_dbus_message_new_method_call(interface_name.c_str(), - RPC_PORT_OBJECT_PATH, - interface_name.c_str(), "send_message"); - if (!msg) { - _E("Can't allocate new method call"); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - std::lock_guard lock(GetMutex()); - if (cancellable_) { - g_cancellable_cancel(cancellable_); // LCOV_EXCL_LINE - g_object_unref(cancellable_); // LCOV_EXCL_LINE - } - - cancellable_ = g_cancellable_new(); - if (!cancellable_) { - _E("Failed to create GCancellable"); // LCOV_EXCL_LINE - g_object_unref(msg); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - if (res_data_) - DestroyWeakPtr(res_data_); - - res_data_ = CreateWeakPtr(); - if (res_data_ == nullptr) { - _E("Failed to create weak ptr"); - g_object_unref(msg); - return -1; - } - - g_dbus_message_set_unix_fd_list(msg, fd_list.GetRaw()); - g_dbus_connection_send_message_with_reply(GetConnection(), - msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE, - 5000, NULL, cancellable_, OnResultReceived, res_data_); - g_object_unref(msg); - - (*fds)[0] = main_sock_pair.Detach(SocketPair::SENDER); - (*fds)[1] = delegate_sock_pair.Detach(SocketPair::SENDER); - - return (*fds)[0]; -} - -// LCOV_EXCL_START -int FdBroker::SendSync(const std::string& target_appid, - const std::string& port_name, - int (*fds)[2]) { - SocketPair main_sock_pair(mock_); - int ret = main_sock_pair.Request(target_appid, port_name); - if (ret != 0) - return -1; - - SocketPair delegate_sock_pair(mock_); - ret = delegate_sock_pair.Request(target_appid, port_name); - if (ret != 0) - return -1; - - if (mock_) { - int send_fds[2]; - send_fds[0] = main_sock_pair.Detach(SocketPair::RECEIVER); - send_fds[1] = delegate_sock_pair.Detach(SocketPair::RECEIVER); - - ret = DBusMock::GetInst().Send("TestApp", port_name, send_fds); - if (ret < 0) - return ret; - - (*fds)[0] = main_sock_pair.Detach(SocketPair::SENDER); - (*fds)[1] = delegate_sock_pair.Detach(SocketPair::SENDER); - return (*fds)[0]; - } - - FdList fd_list; - ret = fd_list.Add(main_sock_pair.Detach(SocketPair::RECEIVER)); - if (ret != 0) - return -1; - - ret = fd_list.Add(delegate_sock_pair.Detach(SocketPair::RECEIVER)); - if (ret != 0) - return -1; - - std::string interface_name = GetInterfaceName(target_appid, port_name); - -#define MAX_CNT 100 -#define MAX_SLEEP 100 -#define MIN_SLEEP 50 -#define BASE_SLEEP (1000 * 1000) - GDBusMessage* reply; - GError* err = nullptr; - struct timespec try_sleep_time = { 0, MIN_SLEEP * BASE_SLEEP }; - struct timespec start_time = { 0, }; - struct timespec end_time = { 0, }; - int max_timeout = MAX_CNT * MAX_SLEEP; - - do { - clock_gettime(CLOCK_MONOTONIC, &start_time); - GDBusMessage* msg = g_dbus_message_new_method_call(interface_name.c_str(), - RPC_PORT_OBJECT_PATH, interface_name.c_str(), "send_message"); - if (msg == nullptr) { - _E("g_dbus_message_new_method_call() is failed"); - return -1; - } - - g_dbus_message_set_unix_fd_list(msg, fd_list.GetRaw()); - - reply = g_dbus_connection_send_message_with_reply_sync(GetConnection(), - msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE, 500, nullptr, nullptr, &err); - clock_gettime(CLOCK_MONOTONIC, &end_time); - g_object_unref(msg); - - if (reply && !g_dbus_message_to_gerror(reply, &err)) - break; - - if (reply == nullptr) { - _E("g_dbus_connection_send_message_with_reply_sync() is failed"); - if (err) { - _E("error(%s)", err->message); - g_error_free(err); - } - } else if (g_dbus_message_to_gerror(reply, &err)) { - _E("error(%s) was set", err->message); - g_error_free(err); - g_object_unref(reply); - } - err = nullptr; - - max_timeout -= (((end_time.tv_sec - start_time.tv_sec) * 1000) + - ((end_time.tv_nsec - start_time.tv_nsec) / BASE_SLEEP)); - if (max_timeout <= 0) - break; - - nanosleep(&try_sleep_time, 0); - max_timeout -= (try_sleep_time.tv_nsec / BASE_SLEEP); - if (max_timeout <= 0) - break; - - try_sleep_time.tv_nsec *= 2; - if (try_sleep_time.tv_nsec > (MAX_SLEEP * BASE_SLEEP)) - try_sleep_time.tv_nsec = MAX_SLEEP * BASE_SLEEP; - - _D("Retry"); - } while (max_timeout > 0); - - if (max_timeout <= 0) { - _E("Timed out"); - return -1; - } - - GVariant* reply_body = g_dbus_message_get_body(reply); - if (reply_body == nullptr) { - _E("g_dbus_message_get_body() is failed"); - g_object_unref(reply); - return -1; - } - - g_variant_get(reply_body, "(i)", &ret); - if (ret != 0) { - _E("Access Denied[result: %d]", ret); - g_object_unref(reply); - return -EILLEGALACCESS; - } - - _D("[Reply: %d]", ret); - - (*fds)[0] = main_sock_pair.Detach(SocketPair::SENDER); - (*fds)[1] = delegate_sock_pair.Detach(SocketPair::SENDER); - - return (*fds)[0]; -} -// LCOV_EXCL_STOP - -void FdBroker::ReceiveMessage(const char* sender_appid, - GDBusMethodInvocation* invocation) { - GDBusMessage* msg; - GUnixFDList* fd_list; - int fd_len = 0; - int* returned_fds = nullptr; - - msg = g_dbus_method_invocation_get_message(invocation); - fd_list = g_dbus_message_get_unix_fd_list(msg); - - if (fd_list == nullptr) - return; // LCOV_EXCL_LINE - - returned_fds = g_unix_fd_list_steal_fds(fd_list, &fd_len); - if (returned_fds == nullptr || fd_len != 2) { - _E("fail to get fds. fd_len(%d)", fd_len); // LCOV_EXCL_LINE - return; // LCOV_EXCL_LINE - } - - listener_->OnFdReceived(sender_appid, returned_fds); - free(returned_fds); -} - -void FdBroker::OnReceiveDbusMethod(GDBusConnection* conn, - const gchar* sender, const gchar* object_path, - const gchar* iface_name, const gchar* method_name, - GVariant* parameters, GDBusMethodInvocation* invocation, - gpointer user_data) { - auto* ptr = static_cast*>(user_data); - auto broker = ptr->lock(); - if (broker == nullptr) { - _E("broker is nullptr"); - return; - } - - std::lock_guard lock(broker->GetMutex()); - if (broker->registration_id_ == 0) { - _E("Invalid context. FdBroker(%p)", broker.get()); - return; - } - - std::string sender_id; - int sender_pid = broker->GetSenderPid(conn, sender); - char sender_appid[256]; - int ret = aul_app_get_appid_bypid(sender_pid, sender_appid, - sizeof(sender_appid)); - if (ret < 0) - sender_id = "Daemon"; - else - sender_id = std::string(sender_appid); - - if (sender_id.empty()) { - ret = -1; - g_dbus_method_invocation_return_value(invocation, - g_variant_new("(i)", ret)); - return; - } - - AccessController& ac = broker->GetAccessController(); - ret = ac.Check(conn, sender, sender_id.c_str()); - if (ret == 0) - broker->ReceiveMessage(sender_id.c_str(), invocation); - - g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ret)); -} - -int FdBroker::GetOwnerId(const std::string& interface_name) { - int owner_id = 0; - GError* error = NULL; - - GVariant* result = g_dbus_connection_call_sync( - GetConnection(), - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "RequestName", - g_variant_new("(su)", interface_name.c_str(), - G_BUS_NAME_OWNER_FLAGS_NONE), - G_VARIANT_TYPE("(u)"), - G_DBUS_CALL_FLAGS_NONE, - -1, - nullptr, - &error); - - if (error) { - _E("RequestName fail : %s", error->message); // LCOV_EXCL_LINE - g_error_free(error); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - if (result == nullptr) { - _E("fail to get name NULL"); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - g_variant_get(result, "(u)", &owner_id); - if (owner_id == 0) { - _E("Acquiring the own name is failed"); // LCOV_EXCL_LINE - g_variant_unref(result); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - _D("Acquiring the own name : %d", owner_id); - g_variant_unref(result); - - return owner_id; -} - -int FdBroker::GetSenderPid(GDBusConnection* connection, const gchar* sender) { - GDBusMessage* msg = NULL; - GDBusMessage* reply = NULL; - GError* err = NULL; - GVariant* body; - int pid = 0; - - msg = g_dbus_message_new_method_call("org.freedesktop.DBus", - "/org/freedesktop/DBus", "org.freedesktop.DBus", - "GetConnectionUnixProcessID"); - if (!msg) { - _E("Can't allocate new method call"); // LCOV_EXCL_LINE - goto out; // LCOV_EXCL_LINE - } - - g_dbus_message_set_body(msg, g_variant_new("(s)", sender)); - reply = g_dbus_connection_send_message_with_reply_sync(connection, msg, - G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL, &err); - - if (!reply) { - // LCOV_EXCL_START - if (err != NULL) { - _E("Failed to get pid [%s]", err->message); - g_error_free(err); - } - goto out; - // LCOV_EXCL_STOP - } - - body = g_dbus_message_get_body(reply); - g_variant_get(body, "(u)", &pid); - -out: - if (msg) - g_object_unref(msg); - if (reply) - g_object_unref(reply); - - return pid; -} - -int FdBroker::RegisterDbusInterface(const std::string& port_name) { - static const GDBusInterfaceVTable interface_vtable = { - OnReceiveDbusMethod, - nullptr, - nullptr - }; - static const char introspection_prefix[] = - "" - " " - " " - " " - " " - " " - ""; - char appid[255]; - - if (aul_app_get_appid_bypid(getpid(), appid, sizeof(appid)) < 0) - return -1; - - std::string interface_name = GetInterfaceName(appid, port_name); - std::string introspection_xml = introspection_prefix + - interface_name + - introspection_postfix; - - GDBusNodeInfo* introspection_data = g_dbus_node_info_new_for_xml( - introspection_xml.c_str(), nullptr); - if (!introspection_data) { - _E("g_dbus_node_info_new_for_xml() is failed."); - return -1; - } - - auto broker = CreateWeakPtr(); - if (broker == nullptr) { - _E("Failed to create weak ptr"); - return -1; - } - - std::lock_guard lock(GetMutex()); - registration_id_ = g_dbus_connection_register_object( - GetConnection(), - RPC_PORT_OBJECT_PATH, introspection_data->interfaces[0], - &interface_vtable, broker, DestroyWeakPtr, nullptr); - - g_dbus_node_info_unref(introspection_data); - if (registration_id_ == 0) { - _E("Failed to g_dbus_connection_register_object"); - return -1; - } - - if (GetOwnerId(interface_name) < 0) { - _E("Failed to get owner id"); - return -1; - } - - LOGI("%s is registered", port_name.c_str()); - - return 0; -} - -int FdBroker::Listen(IEventListener* ev, const std::string& port_name) { - if (listener_ != nullptr) { - _E("listener_ is not NULL"); // LCOV_EXCL_LINE - return RPC_PORT_ERROR_INVALID_PARAMETER; // LCOV_EXCL_LINE - } - - if (ev == nullptr) { - _E("ev is NULL"); // LCOV_EXCL_LINE - return RPC_PORT_ERROR_INVALID_PARAMETER; // LCOV_EXCL_LINE - } - - if (mock_) { - // LCOV_EXCL_START - int ret = DBusMock::GetInst().AddListener(port_name, ev); - - if (ret < 0) - return ret; - - return RPC_PORT_ERROR_NONE; - // LCOV_EXCL_STOP - } - - int ret = RegisterDbusInterface(port_name); - - if (ret != 0) { - _E("Failed to register dbus interface"); // LCOV_EXCL_LINE - return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE - } - - listener_ = ev; - return RPC_PORT_ERROR_NONE; -} - -AccessController& FdBroker::GetAccessController() { - return ac_; -} - -void FdBroker::OnNameAppeared(GDBusConnection* connection, - const gchar* name, - const gchar* name_owner, - gpointer user_data) { - auto* ptr = static_cast*>(user_data); - auto broker = ptr->lock(); - if (broker == nullptr) { - _E("broker is nullptr"); - return; - } - - std::lock_guard lock(broker->GetMutex()); - if (broker->watcher_id_ == 0) { - _E("Invalid context. FdBroker(%p)", broker.get()); - return; - } - - broker->UnsetConnTimer(); - int pid = broker->GetSenderPid(connection, name_owner); - char owner_appid[255] = { 0, }; - - if (aul_app_get_appid_bypid(pid, owner_appid, sizeof(owner_appid)) < 0) { - // LCOV_EXCL_START - _E("aul_app_get_appid_bypid failed %d", pid); - broker->watcher_->OnPortRejected(RPC_PORT_ERROR_IO_ERROR); - return; - // LCOV_EXCL_STOP - } - - if (broker->watch_appid_ != owner_appid) { - // LCOV_EXCL_START - _E("invalid appid %s", owner_appid); - broker->watcher_->OnPortRejected(RPC_PORT_ERROR_IO_ERROR); - return; - // LCOV_EXCL_STOP - } - - broker->watcher_->OnPortAppeared(); -} - -void FdBroker::OnNameVanished(GDBusConnection* connection, - const gchar* name, - gpointer user_data) { - auto* ptr = static_cast*>(user_data); - auto broker = ptr->lock(); - if (broker == nullptr) { - _E("broker is nullptr"); - return; - } - - std::lock_guard lock(broker->GetMutex()); - if (broker->watcher_id_ == 0) { - _E("Invalid context. FdBroker(%p)", broker.get()); - return; - } - - broker->watcher_->OnPortVanished(); -} - -int FdBroker::Watch(IEventWatcher* ev, const std::string& target_appid, - const std::string& port_name) { - std::lock_guard lock(GetMutex()); - if (ev == nullptr) - return -1; - - int ret = Prepare(target_appid, port_name); - if (ret < 0) - return ret; - - watcher_ = ev; - watch_appid_ = target_appid; - watch_port_name_ = port_name; - UnsetConnTimer(); - - if (mock_) { - // LCOV_EXCL_START - ret = DBusMock::GetInst().Watch(ev, target_appid, port_name); - if (ret < 0) - return -1; - - SetConnTimer(); - return 0; - // LCOV_EXCL_STOP - } - - std::string interface_name = GetInterfaceName(target_appid, port_name); - - if (watcher_id_ > 0) { - // LCOV_EXCL_START - g_bus_unwatch_name(watcher_id_); - _D("Retry to watch name. stub %s:%s", - target_appid.c_str(), port_name.c_str()); - // LCOV_EXCL_STOP - } - - auto broker = CreateWeakPtr(); - if (broker == nullptr) { - _E("Failed to create weak ptr"); - return -1; - } - - watcher_id_ = g_bus_watch_name_on_connection( - GetConnection(), - interface_name.c_str(), - G_BUS_NAME_WATCHER_FLAGS_NONE, - OnNameAppeared, - OnNameVanished, - broker, - DestroyWeakPtr); - if (watcher_id_ == 0) { - // LCOV_EXCL_START - _E("Failed to watch connection(%s)", interface_name.c_str()); - watcher_ = nullptr; - return -1; - // LCOV_EXCL_STOP - } - - SetConnTimer(); - return 0; -} - -int FdBroker::Prepare(const std::string& target_appid, - const std::string& port_name) { - if (!mock_) { - int ret = aul_rpc_port_prepare_stub(target_appid.c_str(), - port_name.c_str()); - if (ret != AUL_R_OK) { - // LCOV_EXCL_START - _E("Failed to prepare stub %s:%s [ret : %d]", - target_appid.c_str(), port_name.c_str(), ret); - if (ret == AUL_R_EILLACC) - return -EILLEGALACCESS; - - return ret; - // LCOV_EXCL_STOP - } - } - - return 0; -} - -void FdBroker::OnResultReceived(GObject* source_object, - GAsyncResult* res, - gpointer user_data) { - _W("OnResultReceived()"); - GDBusConnection* conn = reinterpret_cast(source_object); - GError* err = nullptr; - GDBusMessage* reply = g_dbus_connection_send_message_with_reply_finish(conn, - res, &err); - if (reply == nullptr) { - if (err) { - if (err->code == G_IO_ERROR_CANCELLED) - _E("IO error cancelled"); - g_error_free(err); - } else { - _E("g_dbus_connection_send_message_with_reply_finish() is failed"); - } - return; - } - - auto reply_ptr = std::unique_ptr( - reply, g_object_unref); - auto* ptr = static_cast*>(user_data); - auto broker = ptr->lock(); - if (broker == nullptr) { - _E("broker is nullptr"); - return; - } - - std::lock_guard lock(broker->GetMutex()); - if (broker->cancellable_ == nullptr) { - _E("Invalid context. Fdbroker(%p)", broker.get()); - return; - } - - IEventWatcher* watcher = broker->watcher_; - if (g_dbus_message_to_gerror(reply, &err)) { - _E("Failed to send message. error(%s)", err->message); - g_error_free(err); - watcher->OnPortDisconnected(true); - if (broker->cancellable_) { - _W("Cancel the send request"); - g_cancellable_cancel(broker->cancellable_); - g_object_unref(broker->cancellable_); - broker->cancellable_ = nullptr; - } - return; - } - - GVariant* reply_body = g_dbus_message_get_body(reply); - if (reply_body == nullptr) { - _E("g_dbus_message_get_body() is failed"); - watcher->OnPortDisconnected(); - return; - } - - int ret; - g_variant_get(reply_body, "(i)", &ret); - if (ret != 0) { - _E("Access Denied[sender_appid : %s]", broker->watch_appid_.c_str()); - watcher->OnPortRejected(RPC_PORT_ERROR_PERMISSION_DENIED); - return; - } - - watcher->OnPortConnected(); - _D("[Reply : %d]", ret); -} - -gboolean FdBroker::OnDbusNameTimeout(gpointer user_data) { - auto* ptr = static_cast*>(user_data); - auto broker = ptr->lock(); - if (broker == nullptr) { - _E("broker is nullptr"); - return G_SOURCE_REMOVE; - } - - std::lock_guard lock(broker->GetMutex()); - if (broker->conn_data_ == nullptr) { - _E("Invalid context. FdBroker(%p)", broker.get()); - return G_SOURCE_REMOVE; - } - - DestroyWeakPtr(broker->conn_data_); - broker->conn_data_ = nullptr; - broker->Cancel(); - auto* watcher = broker->watcher_; - watcher->OnPortRejected(RPC_PORT_ERROR_IO_ERROR); - - return G_SOURCE_REMOVE; -} - -std::shared_ptr FdBroker::GetSharedPtr() { - return shared_from_this(); -} - -gpointer FdBroker::CreateWeakPtr() { - auto* ptr = new (std::nothrow) std::weak_ptr(GetSharedPtr()); - return static_cast(ptr); -} - -void FdBroker::DestroyWeakPtr(gpointer data) { - auto* ptr = static_cast*>(data); - delete ptr; -} - -void FdBroker::SetConnTimer() { - if (conn_data_) { - _W("Already exists"); - return; - } - - conn_data_ = CreateWeakPtr(); - if (conn_data_ == nullptr) - _E("Out of memory"); - - g_timeout_add(10 * 1000, OnDbusNameTimeout, conn_data_); -} - -void FdBroker::UnsetConnTimer() { - if (conn_data_ == nullptr) - return; - - GSource* source = g_main_context_find_source_by_user_data(nullptr, - conn_data_); - if (source && !g_source_is_destroyed(source)) - g_source_destroy(source); - - DestroyWeakPtr(conn_data_); - conn_data_ = nullptr; -} - -std::recursive_mutex& FdBroker::GetMutex() const { - return mutex_; -} - -} // namespace internal -} // namespace rpc_port diff --git a/src/fdbroker-internal.hh b/src/fdbroker-internal.hh deleted file mode 100644 index 01dc6d0..0000000 --- a/src/fdbroker-internal.hh +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2017 - 2020 Samsung Electronics 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 FDBROKER_INTERNAL_H_ -#define FDBROKER_INTERNAL_H_ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "ac-internal.hh" -#include "rpc-port.h" - -namespace rpc_port { -namespace internal { - -class FdBroker : public std::enable_shared_from_this { - public: - class IEventListener { - public: - virtual void OnFdReceived(const std::string& sender, int fds[2]) = 0; - }; - - class IEventWatcher { - public: - virtual void OnPortAppeared() = 0; - virtual void OnPortVanished() = 0; - virtual void OnPortRejected(int error) = 0; - virtual void OnPortConnected() = 0; - virtual void OnPortDisconnected(bool cancel = false) = 0; - }; - - explicit FdBroker(bool mock = false); - ~FdBroker(); - - void Cancel(); - int Send(const std::string& target_appid, const std::string& port_name, - int (*fds)[2]); - int Listen(IEventListener* ev, const std::string& port_name); - AccessController& GetAccessController(); - int Watch(IEventWatcher* ev, const std::string& target_appid, - const std::string& port_name); - int Prepare(const std::string& target_appid, const std::string& port_name); - int SendSync(const std::string& target_appid, const std::string& port_name, - int (*fds)[2]); - - private: - class DBusMock { - public: - DBusMock(const DBusMock&) = delete; - DBusMock& operator = (const DBusMock&) = delete; - - static DBusMock& GetInst(); - int Send(const std::string& sender, const std::string& port, int fds[2]); - int AddListener(const std::string& port, - FdBroker::IEventListener* listener); - int Watch(FdBroker::IEventWatcher* watcher, const std::string& target_appid, - const std::string& port_name); - void Dispose(); - - private: - DBusMock() = default; // LCOV_EXCL_LINE - ~DBusMock() = default; // LCOV_EXCL_LINE - - private: - std::map ports_; - }; - - class SocketPair { - public: - enum Type { - SENDER = 0, - RECEIVER = 1 - }; - - explicit SocketPair(bool mock = false); - ~SocketPair(); - - int Request(const std::string& target_appid, const std::string& port_name); - void RequestMock(); - int Get(Type t) const; - int Detach(Type t); - - private: - int socks_[2]; - bool mock_; - }; - - class FdList { - public: - FdList(); - ~FdList(); - - int Add(int fd); - GUnixFDList* GetRaw(); - - private: - GUnixFDList* fd_list_; - }; - - private: - static void OnReceiveDbusMethod(GDBusConnection* conn, const gchar* sender, - const gchar* object_path, - const gchar* iface_name, - const gchar* method_name, - GVariant* parameters, - GDBusMethodInvocation* invocation, - gpointer user_data); - int GetOwnerId(const std::string& interface_name); - int GetSenderPid(GDBusConnection* connection, const gchar* sender); - int RegisterDbusInterface(const std::string& port_name); - void ReceiveMessage(const char* sender_appid, - GDBusMethodInvocation* invocation); - std::string GetInterfaceName(const std::string& target_appid, - const std::string& port_name); - static void OnNameAppeared(GDBusConnection* connection, - const gchar* name, - const gchar* name_owner, - gpointer user_data); - static void OnNameVanished(GDBusConnection* connection, - const gchar* name, - gpointer user_data); - static void OnResultReceived(GObject* source_object, - GAsyncResult* res, - gpointer user_data); - static gboolean OnDbusNameTimeout(gpointer user_data); - - std::shared_ptr GetSharedPtr(); - gpointer CreateWeakPtr(); - static void DestroyWeakPtr(gpointer data); - void SetConnTimer(); - void UnsetConnTimer(); - std::recursive_mutex& GetMutex() const; - GDBusConnection* GetConnection(); - - private: - IEventListener* listener_ = nullptr; - int registration_id_ = 0; - bool mock_; - AccessController ac_; - IEventWatcher* watcher_ = nullptr; - guint watcher_id_ = 0; - std::string watch_appid_; - std::string watch_port_name_; - GCancellable* cancellable_ = nullptr; - gpointer res_data_ = nullptr; - gpointer conn_data_ = nullptr; - mutable std::recursive_mutex mutex_; - GDBusConnection* gdbus_conn_ = nullptr; -}; - -} // namespace internal -} // namespace rpc_port - -#endif // FDBROKER_INTERNAL_H_ diff --git a/src/log-private.hh b/src/log-private.hh index 6c6b2d6..36aeb9c 100644 --- a/src/log-private.hh +++ b/src/log-private.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 - 2021 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/peer-cred-internal.cc b/src/peer-cred-internal.cc new file mode 100644 index 0000000..eebc131 --- /dev/null +++ b/src/peer-cred-internal.cc @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021 Samsung Electronics 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 + +#include + +#include "log-private.hh" +#include "peer-cred-internal.hh" + +namespace rpc_port { +namespace internal { + +PeerCred::PeerCred(pid_t pid, uid_t uid, gid_t gid) + : pid_(pid), uid_(uid), gid_(gid) { +} + +PeerCred* PeerCred::Get(int fd) { + struct ucred cred; + socklen_t len = sizeof(struct ucred); + int ret = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, + static_cast(&cred), &len); + if (ret != 0) { + _E("getsockopt() is failed. fd(%d), errno(%d)", fd, errno); + return nullptr; + } + + return new (std::nothrow) PeerCred(cred.pid, cred.uid, cred.gid); +} + +pid_t PeerCred::GetPid() const { + return pid_; +} + +uid_t PeerCred::GetUid() const { + return uid_; +} + +gid_t PeerCred::GetGid() const { + return gid_; +} + +} // namespace internal +} // namespace rpc_port diff --git a/src/peer-cred-internal.hh b/src/peer-cred-internal.hh new file mode 100644 index 0000000..bf57ed5 --- /dev/null +++ b/src/peer-cred-internal.hh @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 Samsung Electronics 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 PEER_CRED_INTERNAL_HH_ +#define PEER_CRED_INTERNAL_HH_ + +namespace rpc_port { +namespace internal { + +class PeerCred { + public: + static PeerCred* Get(int fd); + + pid_t GetPid() const; + uid_t GetUid() const; + gid_t GetGid() const; + + private: + PeerCred(pid_t pid, uid_t uid, gid_t gid); + + private: + pid_t pid_; + uid_t uid_; + gid_t gid_; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // PEER_CRED_INTERNAL_HH_ diff --git a/src/port-internal.cc b/src/port-internal.cc index 1c939da..79438f2 100644 --- a/src/port-internal.cc +++ b/src/port-internal.cc @@ -1,36 +1,32 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd All Rights Reserved * - * Licensed under the Apache License, Version 2.0 (the License); + * 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, + * 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 _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include -#include +#include +#include +#include #include +#include +#include +#include #include #include -#include -#include -#include +#include "include/rpc-port.h" #include "log-private.hh" #include "port-internal.hh" -#include "rpc-port.h" #define MAX_CNT 100 #define MAX_SLEEP 100 diff --git a/src/port-internal.hh b/src/port-internal.hh index 0286304..d6fc428 100644 --- a/src/port-internal.hh +++ b/src/port-internal.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,18 +14,19 @@ * limitations under the License. */ -#ifndef PORT_INTERNAL_H_ -#define PORT_INTERNAL_H_ +#ifndef PORT_INTERNAL_HH_ +#define PORT_INTERNAL_HH_ -#include +#include + +#include +#include +#include #include +#include #include -#include -#include +#include #include -#include -#include -#include namespace rpc_port { namespace internal { @@ -107,4 +108,4 @@ class Port { } // namespace internal } // namespace rpc_port -#endif // PORT_INTERNAL_H_ +#endif // PORT_INTERNAL_HH_ diff --git a/src/proxy-internal.cc b/src/proxy-internal.cc index cac8637..9f7ac7c 100644 --- a/src/proxy-internal.cc +++ b/src/proxy-internal.cc @@ -1,259 +1,309 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd All Rights Reserved * - * Licensed under the Apache License, Version 2.0 (the License); + * 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, + * 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 _GNU_SOURCE -#define _GNU_SOURCE -#endif - #include #include #include #include +#include + +#include +#include "aul-internal.hh" #include "debug-port-internal.hh" +#include "exception-internal.hh" +#include "include/rpc-port-internal.h" #include "log-private.hh" #include "proxy-internal.hh" +#include "request-internal.hh" +#include "response-internal.hh" #define EILLEGALACCESS 127 namespace rpc_port { namespace internal { +namespace { -Proxy::Proxy(bool mock) - : fd_broker_(new FdBroker(mock)) {} +constexpr const char kPortTypeMain[] = "main"; +constexpr const char kPortTypeDelegate[] = "delegate"; -Proxy::~Proxy() { - _D("Proxy::~Proxy"); +std::string GenInstance() { + uuid_t u; + uuid_generate(u); + char uuid[37]; + uuid_unparse(u, uuid); + return std::string(uuid) + "@" + Aul::GetAppId(getpid()); } -gboolean Proxy::OnSocketDisconnected(GIOChannel* gio, GIOCondition cond, - gpointer data) { - Proxy* proxy = static_cast(data); - IEventListener* listener = proxy->listener_; - int fd = g_io_channel_unix_get_fd(gio); - - _W("Socket was disconnected. fd(%d)", fd); - - if (proxy->main_port_.get() != nullptr && proxy->main_port_->GetFd() == fd) { - proxy->listener_ = nullptr; - proxy->main_port_->SetDisconnectedSource(0); - if (listener) - listener->OnDisconnected(proxy->target_appid_); - - proxy->main_port_.reset(); - proxy->delegate_port_.reset(); - } else if (proxy->delegate_port_->GetFd() == fd) { - proxy->listener_ = nullptr; - proxy->delegate_port_->SetDisconnectedSource(0); - if (listener) - listener->OnDisconnected(proxy->target_appid_); +int SendRequest(ClientSocket* client, const Request& request) { + tizen_base::Parcel parcel; + parcel.WriteParcelable(const_cast(request)); + const std::vector& raw = parcel.GetRaw(); + size_t size = raw.size(); + int ret = client->Send(reinterpret_cast(&size), sizeof(size)); + if (ret != 0) { + _E("Send() is failed. error(%d)", ret); + return -1; + } - proxy->main_port_.reset(); - proxy->delegate_port_.reset(); + ret = client->Send(raw.data(), raw.size()); + if (ret != 0) { + _E("Send() is failed. error(%d)", ret); + return -1; } - DebugPort::GetInst().RemoveSession(fd); - return FALSE; + return 0; } -gboolean Proxy::OnDataReceived(GIOChannel* gio, GIOCondition cond, - gpointer data) { - Proxy* proxy = static_cast(data); - int fd = g_io_channel_unix_get_fd(gio); - char buffer[4]; - - if (proxy->delegate_port_->GetFd() == fd) { - if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) { - _W("Socket was disconnected by stub. fd(%d)", fd); - IEventListener* listener = proxy->listener_; - proxy->listener_ = nullptr; - proxy->delegate_port_->SetSource(0); - if (listener) - listener->OnDisconnected(proxy->target_appid_); +int ReceiveResponse(ClientSocket* client, Response** response) { + size_t size = 0; + int ret = client->Receive(reinterpret_cast(&size), sizeof(size)); + if (ret != 0) { + _E("Receive() is failed. error(%d)", ret); + return -1; + } - if (proxy->main_port_.get() != nullptr) { - DebugPort::GetInst().RemoveSession(proxy->main_port_->GetFd()); - proxy->main_port_.reset(); - } - proxy->delegate_port_.reset(); - return FALSE; - } + std::vector buf(size); + ret = client->Receive(buf.data(), size); + if (ret != 0) { + _E("Receive() is failed. error(%d)", ret); + return -1; + } - if (proxy->listener_) - proxy->listener_->OnReceived(proxy->target_appid_); + tizen_base::Parcel parcel(buf.data(), buf.size()); + *response = new (std::nothrow) Response(); + if (*response == nullptr) { + _E("Out of memory"); + return -1; } - return TRUE; + parcel.ReadParcelable(*response); + return 0; } -void Proxy::OnPortRejected(int error) { - _W("[__OnPortRejected__] endpoint(%s), error(%d)", - target_appid_.c_str(), error); - if (listener_ == nullptr) - return; +} // namespace - IEventListener* listener = listener_; - listener_ = nullptr; - listener->OnRejected(target_appid_, error); +Proxy::Proxy() { + _D("Proxy::Proxy()"); } -void Proxy::OnPortAppeared() { - _D("endpoint(%s), port_name(%s)", target_appid_.c_str(), port_name_.c_str()); - if (listener_ == nullptr) - return; +Proxy::~Proxy() { + std::lock_guard lock(GetMutex()); + _D("Proxy::~Proxy()"); + listener_ = nullptr; + UnsetConnTimer(); + Cancel(); +} +int Proxy::Connect(bool sync) { + std::lock_guard lock(GetMutex()); fds_[0] = 0; fds_[1] = 0; - int r = fd_broker_->Send(real_appid_, port_name_, &fds_); - if (r <= 0) { - // LCOV_EXCL_START - IEventListener* listener = listener_; - listener_ = nullptr; - if (r == -EILLEGALACCESS) - listener->OnRejected(target_appid_, RPC_PORT_ERROR_PERMISSION_DENIED); - else - listener->OnDisconnected(target_appid_); - return; - // LCOV_EXCL_STOP - } - _W("[__OnPortAppeared__] fds[0]: %d, fds[1]: %d", fds_[0], fds_[1]); -} + std::string port_path = Aul::GetPortPath(real_appid_, port_name_, + rpc_port_get_target_uid()); + std::string instance = GenInstance(); -void Proxy::OnPortVanished() { - _W("[__OnPortVanished__] endpoint(%s), port_name(%s)", - target_appid_.c_str(), port_name_.c_str()); -} + // Main Port + main_client_.reset(Client::Create(this, port_path)); + if (main_client_.get() == nullptr) + return RPC_PORT_ERROR_IO_ERROR; -void Proxy::OnPortConnected() { - _W("[__OnPortConnected__] endpoint(%s), port_name(%s)", - target_appid_.c_str(), port_name_.c_str()); - if (!listener_) { - _W("listener is null"); // LCOV_EXCL_LINE - return; // LCOV_EXCL_LINE - } + Request request(instance.c_str(), kPortTypeMain); + int ret = SendRequest(main_client_.get(), request); + if (ret != 0) + return RPC_PORT_ERROR_IO_ERROR; - main_port_.reset(new ProxyPort(this, fds_[0], target_appid_, false)); - delegate_port_.reset(new ProxyPort(this, fds_[1], target_appid_)); - listener_->OnConnected(target_appid_, main_port_.get()); - DebugPort::GetInst().AddSession(port_name_, target_appid_, fds_[0], fds_[1]); -} + if (sync) { + Response* response = nullptr; + ret = ReceiveResponse(main_client_.get(), &response); + if (ret != 0) + return RPC_PORT_ERROR_IO_ERROR; -// LCOV_EXCL_START -void Proxy::OnPortDisconnected(bool cancel) { - _W("[__OnPortDisconnected__] endporint(%s), port_name(%s)", - target_appid_.c_str(), port_name_.c_str()); + std::unique_ptr response_auto(response); + if (response->GetResult() != 0) { + _E("Permission denied"); + return RPC_PORT_ERROR_PERMISSION_DENIED; + } - if (cancel) { - close(fds_[0]); - close(fds_[1]); + main_client_->SetNonblock(); + fds_[0] = main_client_->RemoveFd(); + } else { + ret = main_client_->Watch(); + if (ret != 0) + return RPC_PORT_ERROR_IO_ERROR; } - if (!listener_) { - _W("listener is null"); - return; + // Delegate Port + delegate_client_.reset(Client::Create(this, port_path)); + if (delegate_client_.get() == nullptr) + return RPC_PORT_ERROR_IO_ERROR; + + request.SetPortType(kPortTypeDelegate); + ret = SendRequest(delegate_client_.get(), request); + if (ret != 0) + return RPC_PORT_ERROR_IO_ERROR; + + if (sync) { + Response* response = nullptr; + ret = ReceiveResponse(delegate_client_.get(), &response); + if (ret != 0) + return RPC_PORT_ERROR_IO_ERROR; + + std::unique_ptr response_auto(response); + if (response->GetResult() != 0) { + _E("Permission denied"); + return RPC_PORT_ERROR_PERMISSION_DENIED; + } + + delegate_client_->SetNonblock(); + fds_[1] = delegate_client_->RemoveFd(); + } else { + ret = delegate_client_->Watch(); + if (ret != 0) + return RPC_PORT_ERROR_IO_ERROR; } - IEventListener* listener = listener_; - listener_ = nullptr; - listener->OnDisconnected(target_appid_); - DebugPort::GetInst().RemoveSession(fds_[0]); + return RPC_PORT_ERROR_NONE; } -// LCOV_EXCL_STOP int Proxy::Connect(std::string appid, std::string port_name, - IEventListener* ev) { - if (ev == nullptr) + IEventListener* listener) { + if (listener == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; if (listener_ != nullptr) { - _D("Already connected"); // LCOV_EXCL_LINE - return RPC_PORT_ERROR_INVALID_PARAMETER; // LCOV_EXCL_LINE + _D("Already requested"); + return RPC_PORT_ERROR_INVALID_PARAMETER; } - listener_ = ev; + std::lock_guard lock(GetMutex()); + listener_ = listener; target_appid_ = std::move(appid); port_name_ = std::move(port_name); SetRealAppId(target_appid_); - int r = fd_broker_->Watch(this, real_appid_, port_name_); - if (r < 0) { - // LCOV_EXCL_START + UnsetConnTimer(); + int ret = Aul::PrepareStub(real_appid_, port_name_, + rpc_port_get_target_uid()); + if (ret != RPC_PORT_ERROR_NONE) { listener_ = nullptr; - if (r == -EILLEGALACCESS) - return RPC_PORT_ERROR_PERMISSION_DENIED; + return ret; + } + ret = Watch(); + if (ret != 0) { + listener_ = nullptr; return RPC_PORT_ERROR_IO_ERROR; - // LCOV_EXCL_STOP } return RPC_PORT_ERROR_NONE; } int Proxy::ConnectSync(std::string appid, std::string port_name, - IEventListener* ev) { - if (ev == nullptr) + IEventListener* listener) { + if (listener == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; if (listener_ != nullptr) { - _W("Already connected"); + _W("Already requested"); return RPC_PORT_ERROR_INVALID_PARAMETER; } - listener_ = ev; + std::lock_guard lock(GetMutex()); + listener_ = listener; target_appid_ = std::move(appid); port_name_ = std::move(port_name); SetRealAppId(target_appid_); - int ret = fd_broker_->Prepare(real_appid_, port_name_); - if (ret < 0) { + int ret = Aul::PrepareStub(real_appid_, port_name_, + rpc_port_get_target_uid()); + if (ret != RPC_PORT_ERROR_NONE) { listener_ = nullptr; - if (ret == -EILLEGALACCESS) - return RPC_PORT_ERROR_PERMISSION_DENIED; + return ret; + } + bool exist = false; + int retry_count = 20; + do { + exist = Aul::ExistPort(real_appid_, port_name_, rpc_port_get_target_uid()); + if (exist) + break; + + usleep(500 * 1000); + retry_count--; + } while (retry_count > 0); + + if (!exist) { + _E("%s:%s is not ready", real_appid_.c_str(), port_name_.c_str()); + listener_ = nullptr; return RPC_PORT_ERROR_IO_ERROR; } - fds_[0] = 0; - fds_[1] = 0; - ret = fd_broker_->SendSync(real_appid_, port_name_, &fds_); - if (ret <= 0) { + ret = Connect(true); + if (ret != RPC_PORT_ERROR_NONE) { listener_ = nullptr; - if (ret == -EILLEGALACCESS) - return RPC_PORT_ERROR_PERMISSION_DENIED; - - return RPC_PORT_ERROR_IO_ERROR; + return ret; } main_port_.reset(new ProxyPort(this, fds_[0], target_appid_, false)); delegate_port_.reset(new ProxyPort(this, fds_[1], target_appid_)); listener_->OnConnected(target_appid_, main_port_.get()); DebugPort::GetInst().AddSession(port_name, target_appid_, fds_[0], fds_[1]); - return RPC_PORT_ERROR_NONE; } void Proxy::DisconnectPort() { + std::lock_guard lock(GetMutex()); if (main_port_.get() != nullptr) { DebugPort::GetInst().RemoveSession(main_port_->GetFd()); main_port_.reset(); } } +int Proxy::Watch() { + std::lock_guard lock(GetMutex()); + int ret = aul_rpc_port_usr_add_watch(real_appid_.c_str(), port_name_.c_str(), + OnPortAppeared, OnPortVanished, this, rpc_port_get_target_uid(), + &watch_handle_); + if (ret != AUL_R_OK) { + _E("aul_rpc_port_usr_add_watch() is failed. error(%d)", ret); + return -1; + } + + if (Aul::ExistPort(real_appid_, port_name_, rpc_port_get_target_uid())) { + OnPortAppeared(real_appid_.c_str(), port_name_.c_str(), -1, this); + } else { + OnPortVanished(real_appid_.c_str(), port_name_.c_str(), -1, this); + SetConnTimer(); + } + + return 0; +} + +void Proxy::Cancel() { + std::lock_guard lock(GetMutex()); + if (watch_handle_) { + aul_rpc_port_remove_watch(watch_handle_); + watch_handle_ = nullptr; + } +} + void Proxy::SetRealAppId(const std::string& alias_appid) { + std::lock_guard lock(GetMutex()); if (!real_appid_.empty()) return; @@ -269,70 +319,355 @@ void Proxy::SetRealAppId(const std::string& alias_appid) { _W("alias_appid(%s), real_appid(%s)", alias_appid.c_str(), appid); } +std::recursive_mutex& Proxy::GetMutex() const { + return mutex_; +} + +void Proxy::SetConnTimer() { + if (conn_timer_ == 0) + conn_timer_ = g_timeout_add_seconds(10, OnTimedOut, this); +} + +void Proxy::UnsetConnTimer() { + if (conn_timer_) { + g_source_remove(conn_timer_); + conn_timer_ = 0; + } +} + +void Proxy::OnPortAppeared(const char* app_id, const char* port_name, int pid, + void* user_data) { + _W("app_id(%s), port_name(%s), pid(%d)", app_id, port_name, pid); + auto* proxy = static_cast(user_data); + std::lock_guard lock(proxy->GetMutex()); + auto* listener = proxy->listener_; + if (listener == nullptr) { + _E("Invalid context"); + return; + } + + proxy->UnsetConnTimer(); + proxy->Cancel(); + + int ret = proxy->Connect(false); + if (ret != RPC_PORT_ERROR_NONE) { + proxy->listener_ = nullptr; + if (ret == RPC_PORT_ERROR_PERMISSION_DENIED) + listener->OnRejected(proxy->target_appid_, ret); + else + listener->OnDisconnected(proxy->target_appid_); + } +} + +void Proxy::OnPortVanished(const char* app_id, const char* port_name, int pid, + void* user_data) { + _W("app_id(%s), port_name(%s), pid(%d)", app_id, port_name, pid); +} + +gboolean Proxy::OnTimedOut(gpointer user_data) { + _E("Timed out"); + auto* proxy = static_cast(user_data); + std::lock_guard lock(proxy->GetMutex()); + auto* listener = proxy->listener_; + if (listener == nullptr) { + _E("Invalid context"); + return G_SOURCE_REMOVE; + } + + proxy->UnsetConnTimer(); + listener->OnRejected(proxy->target_appid_, RPC_PORT_ERROR_IO_ERROR); + return G_SOURCE_CONTINUE; +} + Proxy::ProxyPort::ProxyPort(Proxy* parent, int fd, const std::string& id, - bool receive) : Port(fd, id), parent_(parent) { + bool receive) + : Port(fd, id), parent_(parent) { Watch(receive); } Proxy::ProxyPort::~ProxyPort() { - if (disconn_src_ > 0) - g_source_remove(disconn_src_); + if (disconn_source_ > 0) + g_source_remove(disconn_source_); - if (src_ > 0) - g_source_remove(src_); + if (source_ > 0) + g_source_remove(source_); - if (gioc_ != nullptr) - g_io_channel_unref(gioc_); + if (channel_ != nullptr) + g_io_channel_unref(channel_); } int Proxy::ProxyPort::Watch(bool receive) { - char buf[1024]; - int fd = GetFd(); - - gioc_ = g_io_channel_unix_new(fd); - if (!gioc_) { - _E("Error is %s", strerror_r(errno, buf, sizeof(buf))); // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE - } - - disconn_src_ = g_io_add_watch(gioc_, - (GIOCondition)(G_IO_ERR | G_IO_HUP | G_IO_NVAL), - Proxy::OnSocketDisconnected, parent_); - if (disconn_src_ == 0) { - // LCOV_EXCL_START - _E("Failed to add watch on socket"); - g_io_channel_unref(gioc_); - gioc_ = nullptr; + channel_ = g_io_channel_unix_new(GetFd()); + if (channel_ == nullptr) { + _E("g_io_channel_unix_new() is failed"); + return -1; + } + + disconn_source_ = g_io_add_watch(channel_, + static_cast(G_IO_ERR | G_IO_HUP | G_IO_NVAL), + Proxy::ProxyPort::OnSocketDisconnected, parent_); + if (disconn_source_ == 0) { + _E("g_io_add_watch() is failed"); return -1; - // LCOV_EXCL_STOP } if (!receive) return 0; - src_ = g_io_add_watch(gioc_, - (GIOCondition)(G_IO_IN), - Proxy::OnDataReceived, parent_); - if (src_ == 0) { - // LCOV_EXCL_START - _E("Failed to add watch on socket"); - g_source_remove(disconn_src_); - disconn_src_ = 0; - g_io_channel_unref(gioc_); - gioc_ = nullptr; + source_ = g_io_add_watch(channel_, static_cast(G_IO_IN), + Proxy::ProxyPort::OnDataReceived, parent_); + if (source_ == 0) { + _E("g_io_add_watch() is failed"); return -1; - // LCOV_EXCL_STOP } return 0; } -void Proxy::ProxyPort::SetDisconnectedSource(int sourceId) { - disconn_src_ = sourceId; +void Proxy::ProxyPort::SetDisconnectedSource(guint source_id) { + disconn_source_ = source_id; +} + +void Proxy::ProxyPort::SetSource(guint source_id) { + source_ = source_id; +} + +gboolean Proxy::ProxyPort::OnSocketDisconnected(GIOChannel* channel, + GIOCondition cond, gpointer user_data) { + auto* proxy = static_cast(user_data); + std::lock_guard lock(proxy->GetMutex()); + auto* listener = proxy->listener_; + if (listener == nullptr) { + _E("Invalid context"); + return G_SOURCE_REMOVE; + } + + int fd = g_io_channel_unix_get_fd(channel); + _W("Socket was disconnected. fd(%d)", fd); + if (proxy->main_port_.get() != nullptr && + proxy->main_port_->GetFd() == fd) { + proxy->main_port_->SetDisconnectedSource(0); + } else if (proxy->delegate_port_.get() != nullptr && + proxy->delegate_port_->GetFd() == fd) { + proxy->delegate_port_->SetDisconnectedSource(0); + } + + proxy->main_port_.reset(); + proxy->delegate_port_.reset(); + proxy->listener_ = nullptr; + listener->OnDisconnected(proxy->target_appid_); + DebugPort::GetInst().RemoveSession(fd); + return G_SOURCE_REMOVE;; +} + +gboolean Proxy::ProxyPort::OnDataReceived(GIOChannel* channel, + GIOCondition cond, gpointer user_data) { + auto* proxy = static_cast(user_data); + std::lock_guard lock(proxy->GetMutex()); + auto* listener = proxy->listener_; + if (listener == nullptr) { + _E("Invalid context"); + return G_SOURCE_REMOVE; + } + + int fd = g_io_channel_unix_get_fd(channel); + if (proxy->delegate_port_->GetFd() == fd) { + char buffer[4]; + if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) { + _W("Socket was disconnected by stub. fd(%d)", fd); + proxy->listener_ = nullptr; + proxy->delegate_port_->SetSource(0); + if (proxy->main_port_.get() != nullptr) { + DebugPort::GetInst().RemoveSession(proxy->main_port_->GetFd()); + proxy->main_port_.reset(); + } + proxy->delegate_port_.reset(); + listener->OnDisconnected(proxy->target_appid_); + return G_SOURCE_REMOVE; + } + + listener->OnReceived(proxy->target_appid_); + } + + return G_SOURCE_CONTINUE; +} + +Proxy::Client::Client(Proxy* parent) : parent_(parent) { } -void Proxy::ProxyPort::SetSource(int sourceId) { - src_ = sourceId; +Proxy::Client::~Client() { + if (channel_) + g_io_channel_unref(channel_); + + if (disconn_source_ > 0) + g_source_remove(disconn_source_); + + if (source_ > 0) + g_source_remove(source_); +} + +Proxy::Client* Proxy::Client::Create(Proxy* parent, + const std::string& endpoint) { + std::unique_ptr client; + try { + client.reset(new (std::nothrow) Proxy::Client(parent)); + } catch (Exception& e) { + _E("Exception(%s) occurs", e.what()); + return nullptr; + } + + int ret; + int retry_count = 5; + do { + ret = client->Connect(endpoint); + if (ret == 0) { + break; + } else if (ret < 0) { + _D("Connect() is failed"); + usleep(100 * 1000); + retry_count--; + } + } while (retry_count > 0); + + if (ret != 0) { + _E("Connect() is failed"); + return nullptr; + } + + client->SetReceiveTimeout(5000); + _W("endpoint(%s), fd(%d)", endpoint.c_str(), client->GetFd()); + return client.release(); +} + +int Proxy::Client::Watch() { + channel_ = g_io_channel_unix_new(GetFd()); + if (channel_ == nullptr) { + _E("g_io_channel_unix_new() is failed"); + return -1; + } + + source_ = g_io_add_watch(channel_, static_cast(G_IO_IN), + Proxy::Client::OnResponseReceived, parent_); + if (source_ == 0) { + _E("g_io_add_watch() is failed"); + return -1; + } + + disconn_source_ = g_io_add_watch(channel_, + static_cast(G_IO_ERR | G_IO_HUP | G_IO_NVAL), + Proxy::Client::OnSocketDisconnected, parent_); + if (disconn_source_ == 0) { + _E("g_io_add_watch() is failed"); + return -1; + } + + return 0; +} + +void Proxy::Client::SetDisconnectedSource(guint source) { + disconn_source_ = source; +} + +void Proxy::Client::SetSource(guint source) { + source_ = source; +} + +gboolean Proxy::Client::OnSocketDisconnected(GIOChannel* channel, + GIOCondition cond, gpointer user_data) { + auto* proxy = static_cast(user_data); + std::lock_guard lock(proxy->GetMutex()); + auto* listener = proxy->listener_; + if (listener == nullptr) { + _E("Invalid context"); + return G_SOURCE_REMOVE; + } + + int fd = g_io_channel_unix_get_fd(channel); + _W("Socket was disconnected. fd(%d)", fd); + if (proxy->main_client_.get() != nullptr && + proxy->main_client_->GetFd() == fd) { + proxy->main_client_->SetDisconnectedSource(0); + } else if (proxy->delegate_client_.get() != nullptr && + proxy->delegate_client_->GetFd() == fd) { + proxy->delegate_client_->SetDisconnectedSource(0); + } + + proxy->main_client_.reset(); + proxy->delegate_client_.reset(); + proxy->listener_ = nullptr; + listener->OnDisconnected(proxy->target_appid_); + return G_SOURCE_REMOVE; +} + +gboolean Proxy::Client::OnResponseReceived(GIOChannel* channel, + GIOCondition cond, gpointer user_data) { + auto* proxy = static_cast(user_data); + std::lock_guard lock(proxy->GetMutex()); + auto* listener = proxy->listener_; + if (listener == nullptr) { + _E("Invalid context"); + return G_SOURCE_REMOVE; + } + + bool is_delegate = false; + std::unique_ptr client; + int fd = g_io_channel_unix_get_fd(channel); + if (proxy->main_client_.get() != nullptr && + proxy->main_client_->GetFd() == fd) { + client.reset(proxy->main_client_.release()); + } else if (proxy->delegate_client_.get() != nullptr && + proxy->delegate_client_->GetFd() == fd) { + client.reset(proxy->delegate_client_.release()); + is_delegate = true; + } + + if (client.get() == nullptr) { + _E("Unknown fd(%d)", fd); + return G_SOURCE_REMOVE; + } + + client->SetSource(0); + + Response* response = nullptr; + int ret = ReceiveResponse(client.get(), &response); + if (ret != 0) { + proxy->listener_ = nullptr; + proxy->main_client_.reset(); + proxy->delegate_client_.reset(); + listener->OnRejected(proxy->target_appid_, RPC_PORT_ERROR_IO_ERROR); + return G_SOURCE_REMOVE; + } + + std::unique_ptr response_auto(response); + if (response->GetResult() != 0) { + _E("Permission denied"); + proxy->listener_ = nullptr; + proxy->main_client_.reset(); + proxy->delegate_client_.reset(); + listener->OnRejected(proxy->target_appid_, + RPC_PORT_ERROR_PERMISSION_DENIED); + return G_SOURCE_REMOVE; + } + + client->SetNonblock(); + int client_fd = client->RemoveFd(); + if (is_delegate) { + proxy->fds_[1] = client_fd; + proxy->delegate_port_.reset( + new ProxyPort(proxy, proxy->fds_[1], proxy->target_appid_)); + listener->OnConnected(proxy->target_appid_, proxy->main_port_.get()); + DebugPort::GetInst().AddSession(proxy->port_name_, proxy->target_appid_, + proxy->fds_[0], proxy->fds_[1]); + _W("target_appid(%s), port_name(%s), main_fd(%d), delegate_fd(%d)", + proxy->target_appid_.c_str(), proxy->port_name_.c_str(), + proxy->fds_[0], proxy->fds_[1]); + } else { + proxy->fds_[0] = client_fd; + proxy->main_port_.reset( + new ProxyPort(proxy, proxy->fds_[0], proxy->target_appid_, false)); + } + + return G_SOURCE_REMOVE; } } // namespace internal diff --git a/src/proxy-internal.hh b/src/proxy-internal.hh index 64a824c..df0fbcb 100644 --- a/src/proxy-internal.hh +++ b/src/proxy-internal.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,25 +14,27 @@ * limitations under the License. */ -#ifndef PROXY_INTERNAL_H_ -#define PROXY_INTERNAL_H_ +#ifndef PROXY_INTERNAL_HH_ +#define PROXY_INTERNAL_HH_ +#include #include #include #include #include #include +#include -#include "fdbroker-internal.hh" +#include "client-socket-internal.hh" #include "port-internal.hh" namespace rpc_port { namespace internal { -class Proxy : public FdBroker::IEventWatcher { +class Proxy { public: - explicit Proxy(bool mock = false); + Proxy(); virtual ~Proxy(); class IEventListener { @@ -62,47 +64,82 @@ class Proxy : public FdBroker::IEventWatcher { private: class ProxyPort : public Port { public: - ProxyPort(Proxy* parent, int fd, const std::string& id, bool receive = true); + ProxyPort(Proxy* parent, int fd, const std::string& id, + bool receive = true); virtual ~ProxyPort(); - void SetDisconnectedSource(int sourceId); - void SetSource(int sourceId); + void SetDisconnectedSource(guint source_id); + void SetSource(guint source_id); private: int Watch(bool receive); + static gboolean OnSocketDisconnected(GIOChannel* channel, GIOCondition cond, + gpointer user_data); + static gboolean OnDataReceived(GIOChannel* channel, GIOCondition cond, + gpointer user_data); + private: - GIOChannel* gioc_ = nullptr; - int disconn_src_ = 0; - int src_ = 0; Proxy* parent_ = nullptr; + GIOChannel* channel_ = nullptr; + guint disconn_source_ = 0; + guint source_ = 0; + }; + + class Client : public ClientSocket { + public: + Client(Proxy* parent); + virtual ~Client(); + + static Client* Create(Proxy* parent, const std::string& endpoint); + + int Watch(); + void SetDisconnectedSource(guint source); + void SetSource(guint source); + + private: + static gboolean OnSocketDisconnected(GIOChannel* channel, GIOCondition cond, + gpointer user_data); + static gboolean OnResponseReceived(GIOChannel* channel, GIOCondition cond, + gpointer user_data); + + private: + Proxy* parent_; + GIOChannel* channel_ = nullptr; + guint disconn_source_ = 0; + guint source_ = 0; }; private: - static gboolean OnSocketDisconnected(GIOChannel* gio, GIOCondition cond, - gpointer data); - static gboolean OnDataReceived(GIOChannel* gio, GIOCondition cond, - gpointer data); - static gboolean DbusNameTimeout(gpointer user_data); - void OnPortAppeared() override; - void OnPortVanished() override; - void OnPortRejected(int error) override; - void OnPortConnected() override; - void OnPortDisconnected(bool cancel = false) override; + static void OnPortAppeared(const char* app_id, const char* port_name, int pid, + void* user_data); + static void OnPortVanished(const char* app_id, const char* port_name, int pid, + void* user_data); + static gboolean OnTimedOut(gpointer user_data); + void SetRealAppId(const std::string& alias_appid); + std::recursive_mutex& GetMutex() const; + int Connect(bool sync); + int Watch(); + void Cancel(); + void SetConnTimer(); + void UnsetConnTimer(); private: std::string port_name_; std::shared_ptr main_port_; std::shared_ptr delegate_port_; IEventListener* listener_ = nullptr; - std::shared_ptr fd_broker_; std::string target_appid_; std::string real_appid_; int fds_[2]; + std::unique_ptr main_client_; + std::unique_ptr delegate_client_; + aul_rpc_port_watch_h watch_handle_ = nullptr; guint conn_timer_ = 0; + mutable std::recursive_mutex mutex_; }; } // namespace internal } // namespace rpc_port -#endif // PROXY_INTERNAL_H_ +#endif // PROXY_INTERNAL_HH_ diff --git a/src/request-internal.cc b/src/request-internal.cc new file mode 100644 index 0000000..ef15ad5 --- /dev/null +++ b/src/request-internal.cc @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "request-internal.hh" + +namespace rpc_port { +namespace internal { + +Request::Request(std::string instance, std::string port_type) + : instance_(std::move(instance)), + port_type_(std::move(port_type)) { +} + +Request::Request() = default; + +Request::~Request() = default; + +void Request::SetPortType(std::string port_type) { + port_type_ = std::move(port_type); +} + +const std::string& Request::GetInstance() { + return instance_; +} + +const std::string& Request::GetPortType() { + return port_type_; +} + +void Request::WriteToParcel(tizen_base::Parcel* parcel) const { + parcel->WriteString(instance_); + parcel->WriteString(port_type_); +} + +void Request::ReadFromParcel(tizen_base::Parcel* parcel) { + instance_ = parcel->ReadString(); + port_type_ = parcel->ReadString(); +} + +} // namespace internal +} // namespace rpc_port diff --git a/src/request-internal.hh b/src/request-internal.hh new file mode 100644 index 0000000..bd72505 --- /dev/null +++ b/src/request-internal.hh @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 Samsung Electronics 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 REQUEST_INTERNAL_HH_ +#define REQUEST_INTERNAL_HH_ + +#include +#include + +#include + +namespace rpc_port { +namespace internal { + +class Request : public tizen_base::Parcelable { + public: + Request(std::string instance, std::string port_type); + Request(); + ~Request(); + + void SetPortType(std::string port_type); + const std::string& GetInstance(); + const std::string& GetPortType(); + + void WriteToParcel(tizen_base::Parcel* parcel) const override; + void ReadFromParcel(tizen_base::Parcel* parcel) override; + + private: + std::string instance_; + std::string port_type_; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // REQUEST_INTERNAL_HH_ diff --git a/src/response-internal.cc b/src/response-internal.cc new file mode 100644 index 0000000..3583dde --- /dev/null +++ b/src/response-internal.cc @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 Samsung Electronics 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 "response-internal.hh" + +namespace rpc_port { +namespace internal { + +Response::Response(int result) : result_(result) { +} + +Response::Response() : result_(0) { +} + +Response::~Response() = default; + +int Response::GetResult() { + return result_; +} + +void Response::WriteToParcel(tizen_base::Parcel* parcel) const { + parcel->WriteInt32(result_); +} + +void Response::ReadFromParcel(tizen_base::Parcel* parcel) { + parcel->ReadInt32(&result_); +} + +} // namespace internal +} // namespace rpc_port diff --git a/src/response-internal.hh b/src/response-internal.hh new file mode 100644 index 0000000..4855b81 --- /dev/null +++ b/src/response-internal.hh @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021 Samsung Electronics 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 RESPONSE_INTERNAL_HH_ +#define RESPONSE_INTERNAL_HH_ + +#include +#include + +namespace rpc_port { +namespace internal { + +class Response : public tizen_base::Parcelable { + public: + Response(int result); + Response(); + ~Response(); + + int GetResult(); + + void WriteToParcel(tizen_base::Parcel* parcel) const override; + void ReadFromParcel(tizen_base::Parcel* parcel) override; + + private: + int result_; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // RESPONSE_INTERNAL_HH_ diff --git a/src/rpc-port-internal.cc b/src/rpc-port-internal.cc new file mode 100644 index 0000000..a8c5569 --- /dev/null +++ b/src/rpc-port-internal.cc @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 +#include + +#include + +#include "include/rpc-port-internal.h" +#include "include/rpc-port.h" + +#undef RPC_API +#define RPC_API extern "C" __attribute__((visibility("default"))) + +namespace { + +constexpr uid_t kRegularUidMin = 5000; +std::atomic __target_uid { getuid() }; + +} // namespace + +RPC_API void rpc_port_set_target_uid(uid_t target_uid) { + __target_uid.exchange(target_uid); +} + +RPC_API uid_t rpc_port_get_target_uid(void) { + if (__target_uid < kRegularUidMin) + __target_uid.exchange(tzplatform_getuid(TZ_SYS_DEFAULT_USER)); + + return __target_uid; +} diff --git a/src/rpc-port-parcel.cc b/src/rpc-port-parcel.cc index 625bbd9..424d781 100644 --- a/src/rpc-port-parcel.cc +++ b/src/rpc-port-parcel.cc @@ -1,14 +1,14 @@ /* - * Copyright (c) 2018 - 2020 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2018 - 2021 Samsung Electronics Co., Ltd All Rights Reserved * - * Licensed under the Apache License, Version 2.0 (the License); + * 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, + * 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. @@ -20,9 +20,9 @@ #include +#include "include/rpc-port-parcel.h" #include "log-private.hh" #include "port-internal.hh" -#include "rpc-port-parcel.h" #define MAX_PARCEL_SIZE (1024 * 1024 * 10) diff --git a/src/rpc-port.cc b/src/rpc-port.cc index 04e20c8..ca708d8 100644 --- a/src/rpc-port.cc +++ b/src/rpc-port.cc @@ -1,29 +1,32 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd All Rights Reserved * - * Licensed under the Apache License, Version 2.0 (the License); + * 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, + * 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 #include #include #include #include +#include "include/rpc-port-internal.h" +#include "include/rpc-port.h" #include "log-private.hh" #include "port-internal.hh" #include "proxy-internal.hh" -#include "rpc-port.h" #include "stub-internal.hh" #undef RPC_API @@ -44,7 +47,7 @@ class Event { class ProxyExt : public Proxy, public Proxy::IEventListener { public: - explicit ProxyExt(bool mock = false) : Proxy(mock), destroying_(false) {} + explicit ProxyExt() : Proxy(), destroying_(false) {} virtual ~ProxyExt() = default; void AddConnectedEventListener(rpc_port_proxy_connected_event_cb cb, @@ -136,8 +139,7 @@ class ProxyExt : public Proxy, public Proxy::IEventListener { class StubExt : public Stub, public Stub::IEventListener { public: - explicit StubExt(const std::string& port, bool mock = false) - : Stub(port, mock) {} + explicit StubExt(const std::string& port) : Stub(port) {} virtual ~StubExt() = default; void AddConnectedEventListener(rpc_port_stub_connected_event_cb cb, @@ -254,15 +256,6 @@ RPC_API int rpc_port_proxy_create(rpc_port_proxy_h* h) { return RPC_PORT_ERROR_NONE; } -// LCOV_EXCL_START -RPC_API int rpc_port_proxy_create_mockup(rpc_port_proxy_h* h) { - auto p = new ::ProxyExt(true); - - *h = p; - return 0; -} -// LCOV_EXL_STOP - RPC_API int rpc_port_proxy_destroy(rpc_port_proxy_h h) { if (h == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; @@ -393,25 +386,13 @@ RPC_API int rpc_port_stub_create(rpc_port_stub_h* h, const char* port_name) { return RPC_PORT_ERROR_NONE; } -// LCOV_EXCL_START -RPC_API int rpc_port_stub_create_mockup(rpc_port_stub_h* h, - const char* port_name) { - if (h == nullptr || port_name == nullptr) - return -1; - - auto p = new ::StubExt(port_name, true); - - *h = p; - return 0; -} -//LCOV_EXCL_STOP - RPC_API int rpc_port_stub_destroy(rpc_port_stub_h h) { if (h == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; _W("rpc_port_stub_destroy(%p)", h); auto p = static_cast<::StubExt*>(h); + aul_rpc_port_usr_destroy(p->GetPortName().c_str(), rpc_port_get_target_uid()); delete p; return RPC_PORT_ERROR_NONE; } @@ -424,7 +405,15 @@ RPC_API int rpc_port_stub_listen(rpc_port_stub_h h) { auto p = static_cast<::StubExt*>(h); std::lock_guard lock(p->GetMutex()); - return p->Listen(p); + int fd = -1; + int ret = aul_rpc_port_usr_create(p->GetPortName().c_str(), + rpc_port_get_target_uid(), &fd); + if (ret != AUL_R_OK) { + _E("aul_rpc_port_usr_create() is failed. error(%d)", ret); + return RPC_PORT_ERROR_IO_ERROR; + } + + return p->Listen(p, fd); } RPC_API int rpc_port_stub_add_privilege(rpc_port_stub_h h, diff --git a/src/server-socket-internal.cc b/src/server-socket-internal.cc new file mode 100644 index 0000000..228e75b --- /dev/null +++ b/src/server-socket-internal.cc @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2021 Samsung Electronics 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 +#include +#include +#include +#include +#include + +#include "log-private.hh" +#include "server-socket-internal.hh" + +namespace rpc_port { +namespace internal { + +ServerSocket::ServerSocket(int fd) : fd_(fd) { +} + +ServerSocket::~ServerSocket() { + if (!IsClosed()) + Close(); +} + +bool ServerSocket::IsClosed() { + return fd_ < 0 ? true : false; +} + +ClientSocket* ServerSocket::Accept() { + struct sockaddr_un addr = { 0, }; + socklen_t len = sizeof(struct sockaddr_un); + auto* addr_ptr = reinterpret_cast(&addr); + int client_fd = accept(GetFd(), addr_ptr, &len); + if (client_fd == -1) { + _E("accept() is failed. errno(%d)", errno); + return nullptr; + } + + return new (std::nothrow) ClientSocket(client_fd); +} + +int ServerSocket::GetFd() const { + return fd_; +} + +int ServerSocket::Listen(int backlog) { + int ret = listen(GetFd(), backlog); + if (ret < 0) { + _E("listen() is failed. errno(%d)", errno); + return -1; + } + + return 0; +} + +void ServerSocket::Close() { + if (fd_ > -1) { + close(fd_); + fd_ = -1; + } +} + +} // namespace internal +} // namespace rpc_port diff --git a/src/server-socket-internal.hh b/src/server-socket-internal.hh new file mode 100644 index 0000000..ae025ac --- /dev/null +++ b/src/server-socket-internal.hh @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 Samsung Electronics 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 SERVER_SOCKET_INTERNAL_HH_ +#define SERVER_SOCKET_INTERNAL_HH_ + +#include "client-socket-internal.hh" + +namespace rpc_port { +namespace internal { + +class ServerSocket { + public: + ServerSocket(int fd); + virtual ~ServerSocket(); + + bool IsClosed(); + ClientSocket* Accept(); + int GetFd() const; + int Listen(int backlog); + void Close(); + + private: + int fd_; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // SERVER_SOCKET_INTERNAL_HH_ diff --git a/src/shared-queue-internal.hh b/src/shared-queue-internal.hh index 2ea1a87..4cd0d95 100644 --- a/src/shared-queue-internal.hh +++ b/src/shared-queue-internal.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 - 2021 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/stub-internal.cc b/src/stub-internal.cc index df41588..8a038c4 100644 --- a/src/stub-internal.cc +++ b/src/stub-internal.cc @@ -1,60 +1,128 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd All Rights Reserved * - * Licensed under the Apache License, Version 2.0 (the License); + * 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, + * 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 -#include #include #include +#include +#include +#include +#include "aul-internal.hh" #include "debug-port-internal.hh" +#include "include/rpc-port.h" #include "log-private.hh" +#include "peer-cred-internal.hh" +#include "request-internal.hh" +#include "response-internal.hh" #include "stub-internal.hh" namespace rpc_port { namespace internal { +namespace { + +constexpr const char kPortTypeMain[] = "main"; +constexpr const char kPortTypeDelegate[] = "delegate"; +constexpr uid_t kRegularUidMin = 5000; + +int ReceiveRequest(ClientSocket* client, Request** request) { + size_t size = 0; + int ret = client->Receive(reinterpret_cast(&size), sizeof(size)); + if (ret != 0) { + _E("Receive() is failed. error(%d)", ret); + return -1; + } + + std::vector buf(size); + ret = client->Receive(buf.data(), size); + if (ret != 0) { + _E("Receive() is failed. error(%d)", ret); + return -1; + } + + tizen_base::Parcel parcel(buf.data(), buf.size()); + *request = new (std::nothrow) Request(); + if (*request == nullptr) { + _E("Out of memory"); + return -1; + } + + parcel.ReadParcelable(*request); + return 0; +} + +int SendResponse(ClientSocket* client, const Response& response) { + tizen_base::Parcel parcel; + parcel.WriteParcelable(const_cast(response)); + const std::vector& raw = parcel.GetRaw(); + size_t size = raw.size(); + int ret = client->Send(reinterpret_cast(&size), sizeof(size)); + if (ret != 0) { + _E("Send() is failed. error(%d)", ret); + return -1; + } + + ret = client->Send(raw.data(), raw.size()); + if (ret != 0) { + _E("Send() is failed. error(%d)", ret); + return -1; + } -Stub::Stub(const std::string& port_name, bool mock) - : fd_broker_(new FdBroker(mock)), - port_name_(port_name) { + return 0; +} + +} // namespace + +Stub::Stub(std::string port_name) : port_name_(std::move(port_name)) { + _D("Stub::Stub()"); } Stub::~Stub() { + std::lock_guard lock(GetMutex()); _D("Stub::~Stub"); + listener_ = nullptr; + server_.reset(); } -int Stub::Listen(IEventListener* ev) { +int Stub::Listen(IEventListener* ev, int fd) { if (ev == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; + if (listener_ != nullptr) { + _E("Already listening!"); + return RPC_PORT_ERROR_INVALID_PARAMETER; + } + + std::lock_guard lock(GetMutex()); listener_ = ev; - return fd_broker_->Listen(this, port_name_); + server_.reset(new Server(fd, this)); + return server_->Listen(); } void Stub::AddPrivilege(const std::string& privilege) { - AccessController& ac = fd_broker_->GetAccessController(); - ac.AddPrivilege(privilege); + std::lock_guard lock(GetMutex()); + access_controller_.AddPrivilege(privilege); } void Stub::SetTrusted(const bool trusted) { - AccessController& ac = fd_broker_->GetAccessController(); - ac.SetTrusted(trusted); + std::lock_guard lock(GetMutex()); + access_controller_.SetTrusted(trusted); } std::shared_ptr Stub::FindPort(const std::string& instance) const { + std::lock_guard lock(GetMutex()); for (auto& p : ports_) { if (p->GetInstance() == instance && !p->IsDelegate()) { return p; @@ -66,16 +134,22 @@ std::shared_ptr Stub::FindPort(const std::string& instance) const { std::shared_ptr Stub::FindDelegatePort( const std::string& instance) const { + std::lock_guard lock(GetMutex()); for (auto& p : ports_) { if (p->GetInstance() == instance && p->IsDelegate()) { return p; } } - return {}; // LCOV_EXCL_LINE + return {}; +} + +const std::string& Stub::GetPortName() const { + return port_name_; } void Stub::RemoveAcceptedPorts(std::string instance) { + std::lock_guard lock(GetMutex()); auto iter = ports_.begin(); while (iter != ports_.end()) { if ((*iter)->GetInstance().compare(instance) == 0) { @@ -88,78 +162,101 @@ void Stub::RemoveAcceptedPorts(std::string instance) { } } -gboolean Stub::OnDataReceived(GIOChannel* gio, GIOCondition cond, - gpointer data) { - Stub* stub = static_cast(data); - int fd = g_io_channel_unix_get_fd(gio); - char buffer[4]; +gboolean Stub::OnDataReceived(GIOChannel* channel, GIOCondition cond, + gpointer user_data) { + Stub* stub = static_cast(user_data); + std::lock_guard lock(stub->GetMutex()); + auto* listener = stub->listener_; + if (listener == nullptr) { + _E("Invalid context"); + return G_SOURCE_REMOVE; + } + int fd = g_io_channel_unix_get_fd(channel); for (auto& p : stub->ports_) { if (p->GetFd() == fd && !p->IsDelegate()) { + char buffer[4]; if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) { _W("Socket was disconnected from proxy. fd(%d)", fd); - stub->listener_->OnDisconnected(p->GetId(), p->GetInstance()); + listener->OnDisconnected(p->GetId(), p->GetInstance()); stub->RemoveAcceptedPorts(p->GetInstance()); - - if (aul_rpc_port_notify_rpc_finished() != AUL_R_OK) - _W("Failed to notify rpc finished"); // LCOV_EXCL_LINE - - return FALSE; + Aul::NotifyRpcFinished(); + return G_SOURCE_REMOVE; } int ret = stub->listener_->OnReceived(p->GetId(), p->GetInstance(), - p.get()); - + p.get()); if (ret != 0) { _W("Invalid protocol"); - stub->listener_->OnDisconnected(p->GetId(), p->GetInstance()); + listener->OnDisconnected(p->GetId(), p->GetInstance()); stub->RemoveAcceptedPorts(p->GetInstance()); - - if (aul_rpc_port_notify_rpc_finished() != AUL_R_OK) - _W("Failed to notify rpc finished"); // LCOV_EXCL_LINE - - return FALSE; + Aul::NotifyRpcFinished(); + return G_SOURCE_REMOVE; } break; } } - return TRUE; + return G_SOURCE_CONTINUE; } -gboolean Stub::OnSocketDisconnected(GIOChannel* gio, GIOCondition cond, - gpointer data) { - Stub* stub = static_cast(data); - int fd = g_io_channel_unix_get_fd(gio); +gboolean Stub::OnSocketDisconnected(GIOChannel* channel, GIOCondition cond, + gpointer user_data) { + auto* stub = static_cast(user_data); + std::lock_guard lock(stub->GetMutex()); + auto* listener = stub->listener_; + if (listener == nullptr) { + _E("Invalid context"); + return G_SOURCE_REMOVE; + } + int fd = g_io_channel_unix_get_fd(channel); _W("Socket was disconnected. fd(%d)", fd); for (auto& p : stub->ports_) { if (p->GetFd() == fd) { - stub->listener_->OnDisconnected(p->GetId(), p->GetInstance()); - if (aul_rpc_port_notify_rpc_finished() != AUL_R_OK) - _W("Failed to notify rpc finished"); // LCOV_EXCL_LINE + listener->OnDisconnected(p->GetId(), p->GetInstance()); stub->RemoveAcceptedPorts(p->GetInstance()); + Aul::NotifyRpcFinished(); break; } } - return FALSE; + return G_SOURCE_REMOVE;; } -void Stub::OnFdReceived(const std::string& sender, int fds[2]) { - _W("[__OnFdReceived__] fds[0]: %d, fds[1]: %d", fds[0], fds[1]); - auto* main_port = new AcceptedPort(this, false, fds[0], sender, true); - ports_.emplace_back(main_port); - ports_.emplace_back(new AcceptedPort(this, true, fds[1], sender, - main_port->GetInstance(), false)); +void Stub::AddAcceptedPort(const std::string& sender_appid, + const std::string& instance, const std::string& port_type, int fd) { + std::lock_guard lock(GetMutex()); + if (port_type == kPortTypeMain) { + auto* main_port = new AcceptedPort(this, false, fd, sender_appid, + instance, true); + ports_.emplace_back(main_port); + return; + } + + auto* delegate_port = new AcceptedPort(this, true, fd, sender_appid, + instance, false); + ports_.emplace_back(delegate_port); + + int main_fd = -1; for (auto& p : ports_) { - if (p->GetFd() == fds[0]) { - listener_->OnConnected(p->GetId(), p->GetInstance()); + if (p->GetId() == delegate_port->GetId() && + p->GetInstance() == delegate_port->GetInstance() && + p->GetFd() != delegate_port->GetFd()) { + main_fd = p->GetFd(); break; } } - DebugPort::GetInst().AddSession(port_name_, sender, fds[0], fds[1]); + + _W("sender_appid(%s), instance(%s), main_fd(%d), delegate_fd(%d)", + sender_appid.c_str(), instance.c_str(), main_fd, fd); + listener_->OnConnected(sender_appid, instance); + DebugPort::GetInst().AddSession(port_name_, sender_appid, main_fd, fd); +} + +std::recursive_mutex& Stub::GetMutex() const { + return mutex_; } Stub::AcceptedPort::AcceptedPort(Stub* parent, bool isDelegate, int fd, @@ -183,53 +280,126 @@ Stub::AcceptedPort::~AcceptedPort() { if (src_ > 0) g_source_remove(src_); - if (gioc_ != nullptr) - g_io_channel_unref(gioc_); + if (channel_ != nullptr) + g_io_channel_unref(channel_); } int Stub::AcceptedPort::Watch(bool receive) { - char buf[1024]; - int fd = GetFd(); - - gioc_ = g_io_channel_unix_new(fd); - if (!gioc_) { - // LCOV_EXCL_START - _E("Error is %s", strerror_r(errno, buf, sizeof(buf))); + channel_ = g_io_channel_unix_new(GetFd()); + if (channel_ == nullptr) { + _E("g_io_channel_unix_new() is failed"); return -1; - // LCOV_EXCL_STOP } - disconn_src_ = g_io_add_watch(gioc_, - (GIOCondition)(G_IO_ERR | G_IO_HUP | G_IO_NVAL), - Stub::OnSocketDisconnected, parent_); + disconn_src_ = g_io_add_watch(channel_, + static_cast(G_IO_ERR | G_IO_HUP | G_IO_NVAL), + Stub::OnSocketDisconnected, parent_); if (disconn_src_ == 0) { - // LCOV_EXCL_START - _E("fail to add watch on socket"); - g_io_channel_unref(gioc_); - gioc_ = nullptr; + _E("g_io_add_watch() is failed"); return -1; - // LCOV_EXCL_STOP } if (!receive) return 0; - src_ = g_io_add_watch(gioc_, - (GIOCondition)(G_IO_IN), - Stub::OnDataReceived, parent_); + src_ = g_io_add_watch(channel_, static_cast(G_IO_IN), + Stub::OnDataReceived, parent_); if (src_ == 0) { - // LCOV_EXCL_START - _E("fail to add watch on socket"); - g_source_remove(disconn_src_); - disconn_src_ = 0; - g_io_channel_unref(gioc_); - gioc_ = nullptr; + _E("g_io_add_watch() is failed"); + return -1; + } + + return 0; +} + +Stub::Server::Server(int fd, Stub* parent) + : ServerSocket(fd), + parent_(parent) { +} + +Stub::Server::~Server() { + if (channel_) + g_io_channel_unref(channel_); + + if (source_ > 0) + g_source_remove(source_); +} + +int Stub::Server::Listen() { + channel_ = g_io_channel_unix_new(GetFd()); + if (channel_ == nullptr) { + _E("g_io_channel_unix_new() is failed"); + return -1; + } + + source_ = g_io_add_watch(channel_, static_cast(G_IO_IN), + OnRequestReceived, parent_); + if (source_ == 0) { + _E("g_io_add_watch() is failed"); return -1; - // LCOV_EXCL_STOP } return 0; } +gboolean Stub::Server::OnRequestReceived(GIOChannel* channel, GIOCondition cond, + gpointer user_data) { + Stub* stub = static_cast(user_data); + std::lock_guard lock(stub->GetMutex()); + if (stub->server_.get() == nullptr) { + _E("Invalid context"); + return G_SOURCE_REMOVE; + } + + std::unique_ptr client(stub->server_->Accept()); + if (client.get() == nullptr) { + _E("Out of memory"); + return G_SOURCE_CONTINUE; + } + + Request* request = nullptr; + int ret = ReceiveRequest(client.get(), &request); + if (ret != 0) + return G_SOURCE_CONTINUE; + + std::unique_ptr request_auto(request); + std::unique_ptr cred(PeerCred::Get(client->GetFd())); + if (cred.get() == nullptr) { + _E("Failed to create peer credentials"); + return G_SOURCE_CONTINUE; + } + + std::string app_id = Aul::GetAppId(cred->GetPid()); + int res; + if (cred->GetUid() >= kRegularUidMin) { + if (cred->GetUid() != getuid() && getuid() >= kRegularUidMin) { + _E("Reject request. %u:%u", cred->GetUid(), getuid()); + res = -1; + } else { + res = stub->access_controller_.Check(client->GetFd(), app_id); + } + } else { + _W("Bypass access control. pid(%d), uid(%u)", + cred->GetPid(), cred->GetUid()); + res = 0; + } + + Response response(res); + ret = SendResponse(client.get(), response); + if (ret != 0) + return G_SOURCE_CONTINUE; + + if (res != 0) { + _E("Access denied. fd(%d), pid(%d)", client->GetFd(), cred->GetPid()); + return G_SOURCE_CONTINUE; + } + + client->SetNonblock(); + int client_fd = client->RemoveFd(); + stub->AddAcceptedPort(app_id, request->GetInstance(), request->GetPortType(), + client_fd); + return G_SOURCE_CONTINUE; +} + } // namespace internal } // namespace rpc_port diff --git a/src/stub-internal.hh b/src/stub-internal.hh index bc562df..28114cc 100644 --- a/src/stub-internal.hh +++ b/src/stub-internal.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,44 +14,47 @@ * limitations under the License. */ -#ifndef STUB_INTERNAL_H_ -#define STUB_INTERNAL_H_ +#ifndef STUB_INTERNAL_HH_ +#define STUB_INTERNAL_HH_ #include #include #include -#include #include #include +#include +#include +#include "ac-internal.hh" #include "debug-port-internal.hh" -#include "fdbroker-internal.hh" #include "port-internal.hh" +#include "server-socket-internal.hh" namespace rpc_port { namespace internal { -class Stub : private FdBroker::IEventListener { +class Stub { public: class IEventListener { public: virtual void OnConnected(const std::string& sender, - const std::string& instance) = 0; + const std::string& instance) = 0; virtual void OnDisconnected(const std::string& sender, - const std::string& instance) = 0; + const std::string& instance) = 0; virtual int OnReceived(const std::string& sender, - const std::string& instance, Port* port) = 0; + const std::string& instance, Port* port) = 0; }; - explicit Stub(const std::string& port_name, bool mock = false); + explicit Stub(std::string port_name); virtual ~Stub(); - int Listen(IEventListener* ev); + int Listen(IEventListener* ev, int fd); void AddPrivilege(const std::string& privilege); void SetTrusted(const bool trusted); std::shared_ptr FindPort(const std::string& instance) const; std::shared_ptr FindDelegatePort(const std::string& instance) const; + const std::string& GetPortName() const; private: class AcceptedPort : public Port { @@ -69,29 +72,49 @@ class Stub : private FdBroker::IEventListener { int Watch(bool receive); private: - GIOChannel* gioc_ = nullptr; + GIOChannel* channel_ = nullptr; int disconn_src_ = 0; int src_ = 0; Stub* parent_; bool is_delegate_ = false; }; - static gboolean OnDataReceived(GIOChannel* gio, GIOCondition cond, - gpointer data); - static gboolean OnSocketDisconnected(GIOChannel* gio, GIOCondition cond, - gpointer data); + class Server : public ServerSocket { + public: + Server(int fd, Stub* parent); + virtual ~Server(); + + int Listen(); + + private: + static gboolean OnRequestReceived(GIOChannel* channel, GIOCondition cond, + gpointer user_data); + + private: + Stub* parent_; + GIOChannel* channel_ = nullptr; + guint source_ = 0;; + }; - void OnFdReceived(const std::string& sender, int fds[2]) override; + static gboolean OnDataReceived(GIOChannel* channel, GIOCondition cond, + gpointer user_data); + static gboolean OnSocketDisconnected(GIOChannel* channel, GIOCondition cond, + gpointer user_data); + void AddAcceptedPort(const std::string& sender_appid, + const std::string& instance, const std::string& port_type, int fd); void RemoveAcceptedPorts(std::string instance); + std::recursive_mutex& GetMutex() const; private: + AccessController access_controller_; + std::string port_name_; std::list> ports_; IEventListener* listener_ = nullptr; - std::shared_ptr fd_broker_; - std::string port_name_; + std::unique_ptr server_; + mutable std::recursive_mutex mutex_; }; } // namespace internal } // namespace rpc_port -#endif // STUB_INTERNAL_H_ +#endif // STUB_INTERNAL_HH_ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..c90fac8 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1 @@ +ADD_SUBDIRECTORY(unit_tests) diff --git a/test/unit_tests/CMakeLists.txt b/test/unit_tests/CMakeLists.txt new file mode 100644 index 0000000..a476e73 --- /dev/null +++ b/test/unit_tests/CMakeLists.txt @@ -0,0 +1,27 @@ +AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} UNIT_TEST_SRCS) +AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/mock MOCK_SRCS) + +ADD_EXECUTABLE(${TARGET_RPC_PORT_UNITTESTS} + ${UNIT_TEST_SRCS} + ${MOCK_SRCS}) + +TARGET_INCLUDE_DIRECTORIES(${TARGET_RPC_PORT_UNITTESTS} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/mock + ${CMAKE_CURRENT_SOURCE_DIR}/../ + ${CMAKE_CURRENT_SOURCE_DIR}/../../ + ${CMAKE_CURRENT_SOURCE_DIR}/../../include) + +APPLY_PKG_CONFIG(${TARGET_RPC_PORT_UNITTESTS} PUBLIC + AUL_DEPS + GLIB_DEPS + GMOCK_DEPS +) + +TARGET_LINK_LIBRARIES(${TARGET_RPC_PORT_UNITTESTS} PUBLIC ${TARGET_RPC_PORT}) +SET_TARGET_PROPERTIES(${TARGET_RPC_PORT_UNITTESTS} PROPERTIES + COMPILE_FLAGS "-fPIE") +SET_TARGET_PROPERTIES(${TARGET_RPC_PORT_UNITTESTS} PROPERTIES + LINK_FLAGS "-pie") + +INSTALL(TARGETS ${TARGET_RPC_PORT_UNITTESTS} DESTINATION bin) diff --git a/unit_tests/src/main.cc b/test/unit_tests/main.cc similarity index 100% rename from unit_tests/src/main.cc rename to test/unit_tests/main.cc diff --git a/test/unit_tests/mock/aul_mock.cc b/test/unit_tests/mock/aul_mock.cc new file mode 100644 index 0000000..2fce77b --- /dev/null +++ b/test/unit_tests/mock/aul_mock.cc @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2021 Samsung Electronics 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 "mock/aul_mock.hh" +#include "mock/mock_hook.hh" +#include "mock/test_fixture.hh" + +extern "C" int aul_app_get_appid_bypid(int pid, char* appid, int len) { + return MOCK_HOOK_P3(AulMock, aul_app_get_appid_bypid, pid, appid, len); +} + +extern "C" int aul_rpc_port_usr_get_path(const char* app_id, + const char* port_name, uid_t uid, char** port_path) { + return MOCK_HOOK_P4(AulMock, aul_rpc_port_usr_get_path, app_id, port_name, + uid, port_path); +} + +extern "C" int aul_rpc_port_usr_prepare_stub(const char* app_id, + const char* port_name, uid_t uid) { + return MOCK_HOOK_P3(AulMock, aul_rpc_port_usr_prepare_stub, app_id, port_name, + uid); +} + +extern "C" int aul_rpc_port_usr_exist(const char* app_id, const char* port_name, + uid_t uid, bool* exist) { + return MOCK_HOOK_P4(AulMock, aul_rpc_port_usr_exist, app_id, port_name, uid, + exist); +} + +extern "C" int aul_rpc_port_notify_rpc_finished() { + return MOCK_HOOK_P0(AulMock, aul_rpc_port_notify_rpc_finished); +} + +extern "C" int aul_rpc_port_set_private_sharing(const char* app_id, + const char** paths, unsigned int size) { + return MOCK_HOOK_P3(AulMock, aul_rpc_port_set_private_sharing, app_id, paths, + size); +} + +extern "C" int aul_rpc_port_unset_private_sharing(const char* app_id) { + return MOCK_HOOK_P1(AulMock, aul_rpc_port_unset_private_sharing, app_id); +} + +extern "C" int aul_rpc_port_usr_add_watch(const char* app_id, + const char* port_name, aul_rpc_port_appeared_cb appeared_cb, + aul_rpc_port_vanished_cb vanished_cb, void* user_data, uid_t uid, + aul_rpc_port_watch_h* handle) { + return MOCK_HOOK_P7(AulMock, aul_rpc_port_usr_add_watch, app_id, port_name, + appeared_cb, vanished_cb, user_data, uid, handle); +} + +extern "C" int aul_rpc_port_remove_watch(aul_rpc_port_watch_h handle) { + return MOCK_HOOK_P1(AulMock, aul_rpc_port_remove_watch, handle); +} + +extern "C" int aul_svc_get_appid_by_alias_appid(const char* alias_appid, + char** app_id) { + return MOCK_HOOK_P2(AulMock, aul_svc_get_appid_by_alias_appid, alias_appid, + app_id); +} + +extern "C" int aul_rpc_port_usr_create(const char* port_name, uid_t uid, + int* fd) { + return MOCK_HOOK_P3(AulMock, aul_rpc_port_usr_create, port_name, uid, fd); +} + +extern "C" int aul_rpc_port_usr_destroy(const char* port_name, uid_t uid) { + return MOCK_HOOK_P2(AulMock, aul_rpc_port_usr_destroy, port_name, uid); +} diff --git a/test/unit_tests/mock/aul_mock.hh b/test/unit_tests/mock/aul_mock.hh new file mode 100644 index 0000000..33a26b4 --- /dev/null +++ b/test/unit_tests/mock/aul_mock.hh @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2021 Samsung Electronics 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 UNIT_TESTS_MOCK_AUL_MOCK_HH_ +#define UNIT_TESTS_MOCK_AUL_MOCK_HH_ + +#include +#include +#include +#include +#include +#include + +#include "mock/module_mock.hh" + +class AulMock : public virtual ModuleMock { + public: + virtual ~AulMock() {} + + MOCK_METHOD3(aul_app_get_appid_bypid, + int (int, char*, int)); + MOCK_METHOD4(aul_rpc_port_usr_get_path, + int (const char*, const char*, uid_t, char**)); + MOCK_METHOD3(aul_rpc_port_usr_prepare_stub, + int (const char*, const char*, uid_t)); + MOCK_METHOD4(aul_rpc_port_usr_exist, + int (const char*, const char*, uid_t, bool*)); + MOCK_METHOD0(aul_rpc_port_notify_rpc_finished, + int ()); + MOCK_METHOD3(aul_rpc_port_set_private_sharing, + int (const char*, const char**, unsigned int)); + MOCK_METHOD1(aul_rpc_port_unset_private_sharing, + int (const char*)); + MOCK_METHOD7(aul_rpc_port_usr_add_watch, + int (const char*, const char*, aul_rpc_port_appeared_cb, + aul_rpc_port_vanished_cb, void*, uid_t, aul_rpc_port_watch_h*)); + MOCK_METHOD1(aul_rpc_port_remove_watch, + int (aul_rpc_port_watch_h)); + MOCK_METHOD2(aul_svc_get_appid_by_alias_appid, + int (const char*, char**)); + MOCK_METHOD3(aul_rpc_port_usr_create, + int (const char*, uid_t, int*)); + MOCK_METHOD2(aul_rpc_port_usr_destroy, + int (const char*, uid_t)); +}; + +#endif // UNIT_TESTS_MOCK_AUL_MOCK_HH_ diff --git a/test/unit_tests/mock/mock_hook.hh b/test/unit_tests/mock/mock_hook.hh new file mode 100644 index 0000000..2980460 --- /dev/null +++ b/test/unit_tests/mock/mock_hook.hh @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 Samsung Electronics 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 UNIT_TESTS_MOCK_MOCK_HOOK_HH_ +#define UNIT_TESTS_MOCK_MOCK_HOOK_HH_ + +#define MOCK_HOOK_P0(MOCK_CLASS, f) \ + TestFixture::GetMock().f() +#define MOCK_HOOK_P1(MOCK_CLASS, f, p1) \ + TestFixture::GetMock().f(p1) +#define MOCK_HOOK_P2(MOCK_CLASS, f, p1, p2) \ + TestFixture::GetMock().f(p1, p2) +#define MOCK_HOOK_P3(MOCK_CLASS, f, p1, p2, p3) \ + TestFixture::GetMock().f(p1, p2, p3) +#define MOCK_HOOK_P4(MOCK_CLASS, f, p1, p2, p3, p4) \ + TestFixture::GetMock().f(p1, p2, p3, p4) +#define MOCK_HOOK_P5(MOCK_CLASS, f, p1, p2, p3, p4, p5) \ + TestFixture::GetMock().f(p1, p2, p3, p4, p5) +#define MOCK_HOOK_P6(MOCK_CLASS, f, p1, p2, p3, p4, p5, p6) \ + TestFixture::GetMock().f(p1, p2, p3, p4, p5, p6) +#define MOCK_HOOK_P7(MOCK_CLASS, f, p1, p2, p3, p4, p5, p6, p7) \ + TestFixture::GetMock().f(p1, p2, p3, p4, p5, p6, p7) +#define MOCK_HOOK_P8(MOCK_CLASS, f, p1, p2, p3, p4, p5, p6, p7, p8) \ + TestFixture::GetMock().f(p1, p2, p3, p4, p5, p6, p7, p8) +#define MOCK_HOOK_P10(MOCK_CLASS, f, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) \ + TestFixture::GetMock().f( \ + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) + +#endif // UNIT_TESTS_MOCK_MOCK_HOOK_HH_ diff --git a/test/unit_tests/mock/module_mock.hh b/test/unit_tests/mock/module_mock.hh new file mode 100644 index 0000000..a79584e --- /dev/null +++ b/test/unit_tests/mock/module_mock.hh @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2021 Samsung Electronics 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 UNIT_TESTS_MOCK_MODULE_MOCK_HH_ +#define UNIT_TESTS_MOCK_MODULE_MOCK_HH_ + +class ModuleMock { + public: + virtual ~ModuleMock() {} +}; + +#endif // UNIT_TESTS_MOCK_MODULE_MOCK_HH_ diff --git a/test/unit_tests/mock/test_fixture.cc b/test/unit_tests/mock/test_fixture.cc new file mode 100644 index 0000000..23f907d --- /dev/null +++ b/test/unit_tests/mock/test_fixture.cc @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021 Samsung Electronics 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 "unit_tests/mock/test_fixture.hh" + +std::unique_ptr TestFixture::mock_; diff --git a/test/unit_tests/mock/test_fixture.hh b/test/unit_tests/mock/test_fixture.hh new file mode 100644 index 0000000..8351374 --- /dev/null +++ b/test/unit_tests/mock/test_fixture.hh @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2021 Samsung Electronics 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 UNIT_TESTS_MOCK_TEST_FIXTURE_HH_ +#define UNIT_TESTS_MOCK_TEST_FIXTURE_HH_ + +#include + +#include +#include +#include +#include + +#include "unit_tests/mock/module_mock.hh" + +class TestFixture : public ::testing::Test { + public: + explicit TestFixture(std::unique_ptr mock) { + mock_ = std::move(mock); + } + + virtual ~TestFixture() {} + + virtual void SetUp() {} + virtual void TearDown() {} + + template + static T& GetMock() { + auto ptr = dynamic_cast(mock_.get()); + if (ptr == nullptr) { + throw std::invalid_argument("The test does not provide mock of \"" + + std::string(typeid(T).name()) + "\""); + } + + return *ptr; + } + + static std::unique_ptr mock_; +}; + +#endif // UNIT_TESTS_MOCK_TEST_FIXTURE_HH_ diff --git a/unit_tests/src/rpc_port_parcel_test.cc b/test/unit_tests/rpc_port_parcel_test.cc similarity index 100% rename from unit_tests/src/rpc_port_parcel_test.cc rename to test/unit_tests/rpc_port_parcel_test.cc diff --git a/unit_tests/src/rpc_port_test.cc b/test/unit_tests/rpc_port_test.cc similarity index 54% rename from unit_tests/src/rpc_port_test.cc rename to test/unit_tests/rpc_port_test.cc index 2694d7c..78ac326 100644 --- a/unit_tests/src/rpc_port_test.cc +++ b/test/unit_tests/rpc_port_test.cc @@ -1,41 +1,241 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd All Rights Reserved * - * Licensed under the Apache License, Version 2.0 (the License); + * 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, + * 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 +#include #include -#include +#include #include +#include +#include +#include +#include +#include + +#include #include -#include +#include +#include + +#include "include/rpc-port-internal.h" +#include "unit_tests/mock/aul_mock.hh" +#include "unit_tests/mock/test_fixture.hh" -#include "rpc-port-internal.h" +using ::testing::_; +using ::testing::DoAll; +using ::testing::Return; +using ::testing::SetArgPointee; +using ::testing::Invoke; -using ::testing::AtLeast; +namespace { -class RpcPortBase : public ::testing::Test { +class WatchInfo { public: + WatchInfo() {} + WatchInfo(std::string app_id, std::string port_name, + aul_rpc_port_appeared_cb appeared_cb, + aul_rpc_port_vanished_cb vanished_cb, + void* user_data) + : app_id_(std::move(app_id)), + port_name_(std::move(port_name)), + appeared_cb_(appeared_cb), + vanished_cb_(vanished_cb), + user_data_(user_data) { + } + + ~WatchInfo() {} + + void Appear() { + if (appeared_cb_) + appeared_cb_(app_id_.c_str(), port_name_.c_str(), -1, user_data_); + } + + void Vanish() { + if (vanished_cb_) + vanished_cb_(app_id_.c_str(), port_name_.c_str(), -1, user_data_); + + } + + private: + std::string app_id_; + std::string port_name_; + aul_rpc_port_appeared_cb appeared_cb_ = nullptr; + aul_rpc_port_vanished_cb vanished_cb_ = nullptr; + void* user_data_ = nullptr; +}; + +std::unique_ptr test_port_handle; +std::unique_ptr wrong_port_handle; + +int CreateSocket(const std::string& path) { + int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd < 0) { + fd = -errno; + fprintf(stderr, "socket() is failed. path(%s), errno(%d)\n", + path.c_str(), errno); + return fd; + } + + struct sockaddr_un addr = { 0, }; + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path.c_str()); + unlink(path.c_str()); + + struct sockaddr* addr_ptr = reinterpret_cast(&addr); + int ret = bind(fd, addr_ptr, sizeof(addr)); + if (ret != 0) { + ret = -errno; + fprintf(stderr, "bind() is failed. path(%s), errno(%d)\n", + path.c_str(), errno); + close(fd); + return ret; + } + + ret = listen(fd, 128); + if (ret != 0) { + ret = -errno; + fprintf(stderr, "listen() is failed. path(%s), errno(%d)\n", + path.c_str(), errno); + close(fd); + return ret; + } + + mode_t mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | + S_IROTH | S_IWOTH | S_IXOTH; + ret = chmod(path.c_str(), mode); + if (ret != 0) + fprintf(stderr, "chmod(%s, %d) is failed. errno(%d)\n", + path.c_str(), mode, errno); + + return fd; +} + +int FakeAulAppGetAppIdByPid(int pid, char* app_id, int len) { + snprintf(app_id, len, "%s", "TestApp"); + return 0; +} + +int FakeAulRpcPortUsrGetPath(const char* app_id, const char* port_name, + uid_t uid, char** port_path) { + std::string path = "/tmp/." + std::string(app_id) + "_" + + std::string(port_name); + *port_path = strdup(path.c_str()); + return 0; +} + +int FakeAulRpcPortUsrPrepareStub(const char* app_id, const char* port_name, + uid_t uid) { + return 0; +} + +int FakeAulRpcPortUsrExist(const char* app_id, const char* port_name, uid_t uid, + bool* exist) { + if (!strcmp(port_name, "test_port")) { + *exist = true; + if (test_port_handle.get() != nullptr) + test_port_handle->Appear(); + } else { + *exist = false; + if (test_port_handle.get() != nullptr) + test_port_handle->Vanish(); + } + + return 0; +} + +int FakeAulRpcPortNotifyRpcFinished() { + return 0; +} + +int FakeAulRpcPortUsrAddWatch(const char* app_id, const char* port_name, + aul_rpc_port_appeared_cb appeared_cb, aul_rpc_port_vanished_cb vanished_cb, + void* user_data, uid_t uid, aul_rpc_port_watch_h* handle) { + if (!strcmp(port_name, "test_port")) { + test_port_handle.reset( + new WatchInfo(app_id, port_name, appeared_cb, vanished_cb, user_data)); + *handle = test_port_handle.get(); + } else { + wrong_port_handle.reset( + new WatchInfo(app_id, port_name, appeared_cb, vanished_cb, user_data)); + *handle = wrong_port_handle.get(); + } + + return 0; +} + +int FakeAulRpcPortRemoveWatch(aul_rpc_port_watch_h handle) { + if (handle == test_port_handle.get()) + test_port_handle.reset(); + else if (handle == wrong_port_handle.get()) + wrong_port_handle.reset(); + + return 0; +} + +int FakeAulSvcGetAppIdByAliasAppId(const char* alias_appid, char** app_id) { + return -1; +} + +int FakeAulRpcPortUsrCreate(const char* port_name, uid_t uid, int* fd) { + char* port_path = nullptr; + FakeAulRpcPortUsrGetPath("TestApp", port_name, uid, &port_path); + if (port_path == nullptr) + return -1; + + std::unique_ptr port_path_auto( + port_path, std::free); + int socket_fd = CreateSocket(port_path); + if (socket_fd < 0) + return -1; + + *fd = socket_fd; + return 0; +} + +int FakeAulRpcPortUsrDestroy(const char* port_name, uid_t uid) { + char* port_path = nullptr; + FakeAulRpcPortUsrGetPath("TestApp", port_name, uid, &port_path); + if (port_path == nullptr) + return -1; + + std::unique_ptr port_path_auto( + port_path, std::free); + unlink(port_path); + return 0; +} + +} // namespace + +class Mocks : public ::testing::NiceMock {}; + +class RpcPortBase : public TestFixture { + public: + RpcPortBase() : TestFixture(std::make_unique()) {} + virtual ~RpcPortBase() {} + virtual void SetUp() { + SetFakeFuncs(); mainloop_ = g_main_loop_new(nullptr, FALSE); - int ret = rpc_port_proxy_create_mockup(&proxy_handle_); + int ret = rpc_port_proxy_create(&proxy_handle_); ASSERT_NE(proxy_handle_, nullptr); ASSERT_EQ(ret, 0); - ret = rpc_port_stub_create_mockup(&stub_handle_, "test_port"); + ret = rpc_port_stub_create(&stub_handle_, "test_port"); ASSERT_NE(stub_handle_, nullptr); ASSERT_EQ(ret, 0); } @@ -55,6 +255,39 @@ class RpcPortBase : public ::testing::Test { mainloop_ = nullptr; } + void SetFakeFuncs() { + EXPECT_CALL(GetMock(), + aul_app_get_appid_bypid(_, _, _)) + .WillRepeatedly(Invoke(FakeAulAppGetAppIdByPid)); + EXPECT_CALL(GetMock(), + aul_rpc_port_usr_get_path(_, _, _, _)) + .WillRepeatedly(Invoke(FakeAulRpcPortUsrGetPath)); + EXPECT_CALL(GetMock(), + aul_rpc_port_usr_prepare_stub(_, _, _)) + .WillRepeatedly(Invoke(FakeAulRpcPortUsrPrepareStub)); + EXPECT_CALL(GetMock(), + aul_rpc_port_usr_exist(_, _, _, _)) + .WillRepeatedly(Invoke(FakeAulRpcPortUsrExist)); + EXPECT_CALL(GetMock(), + aul_rpc_port_notify_rpc_finished()) + .WillRepeatedly(Invoke(FakeAulRpcPortNotifyRpcFinished)); + EXPECT_CALL(GetMock(), + aul_rpc_port_usr_add_watch(_, _, _, _, _, _, _)) + .WillRepeatedly(Invoke(FakeAulRpcPortUsrAddWatch)); + EXPECT_CALL(GetMock(), + aul_rpc_port_remove_watch(_)) + .WillRepeatedly(Invoke(FakeAulRpcPortRemoveWatch)); + EXPECT_CALL(GetMock(), + aul_svc_get_appid_by_alias_appid(_, _)) + .WillRepeatedly(Invoke(FakeAulSvcGetAppIdByAliasAppId)); + EXPECT_CALL(GetMock(), + aul_rpc_port_usr_create(_, _, _)) + .WillRepeatedly(Invoke(FakeAulRpcPortUsrCreate)); + EXPECT_CALL(GetMock(), + aul_rpc_port_usr_destroy(_, _)) + .WillRepeatedly(Invoke(FakeAulRpcPortUsrDestroy)); + } + void RunMainLoop() { g_main_loop_run(mainloop_); } @@ -93,20 +326,23 @@ class RpcPortConnection : public RpcPortBase { RpcPortBase::SetUp(); StubSetup(); ProxySetup(); + RunMainLoop(); } virtual void TearDown() { RpcPortBase::TearDown(); + stub_port_ = nullptr; + proxy_port_ = nullptr; } void StubSetup() { int ret = rpc_port_stub_add_received_event_cb(stub_handle_, [](const char* sender, const char* instance, - rpc_port_h port, void *data) -> int { + rpc_port_h port, void *data) -> int { RpcPortConnection* p = static_cast(data); p->stub_port_ = port; - int ret = rpc_port_stub_get_port(p->stub_handle_, RPC_PORT_PORT_CALLBACK, - instance, &p->stub_callback_port_); + int ret = rpc_port_stub_get_port(p->stub_handle_, + RPC_PORT_PORT_CALLBACK, instance, &p->stub_callback_port_); p->Finish(); if (ret != 0) return -1; @@ -137,6 +373,7 @@ class RpcPortConnection : public RpcPortBase { p->proxy_port_ = port; rpc_port_proxy_get_port(p->proxy_handle_, RPC_PORT_PORT_CALLBACK, &p->proxy_callback_port_); + p->Finish(); }, this); ASSERT_EQ(ret, 0); @@ -191,14 +428,16 @@ TEST_F(RpcPortBase, rpc_port_event_connect) { ret = rpc_port_proxy_add_connected_event_cb(proxy_handle_, [](const char *ep, const char *port_name, rpc_port_h port, void *data) { RpcPortBase* p = static_cast(data); - p->touch_proxy_connected_event_cb_ = true; + p->Finish(); }, this); ASSERT_EQ(ret, 0); ret = rpc_port_proxy_connect(proxy_handle_, "TestApp", "test_port"); ASSERT_EQ(ret, 0); + RunMainLoop(); + ASSERT_TRUE(touch_proxy_connected_event_cb_); ASSERT_TRUE(touch_stub_connected_event_cb_); } @@ -214,7 +453,6 @@ TEST_F(RpcPortBase, rpc_port_event_connect_sync) { int ret = rpc_port_stub_add_connected_event_cb(stub_handle_, [](const char *sender, const char* instance, void *data) { RpcPortBase* p = static_cast(data); - p->touch_stub_connected_event_cb_ = true; }, this); ASSERT_EQ(ret, 0); @@ -225,42 +463,53 @@ TEST_F(RpcPortBase, rpc_port_event_connect_sync) { ret = rpc_port_proxy_add_connected_event_cb(proxy_handle_, [](const char *ep, const char *port_name, rpc_port_h port, void *data) { RpcPortBase* p = static_cast(data); - p->touch_proxy_connected_event_cb_ = true; + p->Finish(); }, this); ASSERT_EQ(ret, 0); - ret = rpc_port_proxy_connect_sync(proxy_handle_, "TestApp", "test_port"); - ASSERT_EQ(ret, 0); + std::thread t([](RpcPortBase* p) { + int ret = rpc_port_proxy_connect_sync(p->proxy_handle_, "TestApp", + "test_port"); + ASSERT_EQ(ret, 0); + }, this); + + RunMainLoop(); + t.join(); ASSERT_TRUE(touch_proxy_connected_event_cb_); ASSERT_TRUE(touch_stub_connected_event_cb_); } - /* * @testcase rpc_port_proxy_event_reject_n * @description After the rpc_port_proxy_connect() is called, * the rambda function is called by the rejected event. - * @apicovered rpc_port_stub_listen, rpc_port_proxy_add_connected_event_cb, + * @apicovered rpc_port_proxy_add_connected_event_cb, * rpc_port_proxy_connect, */ TEST_F(RpcPortBase, rpc_port_proxy_event_reject_N) { - int ret = rpc_port_stub_listen(stub_handle_); - ASSERT_EQ(ret, 0); - - ret = rpc_port_proxy_add_rejected_event_cb(proxy_handle_, + int ret = rpc_port_proxy_add_rejected_event_cb(proxy_handle_, [](const char *ep, const char *port_name, void *data) { RpcPortBase* p = static_cast(data); - p->touch_proxy_rejected_event_cb_ = true; + p->Finish(); }, this); ASSERT_EQ(ret, 0); ret = rpc_port_proxy_connect(proxy_handle_, "TestApp", "wrong_port"); ASSERT_EQ(ret, 0); + guint tag = g_timeout_add_seconds(15, + [](gpointer data) -> gboolean { + auto* p = static_cast(data); + p->Finish(); + return G_SOURCE_REMOVE; + }, this); + + RunMainLoop(); ASSERT_TRUE(touch_proxy_rejected_event_cb_); + g_source_remove(tag); } /* @@ -273,11 +522,16 @@ TEST_F(RpcPortConnection, rpc_port_proxy_event_receive_p) { char res[] = "OK"; char r_buf[256]; + if (proxy_port_ == nullptr) + RunMainLoop(); + ASSERT_NE(proxy_port_, nullptr); int ret = rpc_port_write(proxy_port_, res, sizeof(res)); ASSERT_EQ(ret, 0); - RunMainLoop(); + if (stub_port_ == nullptr) + RunMainLoop(); + ASSERT_NE(stub_port_, nullptr); ASSERT_NE(stub_callback_port_, nullptr); @@ -313,11 +567,16 @@ TEST_F(RpcPortConnection, rpc_port_read_write) { char res[] = "OK"; char r_buf[256]; + if (proxy_port_ == nullptr) + RunMainLoop(); + ASSERT_NE(proxy_port_, nullptr); int ret = rpc_port_write(proxy_port_, buf, sizeof(buf)); ASSERT_EQ(ret, 0); - RunMainLoop(); + if (stub_port_ == nullptr) + RunMainLoop(); + ASSERT_NE(stub_port_, nullptr); ret = rpc_port_read(stub_port_, r_buf, sizeof(buf)); diff --git a/unit_tests/CMakeLists.txt b/unit_tests/CMakeLists.txt deleted file mode 100644 index dac0b21..0000000 --- a/unit_tests/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.6) -PROJECT(rpc-port_unittests CXX) - -INCLUDE(FindPkgConfig) -pkg_check_modules(rpc-port_unittests REQUIRED - glib-2.0 - gmock - aul -) - -FOREACH(flag ${rpc-port_unittests_CFLAGS}) - SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") -ENDFOREACH(flag) -SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -Wall -Werror -Winline") - -SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} -std=c++11") -SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") -SET(CMAKE_CXX_FLAGS_RELEASE "-O2") -SET(SOURCES "") - -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../include) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../src) - -AUX_SOURCE_DIRECTORY(src SOURCES) -AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../src RPC_PORT_SOURCES) -ADD_EXECUTABLE(${PROJECT_NAME} - ${RPC_PORT_SOURCES} - ${SOURCES} -) - -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${rpc-port_unittests_LDFLAGS} rpc-port) - -INSTALL(TARGETS ${PROJECT_NAME} DESTINATION /usr/bin) diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index c639ff2..6353206 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -1,34 +1,25 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.8) -PROJECT(rpc-port-util CXX) +AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} UTIL_SRCS) -INCLUDE(FindPkgConfig) -pkg_check_modules(rpc-port-util REQUIRED - aul - bundle - dlog - glib-2.0 -) - -FOREACH(flag ${rpc-port-util_CFLAGS}) - SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") -ENDFOREACH(flag) -SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -Wall -Werror -Winline -fPIE") - -SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} -std=c++14") -SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") -SET(CMAKE_CXX_FLAGS_RELEASE "-O2") -SET(SOURCES "") +ADD_EXECUTABLE(${TARGET_RPC_PORT_UTIL} ${UTIL_SRCS}) -ADD_DEFINITIONS("-DFULLVER=\"${FULLVER}\"") +TARGET_INCLUDE_DIRECTORIES(${TARGET_RPC_PORT_UTIL} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../ + ${CMAKE_CURRENT_SOURCE_DIR}/../../ + ${CMAKE_CURRENT_SOURCE_DIR}/../../include) -INCLUDE_DIRECTORIES( - ${CMAKE_CURRENT_SOURCE_DIR}/../ - ${CMAKE_CURRENT_SOURCE_DIR}/../include - ) - -AUX_SOURCE_DIRECTORY(src SOURCES) -ADD_EXECUTABLE(${PROJECT_NAME} ${SOURCES}) +APPLY_PKG_CONFIG(${TARGET_RPC_PORT_UTIL} PUBLIC + AUL_DEPS + BUNDLE_DEPS + DLOG_DEPS + GLIB_DEPS +) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${rpc-port-util_LDFLAGS} "-pie" rpc-port) +TARGET_LINK_LIBRARIES(${TARGET_RPC_PORT_UTIL} PUBLIC + ${TARGET_RPC_PORT} "-lpthread") +SET_TARGET_PROPERTIES(${TARGET_RPC_PORT_UTIL} PROPERTIES + COMPILE_FLAGS "-fPIE") +SET_TARGET_PROPERTIES(${TARGET_RPC_PORT_UTIL} PROPERTIES + LINK_FLAGS "-pie") -INSTALL(TARGETS ${PROJECT_NAME} DESTINATION /usr/bin) +INSTALL(TARGETS ${TARGET_RPC_PORT_UTIL} DESTINATION bin) diff --git a/utils/src/debug-port.cc b/utils/debug-port.cc similarity index 100% rename from utils/src/debug-port.cc rename to utils/debug-port.cc diff --git a/utils/src/debug-port.hh b/utils/debug-port.hh similarity index 100% rename from utils/src/debug-port.hh rename to utils/debug-port.hh diff --git a/utils/src/log-private.hh b/utils/log-private.hh similarity index 100% rename from utils/src/log-private.hh rename to utils/log-private.hh diff --git a/utils/src/logger.cc b/utils/logger.cc similarity index 100% rename from utils/src/logger.cc rename to utils/logger.cc diff --git a/utils/src/logger.hh b/utils/logger.hh similarity index 100% rename from utils/src/logger.hh rename to utils/logger.hh diff --git a/utils/src/main.cc b/utils/main.cc similarity index 100% rename from utils/src/main.cc rename to utils/main.cc diff --git a/utils/src/message.cc b/utils/message.cc similarity index 100% rename from utils/src/message.cc rename to utils/message.cc diff --git a/utils/src/message.hh b/utils/message.hh similarity index 100% rename from utils/src/message.hh rename to utils/message.hh diff --git a/utils/src/options.cc b/utils/options.cc similarity index 100% rename from utils/src/options.cc rename to utils/options.cc diff --git a/utils/src/options.hh b/utils/options.hh similarity index 100% rename from utils/src/options.hh rename to utils/options.hh -- 2.7.4 From b2311d751255f1ae0e681e0c4013bc768b6d5df6 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Thu, 1 Jul 2021 16:57:09 +0900 Subject: [PATCH 07/16] Support Daemon Stub This patch supports that the daemon process can be the stub. The daemon or service process has to call the rpc_port_register_proc_info() to set the process name. When the proxy tries to connect to the stub, the rpc-port library calls the aul_proc_get_name() if calling the aul_app_get_appid_bypid() is failed. Change-Id: I133b04c6a0196420fcd6aeba52085cf73c10f4d3 Signed-off-by: Hwankyu Jhun --- include/rpc-port-internal.h | 22 ++++++++++++++++++++++ src/aul-internal.cc | 9 ++++++++- src/rpc-port-internal.cc | 20 ++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/include/rpc-port-internal.h b/include/rpc-port-internal.h index 4ac06ca..ab99261 100644 --- a/include/rpc-port-internal.h +++ b/include/rpc-port-internal.h @@ -20,6 +20,7 @@ #include #include +#include #include #ifdef __cplusplus @@ -42,6 +43,27 @@ void rpc_port_set_target_uid(uid_t target_uid); */ uid_t rpc_port_get_target_uid(void); +/** + * @brief Registers the process information. + * @since_tizen 6.5 + * @remarks This function is only for a daemon process. + * @param[in] proc_name The process name + * @param[in] extra The extra data + * @return @c 0 on success, + * otherwise a negative error value + * @see rpc_port_register_proc_info() + */ +int rpc_port_register_proc_info(const char *proc_name, bundle *extra); + +/** + * @brief Dergisters the process information. + * @since_tizen 6.5 + * @return @c 0 on success, + * otherwise a negative error value + * @see rpc_port_deregister_proc_info() + */ +int rpc_port_deregister_proc_info(void); + #ifdef __cplusplus } #endif diff --git a/src/aul-internal.cc b/src/aul-internal.cc index 0dca700..67a5838 100644 --- a/src/aul-internal.cc +++ b/src/aul-internal.cc @@ -16,6 +16,7 @@ #include #include +#include #include @@ -31,7 +32,13 @@ std::string Aul::GetAppId(int pid) { int ret = aul_app_get_appid_bypid(pid, app_id, sizeof(app_id)); if (ret != AUL_R_OK) { _E("aul_app_get_appid_bypid() is failed. pid(%d), error(%d)", pid, ret); - return "Daemon"; + char* name = nullptr; + ret = aul_proc_get_name(pid, &name); + if (ret != AUL_R_OK) + return ""; + + std::unique_ptr name_auto(name, std::free); + return std::string(name); } return std::string(app_id); diff --git a/src/rpc-port-internal.cc b/src/rpc-port-internal.cc index a8c5569..36682dd 100644 --- a/src/rpc-port-internal.cc +++ b/src/rpc-port-internal.cc @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include #include #include @@ -43,3 +44,22 @@ RPC_API uid_t rpc_port_get_target_uid(void) { return __target_uid; } + +RPC_API int rpc_port_register_proc_info(const char* proc_name, bundle* extra) { + if (proc_name == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + int ret = aul_proc_register(proc_name, extra); + if (ret != AUL_R_OK) + return RPC_PORT_ERROR_IO_ERROR; + + return RPC_PORT_ERROR_NONE; +} + +RPC_API int rpc_port_deregister_proc_info(void) { + int ret = aul_proc_deregister(); + if (ret != AUL_R_OK) + return RPC_PORT_ERROR_IO_ERROR; + + return RPC_PORT_ERROR_NONE; +} -- 2.7.4 From 5f9300a9c8f93120915b91689a84b59b30af8a2d Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Mon, 12 Jul 2021 16:59:59 +0900 Subject: [PATCH 08/16] Release version 1.9.0 Changes: - Use Unix Domain Socket instead of Socket Pair - Support Daemon Stub Change-Id: Idcf5bc419ae588df37110018e28e3dade8eae896 Signed-off-by: Hwankyu Jhun --- packaging/rpc-port.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/rpc-port.spec b/packaging/rpc-port.spec index e13591a..8cdcd82 100644 --- a/packaging/rpc-port.spec +++ b/packaging/rpc-port.spec @@ -1,6 +1,6 @@ Name: rpc-port Summary: RPC Port library -Version: 1.8.2 +Version: 1.9.0 Release: 0 Group: Application Framework/Libraries License: Apache-2.0 -- 2.7.4 From bb9665132533abeb5645e9cf81a6498b2afa2d28 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Wed, 14 Jul 2021 08:16:41 +0900 Subject: [PATCH 09/16] Add a missing required library to pkgconfig Adds: - bundle Change-Id: I5cc6a806fae8cbe9dc8cf1fbb417bc17e79fbdf8 Signed-off-by: Hwankyu Jhun --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 78dbd01..c7f5b49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ ADD_DEFINITIONS("-DFULLVER=\"${FULLVER}\"") SET(CMAKE_INSTALL_PREFIX /usr) SET(PREFIX ${CMAKE_INSTALL_PREFIX}) SET(PC_NAME "rpc-port") -SET(PC_REQUIRED "capi-base-common") +SET(PC_REQUIRED "bundle capi-base-common") SET(PC_VERSION ${FULLVER}) SET(PC_LDFLAGS "-lrpc-port") -- 2.7.4 From b04ec061a43db61a2d5120bfbaa35a48c725a501 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Thu, 15 Jul 2021 11:56:54 +0900 Subject: [PATCH 10/16] Release version 1.9.1 Changes: - Add a missing required library to pkgconfig Change-Id: I687fbbb62380474e97ba55fe6501ec9159e888e6 Signed-off-by: Hwankyu Jhun --- packaging/rpc-port.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/rpc-port.spec b/packaging/rpc-port.spec index 8cdcd82..80652e5 100644 --- a/packaging/rpc-port.spec +++ b/packaging/rpc-port.spec @@ -1,6 +1,6 @@ Name: rpc-port Summary: RPC Port library -Version: 1.9.0 +Version: 1.9.1 Release: 0 Group: Application Framework/Libraries License: Apache-2.0 -- 2.7.4 From fe73b32dca63842ff81bbcecddfcf2a672f321a8 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Mon, 19 Jul 2021 08:08:20 +0900 Subject: [PATCH 11/16] Fix static analysis issue - Initialize private members to nullptr Change-Id: I36ebc07223b157b207d2f7c4d4c61e21c21a9a92 Signed-off-by: Hwankyu Jhun --- test/unit_tests/rpc_port_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit_tests/rpc_port_test.cc b/test/unit_tests/rpc_port_test.cc index 78ac326..7163202 100644 --- a/test/unit_tests/rpc_port_test.cc +++ b/test/unit_tests/rpc_port_test.cc @@ -308,8 +308,8 @@ class RpcPortBase : public TestFixture { proxy_handle_ = nullptr; } - rpc_port_proxy_h proxy_handle_; - rpc_port_stub_h stub_handle_; + rpc_port_proxy_h proxy_handle_ = nullptr; + rpc_port_stub_h stub_handle_ = nullptr; bool touch_proxy_connected_event_cb_ = false; bool touch_stub_connected_event_cb_ = false; bool touch_proxy_rejected_event_cb_ = false; -- 2.7.4 From eb20db768fa2046c70ddf61b76781b7a1c0a19f7 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Mon, 19 Jul 2021 08:15:55 +0900 Subject: [PATCH 12/16] Release version 1.9.2 Changes: - Fix static analysis issue Change-Id: I6949c16038588f2e951602aa68e219d43a69d646 Signed-off-by: Hwankyu Jhun --- packaging/rpc-port.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/rpc-port.spec b/packaging/rpc-port.spec index 80652e5..b02b731 100644 --- a/packaging/rpc-port.spec +++ b/packaging/rpc-port.spec @@ -1,6 +1,6 @@ Name: rpc-port Summary: RPC Port library -Version: 1.9.1 +Version: 1.9.2 Release: 0 Group: Application Framework/Libraries License: Apache-2.0 -- 2.7.4 From a3ad231fac16efbfe4603e063cc2e50ece245f42 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Fri, 6 Aug 2021 10:43:14 +0900 Subject: [PATCH 13/16] Fix DebugPort Implementation If the instance is managed as a global variable, the process tries to access to the destroyed DebugPort instance while calling the exit handlers. Change-Id: Ia7cfa9d241266921221ecf28ce8b4b22dc4b95d6 Signed-off-by: Hwankyu Jhun --- src/debug-port-internal.cc | 21 +++++++++++++++++++++ src/debug-port-internal.hh | 16 ++++++---------- src/proxy-internal.cc | 10 +++++----- src/rpc-port.cc | 8 ++++---- src/stub-internal.cc | 4 ++-- 5 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/debug-port-internal.cc b/src/debug-port-internal.cc index 0d89d5f..8b28c77 100644 --- a/src/debug-port-internal.cc +++ b/src/debug-port-internal.cc @@ -34,11 +34,32 @@ const char RPC_PORT_SIGNAL_DEBUG[] = "Debug"; const char RPC_PORT_SIGNAL_NEW[] = "New"; } // namespace +std::atomic DebugPort::inst_; +std::mutex DebugPort::mutex_; + DebugPort::~DebugPort() { if (!disposed_) Dispose(); } +DebugPort* DebugPort::GetInst() { + DebugPort* inst = inst_.load(std::memory_order_acquire); + if (inst == nullptr) { + std::lock_guard lock(mutex_); + inst = inst_.load(std::memory_order_relaxed); + if (inst == nullptr) { + inst = new DebugPort(); + inst_.store(inst, std::memory_order_release); + } + } + + std::lock_guard rec_lock(inst->GetMutex()); + if (inst->disposed_) + inst->Init(); + + return inst; +} + void DebugPort::Dispose() { Unwatch(); Unsubscribe(); diff --git a/src/debug-port-internal.hh b/src/debug-port-internal.hh index 27eb66b..98a3042 100644 --- a/src/debug-port-internal.hh +++ b/src/debug-port-internal.hh @@ -74,14 +74,7 @@ class DebugPort { int delegate_port_; }; - static DebugPort& GetInst() { - static DebugPort inst; - - std::lock_guard lock(inst.GetMutex()); - if (inst.disposed_) - inst.Init(); - return inst; - } + static DebugPort* GetInst(); void Dispose(); bool IsConnected(); @@ -94,8 +87,11 @@ class DebugPort { const void* buf, unsigned int size); private: + static std::atomic inst_; + static std::mutex mutex_; + std::recursive_mutex& GetMutex() const { - return mutex_; + return rec_mutex_; } void Init(); @@ -134,7 +130,7 @@ class DebugPort { std::thread thread_; std::atomic is_running_; SharedQueue> queue_; - mutable std::recursive_mutex mutex_; + mutable std::recursive_mutex rec_mutex_; }; } // namespace internal diff --git a/src/proxy-internal.cc b/src/proxy-internal.cc index 9f7ac7c..c85f17a 100644 --- a/src/proxy-internal.cc +++ b/src/proxy-internal.cc @@ -262,14 +262,14 @@ int Proxy::ConnectSync(std::string appid, std::string port_name, main_port_.reset(new ProxyPort(this, fds_[0], target_appid_, false)); delegate_port_.reset(new ProxyPort(this, fds_[1], target_appid_)); listener_->OnConnected(target_appid_, main_port_.get()); - DebugPort::GetInst().AddSession(port_name, target_appid_, fds_[0], fds_[1]); + DebugPort::GetInst()->AddSession(port_name, target_appid_, fds_[0], fds_[1]); return RPC_PORT_ERROR_NONE; } void Proxy::DisconnectPort() { std::lock_guard lock(GetMutex()); if (main_port_.get() != nullptr) { - DebugPort::GetInst().RemoveSession(main_port_->GetFd()); + DebugPort::GetInst()->RemoveSession(main_port_->GetFd()); main_port_.reset(); } } @@ -456,7 +456,7 @@ gboolean Proxy::ProxyPort::OnSocketDisconnected(GIOChannel* channel, proxy->delegate_port_.reset(); proxy->listener_ = nullptr; listener->OnDisconnected(proxy->target_appid_); - DebugPort::GetInst().RemoveSession(fd); + DebugPort::GetInst()->RemoveSession(fd); return G_SOURCE_REMOVE;; } @@ -478,7 +478,7 @@ gboolean Proxy::ProxyPort::OnDataReceived(GIOChannel* channel, proxy->listener_ = nullptr; proxy->delegate_port_->SetSource(0); if (proxy->main_port_.get() != nullptr) { - DebugPort::GetInst().RemoveSession(proxy->main_port_->GetFd()); + DebugPort::GetInst()->RemoveSession(proxy->main_port_->GetFd()); proxy->main_port_.reset(); } proxy->delegate_port_.reset(); @@ -656,7 +656,7 @@ gboolean Proxy::Client::OnResponseReceived(GIOChannel* channel, proxy->delegate_port_.reset( new ProxyPort(proxy, proxy->fds_[1], proxy->target_appid_)); listener->OnConnected(proxy->target_appid_, proxy->main_port_.get()); - DebugPort::GetInst().AddSession(proxy->port_name_, proxy->target_appid_, + DebugPort::GetInst()->AddSession(proxy->port_name_, proxy->target_appid_, proxy->fds_[0], proxy->fds_[1]); _W("target_appid(%s), port_name(%s), main_fd(%d), delegate_fd(%d)", proxy->target_appid_.c_str(), proxy->port_name_.c_str(), diff --git a/src/rpc-port.cc b/src/rpc-port.cc index ca708d8..7340c2b 100644 --- a/src/rpc-port.cc +++ b/src/rpc-port.cc @@ -222,8 +222,8 @@ RPC_API int rpc_port_read(rpc_port_h h, void* buf, unsigned int size) { return ret; } - auto& debug_port = DebugPort::GetInst(); - debug_port.Send(port->GetFd(), true, seq, buf, size); + auto* debug_port = DebugPort::GetInst(); + debug_port->Send(port->GetFd(), true, seq, buf, size); return RPC_PORT_ERROR_NONE; } @@ -241,8 +241,8 @@ RPC_API int rpc_port_write(rpc_port_h h, const void* buf, unsigned int size) { if (ret < 0) return ret; - auto& debug_port = DebugPort::GetInst(); - debug_port.Send(port->GetFd(), false, seq, buf, size); + auto* debug_port = DebugPort::GetInst(); + debug_port->Send(port->GetFd(), false, seq, buf, size); return RPC_PORT_ERROR_NONE; } diff --git a/src/stub-internal.cc b/src/stub-internal.cc index 8a038c4..63cea83 100644 --- a/src/stub-internal.cc +++ b/src/stub-internal.cc @@ -154,7 +154,7 @@ void Stub::RemoveAcceptedPorts(std::string instance) { while (iter != ports_.end()) { if ((*iter)->GetInstance().compare(instance) == 0) { LOGI("Close: fd(%d)", (*iter)->GetFd()); - DebugPort::GetInst().RemoveSession((*iter)->GetFd()); + DebugPort::GetInst()->RemoveSession((*iter)->GetFd()); iter = ports_.erase(iter); } else { iter++; @@ -252,7 +252,7 @@ void Stub::AddAcceptedPort(const std::string& sender_appid, _W("sender_appid(%s), instance(%s), main_fd(%d), delegate_fd(%d)", sender_appid.c_str(), instance.c_str(), main_fd, fd); listener_->OnConnected(sender_appid, instance); - DebugPort::GetInst().AddSession(port_name_, sender_appid, main_fd, fd); + DebugPort::GetInst()->AddSession(port_name_, sender_appid, main_fd, fd); } std::recursive_mutex& Stub::GetMutex() const { -- 2.7.4 From 52792fc5b7631836a169680a78c7780c84f7906c Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Fri, 6 Aug 2021 12:10:57 +0900 Subject: [PATCH 14/16] Release version 1.9.3 Changes: - Fix DebugPort Implementation Change-Id: I98732667130139c3892762aa979960792964098d Signed-off-by: Hwankyu Jhun --- packaging/rpc-port.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/rpc-port.spec b/packaging/rpc-port.spec index b02b731..5627f21 100644 --- a/packaging/rpc-port.spec +++ b/packaging/rpc-port.spec @@ -1,6 +1,6 @@ Name: rpc-port Summary: RPC Port library -Version: 1.9.2 +Version: 1.9.3 Release: 0 Group: Application Framework/Libraries License: Apache-2.0 -- 2.7.4 From 696a464a2b28909a8ec6e40c66f936e907558685 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Thu, 12 Aug 2021 15:06:38 +0900 Subject: [PATCH 15/16] Fix deadlock issue When the rpc_port_proxy_connect() is called in the sub thread, the port appeared event can be received in the main thread. In this case, the process can be a deadlock state as below: +------------------------------------------------------------------------------+ | -- #0 0xb5d3e6c8 in __lll_lock_wait () from /usr/lib/libpthread-2.30.so | | -- #1 0xb5d35de4 in __pthread_mutex_lock () from /usr/lib/libpthread-2.30.so| | -- #2 0xa63ee315 in _ZN8rpc_port8internal5Proxy14OnPortAppearedEPKcS3_iPv ()| | from /usr/lib/librpc-port.so.1.9.3 | | -- #3 0xb5f69721 in _ZN12_GLOBAL__N_19WatchInfo8AppComCbEPKc20aul_app_com_re| | sult_eP9_bundle_tPv () from /usr/lib/libaul.so.0.38.0 | | -- #4 0xb5f74d2d in app_com_recv () from /usr/lib/libaul.so.0.38.0 | | -- #5 0xb5f74fe7 in __dispatch_request () from /usr/lib/libaul.so.0.38.0 | | -- #6 0xb5b10fb3 in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.| 0.6200.3 | | -- #7 0xb58a01a9 in _ecore_glib_select.lto_priv.0 () from /usr/lib/libecore.| | so.1.25.1 | | -- #8 0xb589f037 in _ecore_main_select () from /usr/lib/libecore.so.1.25.1 | | -- #9 0xb589f8c7 in _ecore_main_loop_iterate_internal () from /usr/lib/libec| | ore.so.1.25.1 | | -- [pthread wait detected] pthread_mutex_lock/pthread_join owner tid:1412 | +------------------------------------------------------------------------------+ | -- [User Backtrace] [Thread state:S (sleeping), Frozen:No] | | -- Pid: 683, Tid: 1412, comm: Parallel[0] exec_start[69.429195162] | | -- #0 0xb5d3e6c8 in __lll_lock_wait () from /usr/lib/libpthread-2.30.so | | -- #1 0xb5d35de4 in __pthread_mutex_lock () from /usr/lib/libpthread-2.30.so| | -- #2 0xb5f789b5 in aul_app_com_leave () from /usr/lib/libaul.so.0.38.0 | | -- #3 0xb5f6d197 in aul_rpc_port_remove_watch () from /usr/lib/libaul.so.0.3| | 8.0 | | -- #4 0xa63ec503 in _ZN8rpc_port8internal5Proxy6CancelEv () from /usr/lib/li| | brpc-port.so.1.9.3 | | -- #5 0xa63ee329 in _ZN8rpc_port8internal5Proxy14OnPortAppearedEPKcS3_iPv ()| | from /usr/lib/librpc-port.so.1.9.3 | | -- #6 0xa63ee45b in _ZN8rpc_port8internal5Proxy5WatchEv () from /usr/lib/lib| | rpc-port.so.1.9.3 | | -- #7 0xa63ee58f in _ZN8rpc_port8internal5Proxy7ConnectENSt7__cxx1112basic_s| | tringIcSt11char_traitsIcESaIcEEES7_PNS1_14IEventListener| | E () from /usr/lib/librpc-port.so.1.9.3 | | -- #8 0xa63efd51 in rpc_port_proxy_connect () from /usr/lib/librpc-port.so.1| | .9.3 | +------------------------------------------------------------------------------+ This patch fixes the proxy handle management using the shared_ptr. And, the port check is moved to the main thread to avoid the deadlock issue. Change-Id: I8ef7f775491427e48eb5894c66dc1629d172a4d5 Signed-off-by: Hwankyu Jhun --- src/proxy-internal.cc | 137 ++++++++++++++++++++++++++++++++++++++++++++------ src/proxy-internal.hh | 12 ++++- src/rpc-port.cc | 88 ++++++++++++++++++-------------- 3 files changed, 182 insertions(+), 55 deletions(-) diff --git a/src/proxy-internal.cc b/src/proxy-internal.cc index c85f17a..f22c6ca 100644 --- a/src/proxy-internal.cc +++ b/src/proxy-internal.cc @@ -104,6 +104,7 @@ Proxy::~Proxy() { std::lock_guard lock(GetMutex()); _D("Proxy::~Proxy()"); listener_ = nullptr; + UnsetIdler(); UnsetConnTimer(); Cancel(); } @@ -284,13 +285,8 @@ int Proxy::Watch() { return -1; } - if (Aul::ExistPort(real_appid_, port_name_, rpc_port_get_target_uid())) { - OnPortAppeared(real_appid_.c_str(), port_name_.c_str(), -1, this); - } else { - OnPortVanished(real_appid_.c_str(), port_name_.c_str(), -1, this); - SetConnTimer(); - } - + SetConnTimer(); + SetIdler(); return 0; } @@ -324,15 +320,59 @@ std::recursive_mutex& Proxy::GetMutex() const { } void Proxy::SetConnTimer() { - if (conn_timer_ == 0) - conn_timer_ = g_timeout_add_seconds(10, OnTimedOut, this); + if (conn_timer_data_) { + _W("Already exists"); + return; + } + + conn_timer_data_ = CreateWeakPtr(); + if (conn_timer_data_ == nullptr) { + _E("Out of memory"); + return; + } + + g_timeout_add_seconds(10, OnTimedOut, conn_timer_data_); } void Proxy::UnsetConnTimer() { - if (conn_timer_) { - g_source_remove(conn_timer_); - conn_timer_ = 0; + if (conn_timer_data_ == nullptr) + return; + + GSource* source = g_main_context_find_source_by_user_data(nullptr, + conn_timer_data_); + if (source && !g_source_is_destroyed(source)) + g_source_destroy(source); + + DestroyWeakPtr(conn_timer_data_); + conn_timer_data_ = nullptr; +} + +void Proxy::SetIdler() { + if (idler_data_) { + _W("Already exists"); + return; } + + idler_data_ = CreateWeakPtr(); + if (idler_data_ == nullptr) { + _E("Out of memory"); + return; + } + + g_idle_add(OnIdle, idler_data_); +} + +void Proxy::UnsetIdler() { + if (idler_data_ == nullptr) + return; + + GSource* source = g_main_context_find_source_by_user_data(nullptr, + idler_data_); + if (source && !g_source_is_destroyed(source)) + g_source_destroy(source); + + DestroyWeakPtr(idler_data_); + idler_data_ = nullptr; } void Proxy::OnPortAppeared(const char* app_id, const char* port_name, int pid, @@ -340,6 +380,13 @@ void Proxy::OnPortAppeared(const char* app_id, const char* port_name, int pid, _W("app_id(%s), port_name(%s), pid(%d)", app_id, port_name, pid); auto* proxy = static_cast(user_data); std::lock_guard lock(proxy->GetMutex()); + proxy->UnsetIdler(); + + if (proxy->watch_handle_ == nullptr) { + _E("Invalid context"); + return; + } + auto* listener = proxy->listener_; if (listener == nullptr) { _E("Invalid context"); @@ -362,21 +409,67 @@ void Proxy::OnPortAppeared(const char* app_id, const char* port_name, int pid, void Proxy::OnPortVanished(const char* app_id, const char* port_name, int pid, void* user_data) { _W("app_id(%s), port_name(%s), pid(%d)", app_id, port_name, pid); + auto* proxy = static_cast(user_data); + std::lock_guard lock(proxy->GetMutex()); + proxy->UnsetIdler(); } gboolean Proxy::OnTimedOut(gpointer user_data) { _E("Timed out"); - auto* proxy = static_cast(user_data); + auto* ptr = static_cast*>(user_data); + auto proxy = ptr->lock(); + if (proxy == nullptr) { + _E("Proxy is nullptr"); + return G_SOURCE_REMOVE; + } + std::lock_guard lock(proxy->GetMutex()); + if (proxy->conn_timer_data_ == nullptr) { + _E("Invalid context. proxy(%p)", proxy.get()); + return G_SOURCE_REMOVE; + } + + DestroyWeakPtr(proxy->conn_timer_data_); + proxy->conn_timer_data_ = nullptr; + auto* listener = proxy->listener_; if (listener == nullptr) { _E("Invalid context"); return G_SOURCE_REMOVE; } - proxy->UnsetConnTimer(); listener->OnRejected(proxy->target_appid_, RPC_PORT_ERROR_IO_ERROR); - return G_SOURCE_CONTINUE; + return G_SOURCE_REMOVE; +} + +gboolean Proxy::OnIdle(gpointer user_data) { + auto* ptr = static_cast*>(user_data); + auto proxy = ptr->lock(); + if (proxy == nullptr) { + _E("Proxy is nullptr"); + return G_SOURCE_REMOVE; + } + + std::lock_guard lock(proxy->GetMutex()); + if (proxy->idler_data_ == nullptr) { + _E("Invalid context. proxy(%p)", proxy.get()); + return G_SOURCE_REMOVE; + } + + DestroyWeakPtr(proxy->idler_data_); + proxy->idler_data_ = nullptr; + + bool exist = Aul::ExistPort(proxy->real_appid_, proxy->port_name_, + rpc_port_get_target_uid()); + if (exist) { + proxy->OnPortAppeared(proxy->real_appid_.c_str(), + proxy->port_name_.c_str(), -1, proxy.get()); + } else { + proxy->OnPortVanished(proxy->real_appid_.c_str(), + proxy->port_name_.c_str(), -1, proxy.get()); + } + + return G_SOURCE_REMOVE; } Proxy::ProxyPort::ProxyPort(Proxy* parent, int fd, const std::string& id, @@ -670,5 +763,19 @@ gboolean Proxy::Client::OnResponseReceived(GIOChannel* channel, return G_SOURCE_REMOVE; } +std::shared_ptr Proxy::GetSharedPtr() { + return shared_from_this(); +} + +gpointer Proxy::CreateWeakPtr() { + auto* ptr = new (std::nothrow) std::weak_ptr(GetSharedPtr()); + return static_cast(ptr); +} + +void Proxy::DestroyWeakPtr(gpointer data) { + auto* ptr = static_cast*>(data); + delete ptr; +} + } // namespace internal } // namespace rpc_port diff --git a/src/proxy-internal.hh b/src/proxy-internal.hh index df0fbcb..414888f 100644 --- a/src/proxy-internal.hh +++ b/src/proxy-internal.hh @@ -32,7 +32,7 @@ namespace rpc_port { namespace internal { -class Proxy { +class Proxy : public std::enable_shared_from_this { public: Proxy(); virtual ~Proxy(); @@ -115,6 +115,7 @@ class Proxy { static void OnPortVanished(const char* app_id, const char* port_name, int pid, void* user_data); static gboolean OnTimedOut(gpointer user_data); + static gboolean OnIdle(gpointer user_data); void SetRealAppId(const std::string& alias_appid); std::recursive_mutex& GetMutex() const; @@ -123,6 +124,12 @@ class Proxy { void Cancel(); void SetConnTimer(); void UnsetConnTimer(); + void SetIdler(); + void UnsetIdler(); + + std::shared_ptr GetSharedPtr(); + gpointer CreateWeakPtr(); + static void DestroyWeakPtr(gpointer data); private: std::string port_name_; @@ -135,7 +142,8 @@ class Proxy { std::unique_ptr main_client_; std::unique_ptr delegate_client_; aul_rpc_port_watch_h watch_handle_ = nullptr; - guint conn_timer_ = 0; + gpointer conn_timer_data_ = nullptr; + gpointer idler_data_ = nullptr; mutable std::recursive_mutex mutex_; }; diff --git a/src/rpc-port.cc b/src/rpc-port.cc index 7340c2b..1410a04 100644 --- a/src/rpc-port.cc +++ b/src/rpc-port.cc @@ -250,9 +250,19 @@ RPC_API int rpc_port_proxy_create(rpc_port_proxy_h* h) { if (h == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; - auto p = new ::ProxyExt(); + auto p = new (std::nothrow) std::shared_ptr<::ProxyExt>( + new (std::nothrow) ::ProxyExt()); + if (p == nullptr) { + _E("Out of memory"); + } else if (p->get() == nullptr) { + _E("Out of memory"); + delete p; + p = nullptr; + } else { + _W("rpc_port_proxy_create(%p)", p->get()); + } + *h = p; - _W("rpc_port_proxy_create(%p)", p); return RPC_PORT_ERROR_NONE; } @@ -260,15 +270,16 @@ RPC_API int rpc_port_proxy_destroy(rpc_port_proxy_h h) { if (h == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; - auto p = static_cast<::ProxyExt*>(h); - _W("rpc_port_proxy_destroy(%p)", p); - p->SetDestroying(true); - p->DisconnectPort(); + auto p = static_cast*>(h); + auto* proxy = p->get(); + _W("rpc_port_proxy_destroy(%p)", proxy); + proxy->SetDestroying(true); + proxy->DisconnectPort(); g_idle_add_full(G_PRIORITY_HIGH, [](gpointer data) -> gboolean { - auto p = static_cast<::ProxyExt*>(data); - _W("rpc_port_proxy_destroy(%p)", p); + auto p = static_cast*>(data); + _W("rpc_port_proxy_destroy(%p)", p->get()); delete p; return G_SOURCE_REMOVE; }, h, nullptr); @@ -280,11 +291,11 @@ RPC_API int rpc_port_proxy_connect(rpc_port_proxy_h h, const char* appid, if (h == nullptr || appid == nullptr || port == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; - _W("rpc_port_proxy_connect(%p, %s, %s)", h, appid, port); - auto p = static_cast<::ProxyExt*>(h); - std::lock_guard lock(p->GetMutex()); - - return p->Connect(appid, port, p); + auto p = static_cast*>(h); + auto* proxy = p->get(); + _W("rpc_port_proxy_connect(%p, %s, %s)", proxy, appid, port); + std::lock_guard lock(proxy->GetMutex()); + return proxy->Connect(appid, port, proxy); } // LCOV_EXCL_START @@ -293,11 +304,11 @@ RPC_API int rpc_port_proxy_connect_sync(rpc_port_proxy_h h, const char* appid, if (h == nullptr || appid == nullptr || port == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; - _W("rpc_port_proxy_connect(%p, %s, %s)", h, appid, port); - auto p = static_cast<::ProxyExt*>(h); - std::lock_guard lock(p->GetMutex()); - - return p->ConnectSync(appid, port, p); + auto p = static_cast*>(h); + auto* proxy = p->get(); + _W("rpc_port_proxy_connect(%p, %s, %s)", proxy, appid, port); + std::lock_guard lock(proxy->GetMutex()); + return proxy->ConnectSync(appid, port, proxy); } // LCOV_EXCL_STOP @@ -306,10 +317,10 @@ RPC_API int rpc_port_proxy_add_connected_event_cb(rpc_port_proxy_h h, if (h == nullptr || cb == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; - auto p = static_cast<::ProxyExt*>(h); - std::lock_guard lock(p->GetMutex()); - - p->AddConnectedEventListener(cb, user_data); + auto p = static_cast*>(h); + auto* proxy = p->get(); + std::lock_guard lock(proxy->GetMutex()); + proxy->AddConnectedEventListener(cb, user_data); return RPC_PORT_ERROR_NONE; } @@ -318,10 +329,10 @@ RPC_API int rpc_port_proxy_add_disconnected_event_cb(rpc_port_proxy_h h, if (h == nullptr || cb == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; - auto p = static_cast<::ProxyExt*>(h); - std::lock_guard lock(p->GetMutex()); - - p->AddDisconnectedEventListener(cb, user_data); + auto p = static_cast*>(h); + auto* proxy = p->get(); + std::lock_guard lock(proxy->GetMutex()); + proxy->AddDisconnectedEventListener(cb, user_data); return RPC_PORT_ERROR_NONE; } @@ -330,10 +341,10 @@ RPC_API int rpc_port_proxy_add_rejected_event_cb(rpc_port_proxy_h h, if (h == nullptr || cb == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; - auto p = static_cast<::ProxyExt*>(h); - std::lock_guard lock(p->GetMutex()); - - p->AddRejectedEventListener(cb, user_data); + auto p = static_cast*>(h); + auto* proxy = p->get(); + std::lock_guard lock(proxy->GetMutex()); + proxy->AddRejectedEventListener(cb, user_data); return RPC_PORT_ERROR_NONE; } @@ -342,10 +353,10 @@ RPC_API int rpc_port_proxy_add_received_event_cb(rpc_port_proxy_h h, if (h == nullptr || cb == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; - auto p = static_cast<::ProxyExt*>(h); - std::lock_guard lock(p->GetMutex()); - - p->AddReceivedEventListener(cb, user_data); + auto p = static_cast*>(h); + auto* proxy = p->get(); + std::lock_guard lock(proxy->GetMutex()); + proxy->AddReceivedEventListener(cb, user_data); return RPC_PORT_ERROR_NONE; } @@ -354,19 +365,20 @@ RPC_API int rpc_port_proxy_get_port(rpc_port_proxy_h h, if (h == nullptr || port == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; - auto p = static_cast<::ProxyExt*>(h); - std::lock_guard lock(p->GetMutex()); + auto p = static_cast*>(h); + auto* proxy = p->get(); + std::lock_guard lock(proxy->GetMutex()); rpc_port_h ret_port; switch (type) { case RPC_PORT_PORT_MAIN: - ret_port = static_cast(p->GetPort().get()); + ret_port = static_cast(proxy->GetPort().get()); if (ret_port == nullptr) return RPC_PORT_ERROR_IO_ERROR; *port = ret_port; break; case RPC_PORT_PORT_CALLBACK: - ret_port = static_cast(p->GetDelegatePort().get()); + ret_port = static_cast(proxy->GetDelegatePort().get()); if (ret_port == nullptr) return RPC_PORT_ERROR_IO_ERROR; *port = ret_port; -- 2.7.4 From 9ddf51c68c268fdfa5cc8d15f4d4dd94b30893bb Mon Sep 17 00:00:00 2001 From: Changgyu Choi Date: Thu, 12 Aug 2021 10:03:16 +0900 Subject: [PATCH 16/16] Fix coding style Change-Id: I77493692e72af5b2d4af5ca1113ef3f04f608de5 Signed-off-by: Changgyu Choi --- src/ac-internal.cc | 2 ++ src/client-socket-internal.hh | 2 +- src/debug-port-internal.cc | 2 ++ src/debug-port-internal.hh | 1 + src/exception-internal.cc | 2 ++ src/port-internal.cc | 4 +++- src/port-internal.hh | 6 +++--- src/proxy-internal.cc | 2 ++ src/proxy-internal.hh | 2 +- src/request-internal.cc | 2 ++ src/response-internal.hh | 2 +- src/rpc-port.cc | 3 ++- src/server-socket-internal.hh | 2 +- src/stub-internal.cc | 5 ++++- utils/debug-port.cc | 1 + utils/logger.cc | 3 +-- utils/message.cc | 1 + 17 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/ac-internal.cc b/src/ac-internal.cc index a0b5e7a..3f3af65 100644 --- a/src/ac-internal.cc +++ b/src/ac-internal.cc @@ -20,6 +20,8 @@ #include #include +#include + #include "ac-internal.hh" #include "aul-internal.hh" #include "log-private.hh" diff --git a/src/client-socket-internal.hh b/src/client-socket-internal.hh index de7e960..2446e38 100644 --- a/src/client-socket-internal.hh +++ b/src/client-socket-internal.hh @@ -25,7 +25,7 @@ namespace internal { class ClientSocket { public: ClientSocket(); - ClientSocket(int fd); + explicit ClientSocket(int fd); virtual ~ClientSocket(); void Close(); diff --git a/src/debug-port-internal.cc b/src/debug-port-internal.cc index 8b28c77..ab660a3 100644 --- a/src/debug-port-internal.cc +++ b/src/debug-port-internal.cc @@ -20,6 +20,8 @@ #include #include +#include + #include "debug-port-internal.hh" #include "log-private.hh" diff --git a/src/debug-port-internal.hh b/src/debug-port-internal.hh index 98a3042..ac63f41 100644 --- a/src/debug-port-internal.hh +++ b/src/debug-port-internal.hh @@ -27,6 +27,7 @@ #include #include #include +#include #include "port-internal.hh" #include "shared-queue-internal.hh" diff --git a/src/exception-internal.cc b/src/exception-internal.cc index 0ee27f0..8e21f20 100644 --- a/src/exception-internal.cc +++ b/src/exception-internal.cc @@ -16,6 +16,8 @@ #include "exception-internal.hh" +#include + namespace rpc_port { namespace internal { diff --git a/src/port-internal.cc b/src/port-internal.cc index 79438f2..9ae6802 100644 --- a/src/port-internal.cc +++ b/src/port-internal.cc @@ -24,6 +24,8 @@ #include #include +#include + #include "include/rpc-port.h" #include "log-private.hh" #include "port-internal.hh" @@ -268,7 +270,7 @@ gboolean Port::OnEventReceived(gint fd, GIOCondition cond, void Port::ClearQueue() { std::lock_guard lock(mutex_); - while(queue_.empty() == false) + while (queue_.empty() == false) queue_.pop(); if (delay_src_id_ != 0) { diff --git a/src/port-internal.hh b/src/port-internal.hh index d6fc428..bda4d41 100644 --- a/src/port-internal.hh +++ b/src/port-internal.hh @@ -84,9 +84,9 @@ class Port { }; enum PortStatus { - PORT_STATUS_ERROR_NONE, - PORT_STATUS_ERROR_IO_ERROR, - PORT_STATUS_ERROR_RESOURCE_UNAVAILABLE + PORT_STATUS_ERROR_NONE, + PORT_STATUS_ERROR_IO_ERROR, + PORT_STATUS_ERROR_RESOURCE_UNAVAILABLE }; int PushDelayedMessage(std::shared_ptr dm); diff --git a/src/proxy-internal.cc b/src/proxy-internal.cc index f22c6ca..35abc75 100644 --- a/src/proxy-internal.cc +++ b/src/proxy-internal.cc @@ -21,6 +21,8 @@ #include #include +#include +#include #include "aul-internal.hh" #include "debug-port-internal.hh" diff --git a/src/proxy-internal.hh b/src/proxy-internal.hh index 414888f..5003539 100644 --- a/src/proxy-internal.hh +++ b/src/proxy-internal.hh @@ -87,7 +87,7 @@ class Proxy : public std::enable_shared_from_this { class Client : public ClientSocket { public: - Client(Proxy* parent); + explicit Client(Proxy* parent); virtual ~Client(); static Client* Create(Proxy* parent, const std::string& endpoint); diff --git a/src/request-internal.cc b/src/request-internal.cc index ef15ad5..af78026 100644 --- a/src/request-internal.cc +++ b/src/request-internal.cc @@ -16,6 +16,8 @@ #include "request-internal.hh" +#include + namespace rpc_port { namespace internal { diff --git a/src/response-internal.hh b/src/response-internal.hh index 4855b81..25227d3 100644 --- a/src/response-internal.hh +++ b/src/response-internal.hh @@ -25,7 +25,7 @@ namespace internal { class Response : public tizen_base::Parcelable { public: - Response(int result); + explicit Response(int result); Response(); ~Response(); diff --git a/src/rpc-port.cc b/src/rpc-port.cc index 1410a04..310cfbc 100644 --- a/src/rpc-port.cc +++ b/src/rpc-port.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include "include/rpc-port-internal.h" #include "include/rpc-port.h" @@ -47,7 +48,7 @@ class Event { class ProxyExt : public Proxy, public Proxy::IEventListener { public: - explicit ProxyExt() : Proxy(), destroying_(false) {} + ProxyExt() : Proxy(), destroying_(false) {} virtual ~ProxyExt() = default; void AddConnectedEventListener(rpc_port_proxy_connected_event_cb cb, diff --git a/src/server-socket-internal.hh b/src/server-socket-internal.hh index ae025ac..47ca970 100644 --- a/src/server-socket-internal.hh +++ b/src/server-socket-internal.hh @@ -24,7 +24,7 @@ namespace internal { class ServerSocket { public: - ServerSocket(int fd); + explicit ServerSocket(int fd); virtual ~ServerSocket(); bool IsClosed(); diff --git a/src/stub-internal.cc b/src/stub-internal.cc index 63cea83..553a9a6 100644 --- a/src/stub-internal.cc +++ b/src/stub-internal.cc @@ -20,6 +20,9 @@ #include #include +#include +#include + #include "aul-internal.hh" #include "debug-port-internal.hh" #include "include/rpc-port.h" @@ -222,7 +225,7 @@ gboolean Stub::OnSocketDisconnected(GIOChannel* channel, GIOCondition cond, } } - return G_SOURCE_REMOVE;; + return G_SOURCE_REMOVE; } void Stub::AddAcceptedPort(const std::string& sender_appid, diff --git a/utils/debug-port.cc b/utils/debug-port.cc index 7a5229b..202d9da 100644 --- a/utils/debug-port.cc +++ b/utils/debug-port.cc @@ -22,6 +22,7 @@ #include #include +#include #include #include "debug-port.hh" diff --git a/utils/logger.cc b/utils/logger.cc index 7bb1895..8d1608f 100644 --- a/utils/logger.cc +++ b/utils/logger.cc @@ -87,8 +87,7 @@ int Logger::Read(void* buf, unsigned int size) { return 0; } -rpc_port_parcel_h Logger::Read() -{ +rpc_port_parcel_h Logger::Read() { int size = 0; int ret = Read(reinterpret_cast(&size), sizeof(size)); if (ret < 0 || size <= 0) diff --git a/utils/message.cc b/utils/message.cc index 17fa647..47be341 100644 --- a/utils/message.cc +++ b/utils/message.cc @@ -20,6 +20,7 @@ #include #include #include +#include #include "message.hh" -- 2.7.4