Use Unix Domain Socket instead of Socket Pair 91/260091/27
authorHwankyu Jhun <h.jhun@samsung.com>
Fri, 18 Jun 2021 09:38:55 +0000 (18:38 +0900)
committerHwankyu Jhun <h.jhun@samsung.com>
Mon, 12 Jul 2021 04:39:11 +0000 (13:39 +0900)
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 <h.jhun@samsung.com>
62 files changed:
CMakeLists.txt
cmake/Modules/ApplyPkgConfig.cmake [new file with mode: 0644]
include/rpc-port-internal.h
include/rpc-port-parcel-internal.h
include/rpc-port-parcel.h
include/rpc-port.h
packaging/rpc-port.spec
src/CMakeLists.txt [new file with mode: 0644]
src/ac-internal.cc
src/ac-internal.hh
src/aul-internal.cc [new file with mode: 0644]
src/aul-internal.hh [new file with mode: 0644]
src/client-socket-internal.cc [new file with mode: 0644]
src/client-socket-internal.hh [new file with mode: 0644]
src/debug-port-internal.cc
src/debug-port-internal.hh
src/exception-internal.cc [new file with mode: 0644]
src/exception-internal.hh [new file with mode: 0644]
src/fdbroker-internal.cc [deleted file]
src/fdbroker-internal.hh [deleted file]
src/log-private.hh
src/peer-cred-internal.cc [new file with mode: 0644]
src/peer-cred-internal.hh [new file with mode: 0644]
src/port-internal.cc
src/port-internal.hh
src/proxy-internal.cc
src/proxy-internal.hh
src/request-internal.cc [new file with mode: 0644]
src/request-internal.hh [new file with mode: 0644]
src/response-internal.cc [new file with mode: 0644]
src/response-internal.hh [new file with mode: 0644]
src/rpc-port-internal.cc [new file with mode: 0644]
src/rpc-port-parcel.cc
src/rpc-port.cc
src/server-socket-internal.cc [new file with mode: 0644]
src/server-socket-internal.hh [new file with mode: 0644]
src/shared-queue-internal.hh
src/stub-internal.cc
src/stub-internal.hh
test/CMakeLists.txt [new file with mode: 0644]
test/unit_tests/CMakeLists.txt [new file with mode: 0644]
test/unit_tests/main.cc [moved from unit_tests/src/main.cc with 100% similarity]
test/unit_tests/mock/aul_mock.cc [new file with mode: 0644]
test/unit_tests/mock/aul_mock.hh [new file with mode: 0644]
test/unit_tests/mock/mock_hook.hh [new file with mode: 0644]
test/unit_tests/mock/module_mock.hh [new file with mode: 0644]
test/unit_tests/mock/test_fixture.cc [new file with mode: 0644]
test/unit_tests/mock/test_fixture.hh [new file with mode: 0644]
test/unit_tests/rpc_port_parcel_test.cc [moved from unit_tests/src/rpc_port_parcel_test.cc with 100% similarity]
test/unit_tests/rpc_port_test.cc [moved from unit_tests/src/rpc_port_test.cc with 54% similarity]
unit_tests/CMakeLists.txt [deleted file]
utils/CMakeLists.txt
utils/debug-port.cc [moved from utils/src/debug-port.cc with 100% similarity]
utils/debug-port.hh [moved from utils/src/debug-port.hh with 100% similarity]
utils/log-private.hh [moved from utils/src/log-private.hh with 100% similarity]
utils/logger.cc [moved from utils/src/logger.cc with 100% similarity]
utils/logger.hh [moved from utils/src/logger.hh with 100% similarity]
utils/main.cc [moved from utils/src/main.cc with 100% similarity]
utils/message.cc [moved from utils/src/message.cc with 100% similarity]
utils/message.hh [moved from utils/src/message.hh with 100% similarity]
utils/options.cc [moved from utils/src/options.cc with 100% similarity]
utils/options.hh [moved from utils/src/options.hh with 100% similarity]

index 7f93a11..78dbd01 100644 (file)
@@ -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 (file)
index 0000000..f4a262e
--- /dev/null
@@ -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)
index b370e0a..4ac06ca 100644 (file)
@@ -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.
 #ifndef __TIZEN_APPFW_RPC_PORT_INTERNAL_INCLUDE_H__
 #define __TIZEN_APPFW_RPC_PORT_INTERNAL_INCLUDE_H__
 
