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>
-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)
--- /dev/null
+# 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)
/*
- * 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__ */
-
-
-
/*
- * 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.
#endif
#endif /* __TIZEN_APPFW_RPC_PORT_PARCEL_INTERNAL_INCLUDE_H__ */
-
-
-
/*
- * 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.
/*
- * 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.
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
%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
--- /dev/null
+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"
+)
/*
- * 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));
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;
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;
}
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;
}
/*
- * 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 {
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 {
Cynara();
~Cynara();
- int FetchCredsFromDBus(GDBusConnection* connection, const char* sender);
+ int FetchCredsFromSocket(int fd);
int Check(const std::string& privilege) const;
private:
};
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:
} // namespace internal
} // namespace rpc_port
-#endif // AC_INTERNAL_H_
+#endif // AC_INTERNAL_HH_
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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_
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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_
/*
- * 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.
/*
- * 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.
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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_
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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_
/*
- * 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.
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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_
/*
- * 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
/*
- * 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 {
} // namespace internal
} // namespace rpc_port
-#endif // PORT_INTERNAL_H_
+#endif // PORT_INTERNAL_HH_
/*
- * 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;
_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
/*
- * 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 {
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_
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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_
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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_
--- /dev/null
+/*
+ * 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;
+}
/*
- * 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.
#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)
/*
- * 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
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,
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,
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;
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;
}
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,
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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_
/*
- * 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.
/*
- * 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;
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) {
}
}
-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,
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
/*
- * 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 {
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_
--- /dev/null
+ADD_SUBDIRECTORY(unit_tests)
--- /dev/null
+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)
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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_
--- /dev/null
+/*
+ * 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_
--- /dev/null
+/*
+ * 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_
--- /dev/null
+/*
+ * 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_;
--- /dev/null
+/*
+ * 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_
/*
- * 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);
}
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_);
}
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;
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);
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_);
}
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);
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);
}
/*
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);
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));
+++ /dev/null
-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)
-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)