+#include <sys/types.h>
+#include <unistd.h>
+
 #include <rpc-port.h>
 
 #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__ */
-
-
-
index a4f8323..81e18c3 100644 (file)
@@ -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__ */
-
-
-
index 202086b..3b39802 100644 (file)
@@ -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.
index 93c9983..86b175d 100644 (file)
@@ -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.
index cef1a16..e13591a 100644 (file)
@@ -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 (file)
index 0000000..1061211
--- /dev/null
@@ -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"
+)
index 194f9fa..a0b5e7a 100644 (file)
@@ -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 <aul.h>
+#include <cynara-creds-socket.h>
+#include <cynara-error.h>
 #include <dlog.h>
 #include <pkgmgr-info.h>
-#include <cynara-error.h>
-#include <cynara-creds-gdbus.h>
 
 #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;
 }
 
index e870ec3..051a56d 100644 (file)
@@ -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.
  * limitations under the License.
  */
 
-#ifndef AC_INTERNAL_H_
-#define AC_INTERNAL_H_
+#ifndef AC_INTERNAL_HH_
+#define AC_INTERNAL_HH_
 
-#include <glib.h>
+#include <cynara-client.h>
 #include <gio/gio.h>
 #include <glib-unix.h>
-#include <cynara-client.h>
+#include <glib.h>
 
-#include <string>
-#include <vector>
 #include <map>
 #include <memory>
+#include <string>
+#include <vector>
 
 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 (file)
index 0000000..0dca700
--- /dev/null
@@ -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 <aul.h>
+#include <aul_rpc_port.h>
+
+#include <memory>
+
+#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<char, decltype(std::free)*> 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 (file)
index 0000000..4859109
--- /dev/null
@@ -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 <string>
+
+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 (file)
index 0000000..4fbb344
--- /dev/null
@@ -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 <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#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<struct sockaddr*>(&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<const unsigned char*>(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<unsigned char*>(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<void*>(&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<void*>(&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<void*>(&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<time_t>(timeout / 1000),
+    .tv_usec = static_cast<suseconds_t>((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 (file)
index 0000000..de7e960
--- /dev/null
@@ -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 <string>
+
+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_
index debd51e..0d89d5f 100644 (file)
@@ -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.
index caff4ac..27eb66b 100644 (file)
@@ -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 (file)
index 0000000..0ee27f0
--- /dev/null
@@ -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 (file)
index 0000000..4f52240
--- /dev/null
@@ -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 <exception>
+#include <string>
+
+#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 (file)
index 481a054..0000000
+++ /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 <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <aul.h>
-#include <aul_rpc_port.h>
-#include <dlog.h>
-
-#include <algorithm>
-
-#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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::weak_ptr<FdBroker>*>(user_data);
-  auto broker = ptr->lock();
-  if (broker == nullptr) {
-    _E("broker is nullptr");
-    return;
-  }
-
-  std::lock_guard<std::recursive_mutex> 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[] =
-    "<node>"
-    "  <interface name='";
-  static const char introspection_postfix[] =
-    "'>"
-    "  <method name='send_message'>"
-    "    <arg type='i' name='response' direction='out'/>"
-    "  </method>"
-    "  </interface>"
-    "</node>";
-  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<std::recursive_mutex> 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<std::weak_ptr<FdBroker>*>(user_data);
-  auto broker = ptr->lock();
-  if (broker == nullptr) {
-    _E("broker is nullptr");
-    return;
-  }
-
-  std::lock_guard<std::recursive_mutex> 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<std::weak_ptr<FdBroker>*>(user_data);
-  auto broker = ptr->lock();
-  if (broker == nullptr) {
-    _E("broker is nullptr");
-    return;
-  }
-
-  std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> 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<GDBusConnection*>(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<GDBusMessage, decltype(g_object_unref)*>(
-      reply, g_object_unref);
-  auto* ptr = static_cast<std::weak_ptr<FdBroker>*>(user_data);
-  auto broker = ptr->lock();
-  if (broker == nullptr) {
-    _E("broker is nullptr");
-    return;
-  }
-
-  std::lock_guard<std::recursive_mutex> 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<std::weak_ptr<FdBroker>*>(user_data);
-  auto broker = ptr->lock();
-  if (broker == nullptr) {
-    _E("broker is nullptr");
-    return G_SOURCE_REMOVE;
-  }
-
-  std::lock_guard<std::recursive_mutex> 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> FdBroker::GetSharedPtr() {
-  return shared_from_this();
-}
-
-gpointer FdBroker::CreateWeakPtr() {
-  auto* ptr = new (std::nothrow) std::weak_ptr<FdBroker>(GetSharedPtr());
-  return static_cast<gpointer>(ptr);
-}
-
-void FdBroker::DestroyWeakPtr(gpointer data) {
-  auto* ptr = static_cast<std::weak_ptr<FdBroker>*>(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 (file)
index 01dc6d0..0000000
+++ /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 <glib.h>
-#include <gio/gio.h>
-#include <gio/gunixfdlist.h>
-#include <glib-unix.h>
-
-#include <map>
-#include <memory>
-#include <mutex>
-#include <string>
-#include <thread>
-#include <list>
-
-#include "ac-internal.hh"
-#include "rpc-port.h"
-
-namespace rpc_port {
-namespace internal {
-
-class FdBroker : public std::enable_shared_from_this<FdBroker> {
- 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<std::string, FdBroker::IEventListener*> 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<FdBroker> 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_
index 6c6b2d6..36aeb9c 100644 (file)
@@ -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 (file)
index 0000000..eebc131
--- /dev/null
@@ -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 <sys/socket.h>
+#include <sys/types.h>
+
+#include <new>
+
+#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<void*>(&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 (file)
index 0000000..bf57ed5
--- /dev/null
@@ -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_
index 1c939da..79438f2 100644 (file)
@@ -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 <sys/socket.h>
-#include <stdlib.h>
-#include <stdio.h>
+#include <aul_rpc_port.h>
+#include <dlog.h>
+#include <glib-unix.h>
 #include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
 #include <unistd.h>
 #include <uuid/uuid.h>
-#include <dlog.h>
-#include <aul_rpc_port.h>
-#include <glib-unix.h>
 
+#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
index 0286304..d6fc428 100644 (file)
@@ -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.
  * limitations under the License.
  */
 
-#ifndef PORT_INTERNAL_H_
-#define PORT_INTERNAL_H_
+#ifndef PORT_INTERNAL_HH_
+#define PORT_INTERNAL_HH_
 
-#include <thread>
+#include <gio/gio.h>
+
+#include <algorithm>
+#include <atomic>
+#include <memory>
 #include <mutex>
+#include <queue>
 #include <string>
-#include <memory>
-#include <atomic>
+#include <thread>
 #include <vector>
-#include <queue>
-#include <algorithm>
-#include <gio/gio.h>
 
 namespace rpc_port {
 namespace internal {
@@ -107,4 +108,4 @@ class Port {
 }  // namespace internal
 }  // namespace rpc_port
 
-#endif  // PORT_INTERNAL_H_
+#endif  // PORT_INTERNAL_HH_
index cac8637..9f7ac7c 100644 (file)
 /*
- * 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 <aul_svc.h>
 #include <dlog.h>
 #include <sys/socket.h>
 #include <sys/types.h>
+#include <uuid.h>
+
+#include <memory>
 
+#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<Proxy*>(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&>(request));
+  const std::vector<uint8_t>& raw = parcel.GetRaw();
+  size_t size = raw.size();
+  int ret = client->Send(reinterpret_cast<void*>(&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<Proxy*>(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<void*>(&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<uint8_t> 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<std::recursive_mutex> lock(GetMutex());
+  _D("Proxy::~Proxy()");
+  listener_ = nullptr;
+  UnsetConnTimer();
+  Cancel();
+}
 
+int Proxy::Connect(bool sync) {
+  std::lock_guard<std::recursive_mutex> 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> 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> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> lock(GetMutex());
   if (main_port_.get() != nullptr) {
     DebugPort::GetInst().RemoveSession(main_port_->GetFd());
     main_port_.reset();
   }
 }
 
+int Proxy::Watch() {
+  std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<Proxy*>(user_data);
+  std::lock_guard<std::recursive_mutex> 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<Proxy*>(user_data);
+  std::lock_guard<std::recursive_mutex> 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<GIOCondition>(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<GIOCondition>(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<Proxy*>(user_data);
+  std::lock_guard<std::recursive_mutex> 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<Proxy*>(user_data);
+  std::lock_guard<std::recursive_mutex> 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<Proxy::Client> 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<GIOCondition>(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<GIOCondition>(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<Proxy*>(user_data);
+  std::lock_guard<std::recursive_mutex> 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<Proxy*>(user_data);
+  std::lock_guard<std::recursive_mutex> 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> 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> 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
index 64a824c..df0fbcb 100644 (file)
@@ -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.
  * limitations under the License.
  */
 
-#ifndef PROXY_INTERNAL_H_
-#define PROXY_INTERNAL_H_
+#ifndef PROXY_INTERNAL_HH_
+#define PROXY_INTERNAL_HH_
 
+#include <aul_rpc_port.h>
 #include <glib.h>
 #include <gio/gio.h>
 #include <glib-unix.h>
 
 #include <string>
 #include <memory>
+#include <mutex>
 
-#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<ProxyPort> main_port_;
   std::shared_ptr<ProxyPort> delegate_port_;
   IEventListener* listener_ = nullptr;
-  std::shared_ptr<FdBroker> fd_broker_;
   std::string target_appid_;
   std::string real_appid_;
   int fds_[2];
+  std::unique_ptr<Client> main_client_;
+  std::unique_ptr<Client> 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 (file)
index 0000000..ef15ad5
--- /dev/null
@@ -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 (file)
index 0000000..bd72505
--- /dev/null
@@ -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 <parcel.hh>
+#include <parcelable.hh>
+
+#include <string>
+
+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 (file)
index 0000000..3583dde
--- /dev/null
@@ -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 (file)
index 0000000..4855b81
--- /dev/null
@@ -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 <parcel.hh>
+#include <parcelable.hh>
+
+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 (file)
index 0000000..a8c5569
--- /dev/null
@@ -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 <sys/types.h>
+#include <tzplatform_config.h>
+#include <unistd.h>
+
+#include <atomic>
+
+#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<uid_t> __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;
+}
index 625bbd9..424d781 100644 (file)
@@ -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 <memory>
 
+#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)
 
index 04e20c8..ca708d8 100644 (file)
@@ -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 <aul.h>
+#include <aul_rpc_port.h>
 #include <glib.h>
 
 #include <atomic>
 #include <mutex>
 #include <thread>
 
+#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<std::recursive_mutex> 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 (file)
index 0000000..228e75b
--- /dev/null
@@ -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 <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#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<struct sockaddr*>(&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 (file)
index 0000000..ae025ac
--- /dev/null
@@ -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_
index 2ea1a87..4cd0d95 100644 (file)
@@ -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.
index df41588..8a038c4 100644 (file)
 /*
- * 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 <sys/types.h>
-#include <sys/socket.h>
-#include <dlog.h>
 #include <aul.h>
 #include <aul_rpc_port.h>
+#include <dlog.h>
+#include <sys/socket.h>
+#include <sys/types.h>
 
+#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<void*>(&size), sizeof(size));
+  if (ret != 0) {
+    _E("Receive() is failed. error(%d)", ret);
+    return -1;
+  }
+
+  std::vector<uint8_t> 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&>(response));
+  const std::vector<uint8_t>& raw = parcel.GetRaw();
+  size_t size = raw.size();
+  int ret = client->Send(reinterpret_cast<void*>(&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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> lock(GetMutex());
+  access_controller_.AddPrivilege(privilege);
 }
 
 void Stub::SetTrusted(const bool trusted) {
-  AccessController& ac = fd_broker_->GetAccessController();
-  ac.SetTrusted(trusted);
+  std::lock_guard<std::recursive_mutex> lock(GetMutex());
+  access_controller_.SetTrusted(trusted);
 }
 
 std::shared_ptr<Port> Stub::FindPort(const std::string& instance) const {
+  std::lock_guard<std::recursive_mutex> lock(GetMutex());
   for (auto& p : ports_) {
     if (p->GetInstance() == instance && !p->IsDelegate()) {
       return p;
@@ -66,16 +134,22 @@ std::shared_ptr<Port> Stub::FindPort(const std::string& instance) const {
 
 std::shared_ptr<Port> Stub::FindDelegatePort(
     const std::string& instance) const {
+  std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> 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<Stub*>(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<Stub*>(user_data);
+  std::lock_guard<std::recursive_mutex> 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<Stub*>(data);
-  int fd = g_io_channel_unix_get_fd(gio);
+gboolean Stub::OnSocketDisconnected(GIOChannel* channel, GIOCondition cond,
+    gpointer user_data) {
+  auto* stub = static_cast<Stub*>(user_data);
+  std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> 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<GIOCondition>(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<GIOCondition>(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<GIOCondition>(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<Stub*>(user_data);
+  std::lock_guard<std::recursive_mutex> lock(stub->GetMutex());
+  if (stub->server_.get() == nullptr) {
+    _E("Invalid context");
+    return G_SOURCE_REMOVE;
+  }
+
+  std::unique_ptr<ClientSocket> 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> request_auto(request);
+  std::unique_ptr<PeerCred> 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
index bc562df..28114cc 100644 (file)
@@ -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.
  * limitations under the License.
  */
 
-#ifndef STUB_INTERNAL_H_
-#define STUB_INTERNAL_H_
+#ifndef STUB_INTERNAL_HH_
+#define STUB_INTERNAL_HH_
 
 #include <glib.h>
 #include <gio/gio.h>
 #include <glib-unix.h>
 
-#include <string>
 #include <list>
 #include <memory>
+#include <mutex>
+#include <string>
 
+#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<Port> FindPort(const std::string& instance) const;
   std::shared_ptr<Port> 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<std::shared_ptr<AcceptedPort>> ports_;
   IEventListener* listener_ = nullptr;
-  std::shared_ptr<FdBroker> fd_broker_;
-  std::string port_name_;
+  std::unique_ptr<Server> 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 (file)
index 0000000..c90fac8
--- /dev/null
@@ -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 (file)
index 0000000..a476e73
--- /dev/null
@@ -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/test/unit_tests/mock/aul_mock.cc b/test/unit_tests/mock/aul_mock.cc
new file mode 100644 (file)
index 0000000..2fce77b
--- /dev/null
@@ -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 (file)
index 0000000..33a26b4
--- /dev/null
@@ -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 <aul.h>
+#include <aul_rpc_port.h>
+#include <aul_svc.h>
+#include <bundle.h>
+#include <gmock/gmock.h>
+#include <sys/types.h>
+
+#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 (file)
index 0000000..2980460
--- /dev/null
@@ -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<MOCK_CLASS>().f()
+#define MOCK_HOOK_P1(MOCK_CLASS, f, p1)                                        \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1)
+#define MOCK_HOOK_P2(MOCK_CLASS, f, p1, p2)                                    \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1, p2)
+#define MOCK_HOOK_P3(MOCK_CLASS, f, p1, p2, p3)                                \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1, p2, p3)
+#define MOCK_HOOK_P4(MOCK_CLASS, f, p1, p2, p3, p4)                            \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1, p2, p3, p4)
+#define MOCK_HOOK_P5(MOCK_CLASS, f, p1, p2, p3, p4, p5)                        \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1, p2, p3, p4, p5)
+#define MOCK_HOOK_P6(MOCK_CLASS, f, p1, p2, p3, p4, p5, p6)                    \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1, p2, p3, p4, p5, p6)
+#define MOCK_HOOK_P7(MOCK_CLASS, f, p1, p2, p3, p4, p5, p6, p7)                \
+    TestFixture::GetMock<MOCK_CLASS>().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<MOCK_CLASS>().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<MOCK_CLASS>().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 (file)
index 0000000..a79584e
--- /dev/null
@@ -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 (file)
index 0000000..23f907d
--- /dev/null
@@ -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 <memory>
+
+#include "unit_tests/mock/test_fixture.hh"
+
+std::unique_ptr<ModuleMock> TestFixture::mock_;
diff --git a/test/unit_tests/mock/test_fixture.hh b/test/unit_tests/mock/test_fixture.hh
new file mode 100644 (file)
index 0000000..8351374
--- /dev/null
@@ -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 <gtest/gtest.h>
+
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <utility>
+
+#include "unit_tests/mock/module_mock.hh"
+
+class TestFixture : public ::testing::Test {
+ public:
+  explicit TestFixture(std::unique_ptr<ModuleMock> mock) {
+    mock_ = std::move(mock);
+  }
+
+  virtual ~TestFixture() {}
+
+  virtual void SetUp() {}
+  virtual void TearDown() {}
+
+  template <typename T>
+  static T& GetMock() {
+    auto ptr = dynamic_cast<T*>(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<ModuleMock> mock_;
+};
+
+#endif  // UNIT_TESTS_MOCK_TEST_FIXTURE_HH_
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 (file)
 /*
- * 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 <gtest/gtest.h>
+#include <errno.h>
+#include <glib.h>
 #include <gmock/gmock.h>
-#include <iostream>
+#include <gtest/gtest.h>
 #include <stdbool.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <iostream>
 #include <stdexcept>
-#include <glib.h>
+#include <memory>
+#include <thread>
+
+#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<WatchInfo> test_port_handle;
+std::unique_ptr<WatchInfo> 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<struct sockaddr*>(&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<char, decltype(std::free)*> 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<char, decltype(std::free)*> port_path_auto(
+      port_path, std::free);
+  unlink(port_path);
+  return 0;
+}
+
+}  // namespace
+
+class Mocks : public ::testing::NiceMock<AulMock> {};
+
+class RpcPortBase : public TestFixture {
+ public:
+  RpcPortBase() : TestFixture(std::make_unique<Mocks>()) {}
+  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<AulMock>(),
+        aul_app_get_appid_bypid(_, _, _))
+            .WillRepeatedly(Invoke(FakeAulAppGetAppIdByPid));
+    EXPECT_CALL(GetMock<AulMock>(),
+        aul_rpc_port_usr_get_path(_, _, _, _))
+            .WillRepeatedly(Invoke(FakeAulRpcPortUsrGetPath));
+    EXPECT_CALL(GetMock<AulMock>(),
+        aul_rpc_port_usr_prepare_stub(_, _, _))
+            .WillRepeatedly(Invoke(FakeAulRpcPortUsrPrepareStub));
+    EXPECT_CALL(GetMock<AulMock>(),
+        aul_rpc_port_usr_exist(_, _, _, _))
+            .WillRepeatedly(Invoke(FakeAulRpcPortUsrExist));
+    EXPECT_CALL(GetMock<AulMock>(),
+        aul_rpc_port_notify_rpc_finished())
+            .WillRepeatedly(Invoke(FakeAulRpcPortNotifyRpcFinished));
+    EXPECT_CALL(GetMock<AulMock>(),
+        aul_rpc_port_usr_add_watch(_, _, _, _, _, _, _))
+            .WillRepeatedly(Invoke(FakeAulRpcPortUsrAddWatch));
+    EXPECT_CALL(GetMock<AulMock>(),
+        aul_rpc_port_remove_watch(_))
+            .WillRepeatedly(Invoke(FakeAulRpcPortRemoveWatch));
+    EXPECT_CALL(GetMock<AulMock>(),
+        aul_svc_get_appid_by_alias_appid(_, _))
+            .WillRepeatedly(Invoke(FakeAulSvcGetAppIdByAliasAppId));
+    EXPECT_CALL(GetMock<AulMock>(),
+        aul_rpc_port_usr_create(_, _, _))
+            .WillRepeatedly(Invoke(FakeAulRpcPortUsrCreate));
+    EXPECT_CALL(GetMock<AulMock>(),
+        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<RpcPortConnection*>(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<RpcPortBase*>(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<RpcPortBase*>(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<RpcPortBase*>(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<RpcPortBase*>(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<RpcPortBase*>(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 (file)
index dac0b21..0000000
+++ /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)
index c639ff2..6353206 100644 (file)
@@ -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)
similarity index 100%
rename from utils/src/debug-port.cc
rename to utils/debug-port.cc
similarity index 100%
rename from utils/src/debug-port.hh
rename to utils/debug-port.hh
similarity index 100%
rename from utils/src/logger.cc
rename to utils/logger.cc
similarity index 100%
rename from utils/src/logger.hh
rename to utils/logger.hh
similarity index 100%
rename from utils/src/main.cc
rename to utils/main.cc
similarity index 100%
rename from utils/src/message.cc
rename to utils/message.cc
similarity index 100%
rename from utils/src/message.hh
rename to utils/message.hh
similarity index 100%
rename from utils/src/options.cc
rename to utils/options.cc
similarity index 100%
rename from utils/src/options.hh
rename to utils/options.hh