Add Component Port API 80/249880/22
authorHwankyu Jhun <h.jhun@samsung.com>
Thu, 17 Dec 2020 07:25:22 +0000 (16:25 +0900)
committerHwankyu Jhun <h.jhun@samsung.com>
Wed, 30 Dec 2020 06:03:27 +0000 (15:03 +0900)
The component-based-port package is added. The package is for providing
IPC between components. If the component creates a port.
"/run/aul/port/<uid>/.<port_name>-port" is created.
The other component can exchange data using a port name as a destination.

Requires:
 - https://review.tizen.org/gerrit/#/c/platform/core/appfw/aul-1/+/250180/
 - https://review.tizen.org/gerrit/#/c/platform/core/appfw/amd/+/250187/
 - https://review.tizen.org/gerrit/#/c/platform/core/appfw/launchpad/+/250199/

Change-Id: I55379eb4da77ec453911ef87f96b1e6a8e1acbbf
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
33 files changed:
component_based/CMakeLists.txt
component_based/port/CMakeLists.txt [new file with mode: 0644]
component_based/port/api/component_port.h [new file with mode: 0644]
component_based/port/client.cc [new file with mode: 0644]
component_based/port/client.hh [new file with mode: 0644]
component_based/port/component-based-port.pc.in [new file with mode: 0644]
component_based/port/exception.hh [new file with mode: 0644]
component_based/port/export_api.hh [new file with mode: 0644]
component_based/port/log_private.hh [new file with mode: 0644]
component_based/port/main_loop.cc [new file with mode: 0644]
component_based/port/main_loop.hh [new file with mode: 0644]
component_based/port/peer_creds.cc [new file with mode: 0644]
component_based/port/peer_creds.hh [new file with mode: 0644]
component_based/port/port.cc [new file with mode: 0644]
component_based/port/port.hh [new file with mode: 0644]
component_based/port/port_implementation.hh [new file with mode: 0644]
component_based/port/privilege_checker.cc [new file with mode: 0644]
component_based/port/privilege_checker.hh [new file with mode: 0644]
component_based/port/request.cc [new file with mode: 0644]
component_based/port/request.hh [new file with mode: 0644]
component_based/port/response.cc [new file with mode: 0644]
component_based/port/response.hh [new file with mode: 0644]
component_based/port/sender_info.cc [new file with mode: 0644]
component_based/port/sender_info.hh [new file with mode: 0644]
component_based/port/server.cc [new file with mode: 0644]
component_based/port/server.hh [new file with mode: 0644]
component_based/port/socket.cc [new file with mode: 0644]
component_based/port/socket.hh [new file with mode: 0644]
component_based/port/stub.cc [new file with mode: 0644]
component_based/port/util.cc [new file with mode: 0644]
component_based/port/util.hh [new file with mode: 0644]
packaging/component-based-port.manifest [new file with mode: 0644]
packaging/component-based.spec

index 4c72b7fd77671e0c4aef64e41876edfbd0a5dcdd..9af8cbcea52217e78715dfd10b2dcd6093c57400 100644 (file)
@@ -6,6 +6,7 @@ ADD_SUBDIRECTORY(base)
 ADD_SUBDIRECTORY(efl_base)
 ADD_SUBDIRECTORY(widget_base)
 ADD_SUBDIRECTORY(efl_widget_base)
+ADD_SUBDIRECTORY(port)
 
 ADD_DEPENDENCIES(component-based-app-control component-based-uri)
 ADD_DEPENDENCIES(component-based-core-base component-based-app-control)
diff --git a/component_based/port/CMakeLists.txt b/component_based/port/CMakeLists.txt
new file mode 100644 (file)
index 0000000..0c42c5e
--- /dev/null
@@ -0,0 +1,53 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+PROJECT(component-based-port CXX)
+
+SET(PREFIX "${CMAKE_INSTALL_PREFIX}")
+SET(EXEC_PREFIX "\${prefix}")
+SET(PROJECT_NAME "${PROJECT_NAME}")
+SET(LIBDIR ${LIB_INSTALL_DIR})
+SET(INCLUDEDIR "\${prefix}/include")
+SET(VERSION ${FULLVER})
+
+INCLUDE(FindPkgConfig)
+
+SET(requires "glib-2.0 gio-2.0 dlog parcel cynara-client cynara-creds-socket aul")
+
+pkg_check_modules(component-based-port REQUIRED ${requires})
+
+FOREACH(flag ${component-based-port_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++14")
+SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_CXX_FLAGS_RELEASE "-O2")
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../../)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../)
+
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} SOURCES)
+ADD_LIBRARY (${PROJECT_NAME} SHARED ${SOURCES})
+SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES VERSION ${FULLVER})
+SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${MAJORVER})
+
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${component-based-port_LDFLAGS} -lpthread)
+
+SET(PC_NAME component-based-port)
+SET(PC_REQUIRED ${pc_requires})
+
+CONFIGURE_FILE(${PROJECT_NAME}.pc.in ${PROJECT_NAME}.pc @ONLY)
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR})
+INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/api/component_port.h
+  DESTINATION ${INCLUDE_INSTALL_DIR}/component_based/port/api)
+
+SET(HEADER_PORT
+  export_api.hh
+  port.hh
+)
+
+FOREACH(hfile ${HEADER_PORT})
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${hfile}
+  DESTINATION ${INCLUDE_INSTALL_DIR}/component_based/port)
+ENDFOREACH(hfile)
diff --git a/component_based/port/api/component_port.h b/component_based/port/api/component_port.h
new file mode 100644 (file)
index 0000000..b9378b1
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 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 __COMPONENT_PORT_H__
+#define __COMPONRNT_PORT_H__
+
+#include <parcel.h>
+
+/**
+ * @addtogroup COMPONENT_BASED_APPLICATION_MODULE
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief The component port handle.
+ * @since_tizen 6.5
+ */
+typedef void *component_port_h;
+
+/**
+ * @brief Enumeration for error codes for the component port.
+ * @since_tizen 6.5
+ */
+typedef enum {
+       COMPONENT_PORT_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */
+       COMPONENT_PORT_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */
+       COMPONENT_PORT_ERROR_IO_ERROR = TIZEN_ERROR_IO_ERROR, /**< I/O Error */
+       COMPONENT_PORT_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory */
+       COMPONENT_PORT_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< Permission denied */
+} component_port_error_e;
+
+/**
+ * @brief Called when the port received the request.
+ * @details The function is called when the port received the request from the other port.
+ *          The @a request MUST NOT release using parcel_destroy(). It's managed by Platform.
+ * @since_tizen 6.5
+ * @param[in] sender The name of the sender
+ * @param[in] request The request data
+ * @param[in] user_data The user data passed from the registration function
+ * @see component_port_set_request_cb()
+ */
+typedef void (*component_port_request_cb)(const char *sender, parcel_h request, void *user_data);
+
+/**
+ * @brief Called when the port received the request synchronously.
+ * @details The function is called when the port received the request from the other port.
+ *          The @a response data should be set.
+ *          The @a request and @a response MUST NOT release using parcel_destroy(). The parameters are managed by Platform.
+ * @since_tizen 6.5
+ * @param[in] sender The name of the sender
+ * @param[in] request The request data
+ * @param[out] response the response data
+ * @param[in] user_data The user data passed from the registration function
+ * @see component_port_set_sync_request_cb()
+ */
+typedef void (*component_port_sync_request_cb)(const char *sender, parcel_h request, parcel_h response, void *user_data);
+
+/**
+ * @brief Creates the component port handle.
+ * @since_tizen 6.5
+ * @param[in] port_name The port name
+ * @param[out] port The component port handle
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #COMPONENT_PORT_ERROR_NONE Successful
+ * @retval #COMPONENT_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #COMPONENT_PORT_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #COMPONENT_PORT_ERROR_IO_ERROR I/O Error
+ * @see component_port_destroy()
+ */
+int component_port_create(const char *port_name, component_port_h *port);
+
+/**
+ * @brief Destroys the component port handle.
+ * @since_tizen 6.5
+ * @param[in] port The component port handle
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #COMPONENT_PORT_ERROR_NONE Successful
+ * @retval #COMPONENT_PORT_ERROR_INVALID_PARAMETER Invalid prameter
+ * @see component_port_create()
+ */
+int component_port_destroy(component_port_h port);
+
+/**
+ * @brief Sets the request callback function to the component port handle.
+ * @details The callback function is called when a component sends the request using component_port_send().
+ * @since_tizen 6.5
+ * @param[in] port The component port handle
+ * @param[in] callback The callback function to invoke
+ * @param[in] user_data The user data to be passed to the callback function
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #COMPONENT_PORT_ERROR_NONE Successful
+ * @retval #COMPONENT_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @see component_port_request_cb()
+ * @see component_port_send()
+ */
+int component_port_set_request_cb(component_port_h port, component_port_request_cb callback, void *user_data);
+
+/**
+ * @brief Sets the synchornous request callback function to the component port handle.
+ * @detials The callback function is called when a component sends the request using comopnent_port_send_sync().
+ * @since_tizen 6.5
+ * @param[in] port The component port handle
+ * @param[in] callback The callback function to invoke
+ * @param[in] useR_data The user data to be passed to the callback function
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #COMPONENT_PORT_ERROR_NONE Successful
+ * @retval #COMPONENT_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @see component_port_sync_request_cb()
+ */
+int component_port_set_sync_request_cb(component_port_h port, component_port_sync_request_cb callback, void *user_data);
+
+/**
+ * @brief Adds a privilege to the component port handle.
+ * @details When a component sends the request, the privilege will be checked.
+ *          If the sender doesn't have a permission, the request will be rejected.
+ * @since_tizen 6.5
+ * @param[in] port The component port handle
+ * @param[in] privilege The privilege
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #COMPONENT_PORT_ERROR_NONE Successful
+ * @retval #COMPONENT_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @see component_port_sync_request_cb()
+ */
+int component_port_add_privilege(component_port_h port, const char *privilege);
+
+/**
+ * @brief Waits for events on the component port.
+ * @details This function runs a main loop until component_port_cancel() is called.
+ * @since_tizen 6.5
+ * @param[in] port The component port handle
+ * @see component_port_cancel()
+ * @see get_last_result()
+ */
+void component_port_wait_for_event(component_port_h port);
+
+/**
+ * @brief Cancels waiting for events on the component port.
+ * @since_tizen 6.5
+ * @param[in] port The component port handle
+ * @see component_port_wait_for_event()
+ * @see get_last_result()
+ */
+void component_port_cancel(component_port_h port);
+
+/**
+ * @brief Sends the request data.
+ * @details Specifying a negative value or a zero value in @a timeout means an infinite timeout.
+ * @since_tizen 6.5
+ * @param[in] port The component port handle
+ * @param[in] endpoint The endpoint name
+ * @param[in] timeout The interval of milliseconds
+ * @param[in] request The request data
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #COMPONENT_PORT_ERROR_NONE Successful
+ * @retval #COMPONENT_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #COMPONENT_PORT_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #COMPONENT_PORT_ERROR_IO_ERRO I/O error
+ * @retval #COMPONENT_PORT_ERROR_PERMISSION_DENIED Permission denied
+ */
+int component_port_send(component_port_h port, const char *endpoint, int timeout, parcel_h request);
+
+/**
+ * @breif Sends the request data synchrnously.
+ * @details Specifying a negative value or a zero value in @a timeout means an infinite timeout.
+ * @details The @a response should be destroyed using parcel_destroy() if it is no longer needed.
+ * @since_tizen 6.5
+ * @param[in] port The component port handle
+ * @param[in] endpoint The endpoint name
+ * @param[in] timeout The interval of milliseconds
+ * @param[in] request The request data
+ * @param[out] response The response data
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #COMPONENT_PORT_ERROR_NONE Successful
+ * @retval #COMPONENT_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #COMPONENT_PORT_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #COMPONENT_PORT_ERROR_IO_ERRO I/O error
+ * @retval #COMPONENT_PORT_ERROR_PERMISSION_DENIED Permission denied
+ */
+int component_port_send_sync(component_port_h port, const char *endpoint, int timeout, parcel_h request, parcel_h *response);
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @}
+ */
+
+#endif /* __COMPONENT_PORT_H__ */
diff --git a/component_based/port/client.cc b/component_based/port/client.cc
new file mode 100644 (file)
index 0000000..47d1454
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include <aul_component_port.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <tizen.h>
+#include <unistd.h>
+
+#include "component_based/port/client.hh"
+#include "component_based/port/log_private.hh"
+#include "component_based/port/util.hh"
+
+namespace component_based {
+
+Client::Client(int fd, pid_t pid) : Socket(fd), pid_(pid) {
+}
+
+Client::~Client() {
+}
+
+Client* Client::Create(const std::string& name, int timeout) {
+  std::string path = Socket::GetSocketPath(name);
+  bool exist = false;
+  aul_component_port_exist(name.c_str(), &exist);
+  if (!exist) {
+    _E("port(%s) doesn't exist", name.c_str());
+    return nullptr;
+  }
+
+  int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+  if (fd < 0) {
+    _E("socket() is failed. path(%s), errno(%d)", path.c_str(), errno);
+    return nullptr;
+  }
+
+  int retry = 3;
+  struct sockaddr_un addr = { 0, };
+  addr.sun_family = AF_UNIX;
+  snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path.c_str());
+  struct sockaddr* addr_ptr = reinterpret_cast<struct sockaddr*>(&addr);
+  while (connect(fd, addr_ptr, sizeof(addr)) < 0) {
+    if (errno != ETIMEDOUT || retry <= 0) {
+      _E("connect() is failed. path(%s), errno(%d)", path.c_str(), errno);
+      close(fd);
+      return nullptr;
+    }
+
+    usleep(100 * 1000);
+    retry--;
+    _W("Retry to connect to %s. count(%d)", path.c_str(), retry);
+  }
+
+  if (timeout > 0) {
+    time_t sec = timeout / 1000;
+    suseconds_t usec = (timeout - sec * 1000) * 1000;
+    struct timeval tv = { sec, usec };
+    int ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+    if (ret < 0) {
+      _E("setsockopt(SO_RCVTIMEO) is failed. fd(%d), errno(%d)", fd, errno);
+      close(fd);
+      return nullptr;
+    }
+  }
+
+  return new (std::nothrow) Client(fd);
+}
+
+int Client::Send(const std::vector<uint8_t>& data) {
+  size_t size = data.size();
+  auto* p = reinterpret_cast<void*>(&size);
+  int ret = Socket::Send(p, sizeof(size));
+  if (ret != 0) {
+    _E("Send() is failed. error(%d)", ret);
+    return ret;
+  }
+
+  auto* dp = reinterpret_cast<const void*>(&data[0]);
+  ret = Socket::Send(dp, data.size());
+  if (ret != 0)
+    _E("Send() is failed. error(%d)", ret);
+
+  if (getenv("PORT_DEBUG"))
+    Util::Hexdump("Send", data);
+  return ret;
+}
+
+int Client::Recv(std::vector<uint8_t>& data) {
+  size_t size = 0;
+  auto* p = reinterpret_cast<void*>(&size);
+  int ret = Socket::Read(p, sizeof(size));
+  if (ret != 0) {
+    _E("Read() is failed. error(%d)", ret);
+    return ret;
+  }
+
+  std::vector<uint8_t> buf(size);
+  p = reinterpret_cast<void*>(&buf[0]);
+  ret = Socket::Read(p, size);
+  if (ret != 0) {
+    _E("Read() is failed. error(%d)", ret);
+    return ret;
+  }
+
+  std::copy(buf.begin(), buf.end(), std::back_inserter(data));
+  if (getenv("PORT_DEBUG"))
+    Util::Hexdump("Recv", data);
+  return ret;
+}
+
+pid_t Client::GetPid() const {
+  return pid_;
+}
+
+}  // namespace component_based
diff --git a/component_based/port/client.hh b/component_based/port/client.hh
new file mode 100644 (file)
index 0000000..5576853
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 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 COMPONENT_BASED_PORT_CLIENT_HH_
+#define COMPONENT_BASED_PORT_CLIENT_HH_
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include "component_based/port/socket.hh"
+
+namespace component_based {
+
+class Client : public Socket {
+ public:
+  Client(int fd, pid_t pid = -1);
+  virtual ~Client();
+
+  static Client* Create(const std::string& name, int timeout = 0);
+
+  int Send(const std::vector<uint8_t>& data);
+  int Recv(std::vector<uint8_t>& data);
+
+  pid_t GetPid() const;
+
+ private:
+  pid_t pid_ = -1;
+};
+
+}  // namespace component_based
+
+#endif  // COMPONENT_BASED_PORT_CLIENT_HH_
diff --git a/component_based/port/component-based-port.pc.in b/component_based/port/component-based-port.pc.in
new file mode 100644 (file)
index 0000000..d484b6f
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@PREFIX@
+exec_prefix=@EXEC_PREFIX@
+libdir=@LIB_INSTALL_DIR@
+includedir=@INCLUDE_INSTALL_DIR@
+
+Name: @PC_NAME@
+Description: Support development of the Tizen Component-based App Model port
+Version: @VERSION@
+Requires: @PC_REQUIRED@
+Libs: -L${libdir} -lcomponent-based-port
+Cflags: -I${includedir} -I${includedir}/appfw -I${includedir}/component_based
diff --git a/component_based/port/exception.hh b/component_based/port/exception.hh
new file mode 100644 (file)
index 0000000..4539f21
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 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 COMPONENT_BASED_PORT_EXCEPTION_HH_
+#define COMPONENT_BASED_PORT_EXCEPTION_HH_
+
+#include <string>
+#include <exception>
+
+#include "component_based/port/log_private.hh"
+
+#define THROW(error_code) throw Exception(error_code, __FILE__, __LINE__)
+
+namespace component_based {
+
+class Exception : public std::exception {
+ public:
+  explicit Exception(int error_code, std::string file = __FILE__,
+      int line = __LINE__ ) {
+    error_code_ = error_code;
+    message_ = file.substr(file.find_last_of("/") + 1) + ":"
+        + std::to_string(line) + " code:" + std::to_string(error_code_);
+    _E("%s", message_.c_str());
+  }
+
+  virtual ~Exception() {}
+
+  virtual const char *what(void) const noexcept {
+    return message_.c_str();
+  }
+
+  int GetErrorCode() {
+    return error_code_;
+  }
+
+ private:
+  int error_code_;
+  std::string message_;
+};
+
+}  // namespace component_based
+
+#endif  // COMPONENT_BASED_PORT_EXCEPTION_HH_
diff --git a/component_based/port/export_api.hh b/component_based/port/export_api.hh
new file mode 100644 (file)
index 0000000..fe31fe0
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 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 COMPONENT_BASED_PORT_EXPORT_API_HH_
+#define COMPONENT_BASED_PORT_EXPORT_API_HH_
+
+#undef EXPORT_API
+#define EXPORT_API __attribute__((visibility("default")))
+
+#endif  // COMPONENT_BASED_PORT_EXPORT_API_HH_
diff --git a/component_based/port/log_private.hh b/component_based/port/log_private.hh
new file mode 100644 (file)
index 0000000..d4b7d6b
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 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 COMPONENT_BASED_PORT_LOG_PRIVATE_HH_
+#define COMPONENT_BASED_PORT_LOG_PRIVATE_HH_
+
+#include <dlog.h>
+
+#undef LOG_TAG
+#define LOG_TAG "COMPONENT_BASED_PORT"
+
+#undef _E
+#define _E LOGE
+
+#undef _W
+#define _W LOGW
+
+#undef _I
+#define _I LOGI
+
+#undef _D
+#define _D LOGD
+
+#endif  // COMPONENT_BASED_PORT_LOG_PRIVATE_HH_
diff --git a/component_based/port/main_loop.cc b/component_based/port/main_loop.cc
new file mode 100644 (file)
index 0000000..7b373c9
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "component_based/port/log_private.hh"
+#include "component_based/port/main_loop.hh"
+
+namespace component_based {
+
+MainLoop::MainLoop() = default;
+
+MainLoop::~MainLoop() {
+  if (thread_default_)
+    g_main_context_pop_thread_default(context_);
+
+  if (loop_) {
+    if (g_main_loop_is_running(loop_))
+      g_main_loop_quit(loop_);
+
+    g_main_loop_unref(loop_);
+  }
+
+  if (context_)
+    g_main_context_unref(context_);
+}
+
+void MainLoop::Run() {
+  if (context_ == nullptr) {
+    if (gettid() != getpid()) {
+      _W("Sub thread");
+      context_ = g_main_context_get_thread_default();
+      if (context_ == nullptr) {
+        context_ = g_main_context_new();
+        g_main_context_push_thread_default(context_);
+        thread_default_ = true;
+      } else {
+        context_ = g_main_context_ref_thread_default();
+      }
+    } else {
+      _W("Main thread");
+      context_ = g_main_context_ref(g_main_context_default());
+    }
+  }
+
+  if (loop_ == nullptr)
+    loop_ = g_main_loop_new(context_, FALSE);
+
+  if (!g_main_loop_is_running(loop_)) {
+    _W("Run");
+    g_main_loop_run(loop_);
+  } else {
+    _W("Loop is already running");
+  }
+}
+
+void MainLoop::Quit() {
+  if (g_main_loop_is_running(loop_)) {
+    _W("Quit");
+    g_main_loop_quit(loop_);
+  } else {
+    _W("Loop is not running");
+  }
+}
+
+GMainContext* MainLoop::GetContext() const {
+  return context_;
+}
+
+}  // namespace component_based
diff --git a/component_based/port/main_loop.hh b/component_based/port/main_loop.hh
new file mode 100644 (file)
index 0000000..e475ca4
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 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 COMPONENT_BASED_PORT_MAIN_LOOP_HH_
+#define COMPONENT_BASED_PORT_MAIN_LOOP_HH_
+
+#include <glib.h>
+
+namespace component_based {
+
+class MainLoop {
+ public:
+  MainLoop();
+  virtual ~MainLoop();
+
+  void Run();
+  void Quit();
+
+  GMainContext* GetContext() const;
+
+ private:
+  bool thread_default_ = false;
+  GMainContext* context_ = nullptr;
+  GMainLoop* loop_ = nullptr;
+};
+
+}  // namespace component_based
+
+#endif  // COMPONENT_BASED_PORT_MAIN_LOOP_HH_
diff --git a/component_based/port/peer_creds.cc b/component_based/port/peer_creds.cc
new file mode 100644 (file)
index 0000000..424a135
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include <cynara-creds-socket.h>
+#include <cynara-error.h>
+#include <cynara-session.h>
+
+#include <memory>
+
+#include "component_based/port/log_private.hh"
+#include "component_based/port/peer_creds.hh"
+
+namespace component_based {
+
+PeerCreds::PeerCreds(pid_t pid, std::string user, std::string client,
+    std::string session)
+    : pid_(pid),
+      user_(std::move(user)),
+      client_(std::move(client)),
+      session_(std::move(session)) {
+}
+
+PeerCreds::~PeerCreds() = default;
+
+pid_t PeerCreds::GetPid() const {
+  return pid_;
+}
+
+const std::string& PeerCreds::GetUser() const {
+  return user_;
+}
+
+const std::string& PeerCreds::GetClient() const {
+  return client_;
+}
+
+const std::string& PeerCreds::GetSession() const {
+  return session_;
+}
+
+PeerCreds* PeerCreds::Get(int fd) {
+  pid_t pid;
+  int ret = cynara_creds_socket_get_pid(fd, &pid);
+  if (ret != CYNARA_API_SUCCESS) {
+    char err[128];
+    cynara_strerror(ret, err, sizeof(err));
+    _E("cynara_creds_socket_get_pid() is failed. error(%s)", err);
+    return nullptr;
+  }
+
+  const char* session = "";
+
+  char* user = nullptr;
+  ret = cynara_creds_socket_get_user(fd, USER_METHOD_DEFAULT, &user);
+  if (ret != CYNARA_API_SUCCESS) {
+    char err[128];
+    cynara_strerror(ret, err, sizeof(err));
+    _E("cynara_creds_socket_get_user() is failed. error(%s)", err);
+    return nullptr;
+  }
+  auto user_ptr = std::unique_ptr<char, decltype(std::free)*>(user, std::free);
+
+  char* client = nullptr;
+  ret = cynara_creds_socket_get_client(fd, CLIENT_METHOD_DEFAULT, &client);
+  if (ret != CYNARA_API_SUCCESS) {
+    char err[128];
+    cynara_strerror(ret, err, sizeof(err));
+    _E("cynara_creds_socket_get_client() is failed. error(%s)", err);
+    return nullptr;
+  }
+  auto client_ptr = std::unique_ptr<char, decltype(std::free)*>(client,
+      std::free);
+
+  return new (std::nothrow) PeerCreds(pid, user, client, session);
+}
+
+}  // namespace component_based
diff --git a/component_based/port/peer_creds.hh b/component_based/port/peer_creds.hh
new file mode 100644 (file)
index 0000000..420b66e
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 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 COMPONENT_BASED_PORT_PEER_CREDS_HH_
+#define COMPONENT_BASED_PORT_PEER_CREDS_HH_
+
+#include <sys/types.h>
+
+#include <string>
+
+namespace component_based {
+
+class PeerCreds {
+ public:
+  PeerCreds(pid_t pid, std::string user, std::string client,
+      std::string session);
+  virtual ~PeerCreds();
+
+  pid_t GetPid() const;
+  const std::string& GetUser() const;
+  const std::string& GetClient() const;
+  const std::string& GetSession() const;
+
+  static PeerCreds* Get(int fd);
+
+ private:
+  pid_t pid_;
+  std::string user_;
+  std::string client_;
+  std::string session_;
+};
+
+}  // namespace component_based
+
+#endif  // COMPONENT_BASED_PORT_PEER_CREDS_HH_
diff --git a/component_based/port/port.cc b/component_based/port/port.cc
new file mode 100644 (file)
index 0000000..c395194
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include <errno.h>
+#include <tizen.h>
+
+#include "component_based/port/client.hh"
+#include "component_based/port/exception.hh"
+#include "component_based/port/log_private.hh"
+#include "component_based/port/port.hh"
+#include "component_based/port/port_implementation.hh"
+#include "component_based/port/request.hh"
+#include "component_based/port/response.hh"
+
+namespace component_based {
+
+Port::Impl::~Impl() {
+}
+
+Port::Impl::Impl(Port* parent, std::string name, Port::IEvent* listener)
+    : parent_(parent),
+      name_(std::move(name)),
+      listener_(listener),
+      server_(Server::Create(name_, this)) {
+}
+
+void Port::Impl::WaitForEvent() {
+  server_->Poll();
+}
+
+void Port::Impl::Cancel() {
+  server_->Cancel();
+}
+
+void Port::Impl::AddPrivilege(const std::string& privilege) {
+  server_->AddPrivilege(privilege);
+}
+
+int Port::Impl::Send(const std::string& endpoint, int timeout,
+    const std::shared_ptr<tizen_base::Parcel>& request) {
+  auto client = std::unique_ptr<Client>(Client::Create(endpoint, timeout));
+  if (client.get() == nullptr) {
+    _E("Client::Create() is failed");
+    return -EIO;
+  }
+
+  Request req(std::string(name_), false, request->GetRaw());
+  tizen_base::Parcel req_parcel;
+  req_parcel.WriteParcelable(req);
+  int ret = client->Send(req_parcel.GetRaw());
+  if (ret != 0) {
+    _E("Send() is failed. endpoint(%s), error(%d)", endpoint.c_str(), ret);
+    return ret;
+  }
+
+  std::vector<uint8_t> data;
+  ret = client->Recv(data);
+  if (ret != 0) {
+    _E("Recv() is failed. endpoint(%s), error(%d)", endpoint.c_str(), ret);
+    return ret;
+  }
+
+  Response res;
+  auto* p = reinterpret_cast<void*>(&data[0]);
+  tizen_base::Parcel res_parcel(p, data.size());
+  res_parcel.ReadParcelable(&res);
+  return res.GetResult();
+}
+
+int Port::Impl::SendSync(const std::string& endpoint, int timeout,
+    const std::shared_ptr<tizen_base::Parcel>& request,
+    std::shared_ptr<tizen_base::Parcel>& response) {
+  auto client = std::unique_ptr<Client>(Client::Create(endpoint, timeout));
+  if (client.get() == nullptr) {
+    _E("Client::Create() is failed");
+    return -EIO;
+  }
+
+  Request req(std::string(name_), true, request->GetRaw());
+  tizen_base::Parcel req_parcel;
+  req_parcel.WriteParcelable(req);
+  int ret = client->Send(req_parcel.GetRaw());
+  if (ret != 0) {
+    _E("Send() is failed. endpoint(%s), error(%d)", endpoint.c_str(), ret);
+    return ret;
+  }
+
+  std::vector<uint8_t> data;
+  ret = client->Recv(data);
+  if (ret != 0) {
+    _E("Recv() is failed. endpoint(%s), error(%d)", endpoint.c_str(), ret);
+    return ret;
+  }
+
+  Response res;
+  auto* p = reinterpret_cast<void*>(&data[0]);
+  tizen_base::Parcel res_parcel(p, data.size());
+  res_parcel.ReadParcelable(&res);
+  auto& res_data = res.GetData();
+  if (res_data.size() > 0) {
+    auto *p = reinterpret_cast<const void*>(&res_data[0]);
+    response->Write(p, res_data.size());
+  }
+
+  return res.GetResult();
+}
+
+void Port::Impl::OnSyncRequestReceived(const std::string& sender, pid_t pid,
+    const std::vector<uint8_t>& request, std::vector<uint8_t>& response) {
+  auto sender_info = std::make_shared<SenderInfo>(sender, pid);
+  auto req = std::shared_ptr<tizen_base::Parcel>(
+      new (std::nothrow) tizen_base::Parcel());
+  auto* p = reinterpret_cast<const void*>(&request[0]);
+  req->Write(p, request.size());
+  auto res = std::shared_ptr<tizen_base::Parcel>(
+      new (std::nothrow) tizen_base::Parcel());
+  listener_->OnSyncRequest(sender_info, req, res);
+}
+
+void Port::Impl::OnRequestReceived(const std::string& sender, pid_t pid,
+    const std::vector<uint8_t>& request) {
+  auto sender_info = std::make_shared<SenderInfo>(sender, pid);
+  auto req = std::shared_ptr<tizen_base::Parcel>(
+      new (std::nothrow) tizen_base::Parcel());
+  auto* p = reinterpret_cast<const void*>(&request[0]);
+  req->Write(p, request.size());
+  listener_->OnRequest(sender_info, req);
+}
+
+Port::Port(std::string name, IEvent* listener)
+    : impl_(new Impl(this, name, listener)) {
+  if (impl_->server_.get() == nullptr) {
+    _E("Failed to create server. error(%d)", get_last_result());
+    THROW(get_last_result());
+  }
+}
+
+Port::~Port() {
+}
+
+void Port::WaitForEvent() {
+  impl_->WaitForEvent();
+}
+
+void Port::Cancel() {
+  impl_->Cancel();
+}
+
+void Port::AddPrivilege(const std::string& privilege) {
+  impl_->AddPrivilege(privilege);
+}
+
+int Port::Send(const std::string& endpoint, int timeout,
+    const std::shared_ptr<tizen_base::Parcel>& request) {
+  return impl_->Send(endpoint, timeout, request);
+}
+
+int Port::SendSync(const std::string& endpoint, int timeout,
+    const std::shared_ptr<tizen_base::Parcel>& request,
+    std::shared_ptr<tizen_base::Parcel>& response) {
+  return impl_->SendSync(endpoint, timeout, request, response);
+}
+
+}  // namespace component_based
diff --git a/component_based/port/port.hh b/component_based/port/port.hh
new file mode 100644 (file)
index 0000000..09e63d6
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 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 COMPONENT_BASED_PORT_PORT_HH_
+#define COMPONENT_BASED_PORT_PORT_HH_
+
+#include <parcel.hh>
+
+#include <memory>
+#include <string>
+
+#include "component_based/port/export_api.hh"
+#include "component_based/port/sender_info.hh"
+
+namespace component_based {
+
+class EXPORT_API Port {
+ public:
+  class IEvent {
+   public:
+     virtual void OnRequest(const std::shared_ptr<SenderInfo>& sender,
+         const std::shared_ptr<tizen_base::Parcel>& request) = 0;
+     virtual void OnSyncRequest(const std::shared_ptr<SenderInfo>& sender,
+         const std::shared_ptr<tizen_base::Parcel>& request,
+         std::shared_ptr<tizen_base::Parcel>& response) = 0;
+  };
+
+  Port(std::string name, IEvent* listener);
+  virtual ~Port();
+
+  void WaitForEvent();
+  void Cancel();
+  void AddPrivilege(const std::string& privilege);
+
+  int Send(const std::string& endpoint, int timeout,
+      const std::shared_ptr<tizen_base::Parcel>& request);
+  int SendSync(const std::string& endpoint, int timeout,
+      const std::shared_ptr<tizen_base::Parcel>& request,
+      std::shared_ptr<tizen_base::Parcel>& response);
+
+ private:
+  class Impl;
+  std::unique_ptr<Impl> impl_;
+};
+
+}  // namespace component_based
+
+#endif  // COMPONENT_BASED_PORT_PORT_HH_
diff --git a/component_based/port/port_implementation.hh b/component_based/port/port_implementation.hh
new file mode 100644 (file)
index 0000000..e3716b5
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 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 COMPONENT_BASED_PORT_PORT_IMPLEMENTATION_HH_
+#define COMPONENT_BASED_PORT_PORT_IMPLEMENTATION_HH_
+
+#include <list>
+#include <memory>
+#include <string>
+
+#include "component_based/port/port.hh"
+#include "component_based/port/server.hh"
+
+namespace component_based {
+
+class Port::Impl : public Server::IEvent {
+ public:
+  virtual ~Impl();
+
+  void AddPrivilege(const std::string& privilege);
+  void WaitForEvent();
+  void Cancel();
+  int Send(const std::string& endpoint, int timeout,
+      const std::shared_ptr<tizen_base::Parcel>& request);
+  int SendSync(const std::string& endpoint, int timeout,
+      const std::shared_ptr<tizen_base::Parcel>& request,
+      std::shared_ptr<tizen_base::Parcel>& response);
+
+ private:
+  friend class Port;
+  explicit Impl(Port* parent, std::string name, Port::IEvent* listener);
+
+  void OnSyncRequestReceived(const std::string& sender, pid_t pid,
+      const std::vector<uint8_t>& request,
+      std::vector<uint8_t>& response) override;
+  void OnRequestReceived(const std::string& sender, pid_t pid,
+      const std::vector<uint8_t>& request) override;
+
+ private:
+  Port* parent_;
+  std::string name_;
+  Port::IEvent* listener_;
+  std::unique_ptr<Server> server_;
+};
+
+}  // namespace component_based
+
+#endif  // COMPONENT_BASED_PORT_PORT_IMPLEMENTATION_HH_
diff --git a/component_based/port/privilege_checker.cc b/component_based/port/privilege_checker.cc
new file mode 100644 (file)
index 0000000..9c26ab8
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include <cynara-error.h>
+#include <errno.h>
+
+#include "component_based/port/log_private.hh"
+#include "component_based/port/peer_creds.hh"
+#include "component_based/port/privilege_checker.hh"
+
+namespace component_based {
+
+PrivilegeChecker::PrivilegeChecker(cynara* handle)
+    : cynara_(handle, cynara_finish) {
+}
+
+PrivilegeChecker::~PrivilegeChecker() {
+}
+
+void PrivilegeChecker::AddPrivilege(const std::string& privilege) {
+  privileges_.push_back(privilege);
+}
+
+int PrivilegeChecker::Check(int fd) {
+  auto creds = std::shared_ptr<PeerCreds>(PeerCreds::Get(fd));
+  if (creds.get() == nullptr) {
+    _E("Failed to get peer credentials");
+    return -EIO;
+  }
+
+  for (auto& privilege : privileges_) {
+    int ret = cynara_check(cynara_.get(), creds->GetClient().c_str(),
+        creds->GetSession().c_str(), creds->GetUser().c_str(),
+        privilege.c_str());
+    if (ret != CYNARA_API_ACCESS_ALLOWED) {
+      char err[128];
+      cynara_strerror(ret, err, sizeof(err));
+      _E("cynara_check() is not allowed. %s:%s:%s, error(%s)",
+          creds->GetClient().c_str(),
+          creds->GetUser().c_str(),
+          privilege.c_str(),
+          err);
+      if (ret == CYNARA_API_ACCESS_DENIED)
+        return -EPERM;
+
+      return -EIO;
+    }
+  }
+
+  return 0;
+}
+
+PrivilegeChecker* PrivilegeChecker::Create() {
+  cynara* cynara = nullptr;
+  int ret = cynara_initialize(&cynara, nullptr);
+  if (ret != CYNARA_API_SUCCESS) {
+    char err[128];
+    cynara_strerror(ret, err, sizeof(err));
+    _E("cynara_initialize() is failed. error(%s)", err);
+    return nullptr;
+  }
+
+  return new (std::nothrow) PrivilegeChecker(cynara);
+}
+
+}  // namespace component_based
diff --git a/component_based/port/privilege_checker.hh b/component_based/port/privilege_checker.hh
new file mode 100644 (file)
index 0000000..84ce8fa
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 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 COMPONENT_BASED_PORT_PRIVILEGE_CHECKER_HH_
+#define COMPONENT_BASED_PORT_PRIVILEGE_CHECKER_HH_
+
+#include <cynara-client.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace component_based {
+
+class PrivilegeChecker {
+ public:
+  explicit PrivilegeChecker(cynara* handle);
+  virtual ~PrivilegeChecker();
+
+  void AddPrivilege(const std::string& privilege);
+  int Check(int fd);
+
+  static PrivilegeChecker* Create();
+
+ private:
+  std::unique_ptr<cynara, decltype(cynara_finish)*> cynara_;
+  std::vector<std::string> privileges_;
+};
+
+}  // namespace component_based
+
+#endif  // COMPONENT_BASED_PORT_PRIVILEGE_CHECKER_HH_
diff --git a/component_based/port/request.cc b/component_based/port/request.cc
new file mode 100644 (file)
index 0000000..b0defcc
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include <memory>
+
+#include "component_based/port/log_private.hh"
+#include "component_based/port/request.hh"
+
+namespace component_based {
+
+Request::Request(std::string sender, bool sync, std::vector<uint8_t> data)
+    : sender_(std::move(sender)), sync_(sync), data_(std::move(data)) {
+}
+
+Request::Request() = default;
+
+Request::~Request() = default;
+
+void Request::WriteToParcel(tizen_base::Parcel* parcel) const {
+  parcel->WriteString(sender_);
+  parcel->WriteBool(sync_);
+  parcel->WriteUInt32(data_.size());
+  if (data_.size() > 0) {
+    auto* p = reinterpret_cast<const void*>(&data_[0]);
+    parcel->Write(p, data_.size());
+  }
+}
+
+void Request::ReadFromParcel(tizen_base::Parcel* parcel) {
+  sender_ = parcel->ReadString();
+  parcel->ReadBool(&sync_);
+  data_.clear();
+  uint32_t size = 0;
+  parcel->ReadUInt32(&size);
+  if (size > 0) {
+    auto* data = new (std::nothrow) uint8_t [size];
+    if (data == nullptr) {
+      _E("Out of memory");
+      return;
+    }
+
+    auto data_ptr = std::unique_ptr<uint8_t[]>(data);
+    parcel->Read(data, size);
+    std::copy(data, data + size, std::back_inserter(data_));
+  }
+}
+
+const std::string& Request::GetSender() const {
+  return sender_;
+}
+
+bool Request::IsSync() const {
+  return sync_;
+}
+
+const std::vector<uint8_t>& Request::GetData() const {
+  return data_;
+}
+
+}  // namespace component_based
diff --git a/component_based/port/request.hh b/component_based/port/request.hh
new file mode 100644 (file)
index 0000000..db0755b
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 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 COMPONENT_BASED_PORT_REQUEST_HH_
+#define COMPONENT_BASED_PORT_REQUEST_HH_
+
+#include <parcel.hh>
+#include <parcelable.hh>
+
+#include <string>
+#include <vector>
+
+namespace component_based {
+
+class Request : public tizen_base::Parcelable {
+ public:
+  Request(std::string sender, bool sync, std::vector<uint8_t> data);
+  Request();
+  virtual ~Request();
+
+  void WriteToParcel(tizen_base::Parcel* parcel) const override;
+  void ReadFromParcel(tizen_base::Parcel* parcel) override;
+
+  const std::string& GetSender() const;
+  bool IsSync() const;
+  const std::vector<uint8_t>& GetData() const;
+
+ private:
+  std::string sender_;
+  bool sync_ = false;
+  std::vector<uint8_t> data_;
+};
+
+}  // namespace component_based
+
+#endif  // COMPONENT_BASED_PORT_REQUEST_HH_
diff --git a/component_based/port/response.cc b/component_based/port/response.cc
new file mode 100644 (file)
index 0000000..46e8c2f
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include <memory>
+
+#include "component_based/port/log_private.hh"
+#include "component_based/port/response.hh"
+
+namespace component_based {
+
+Response::Response(int32_t result, std::vector<uint8_t> data)
+    : result_(result), data_(std::move(data)) {
+}
+
+Response::Response() = default;
+
+Response::~Response() = default;
+
+void Response::WriteToParcel(tizen_base::Parcel* parcel) const {
+  parcel->WriteInt32(result_);
+  parcel->WriteUInt32(data_.size());
+  if (data_.size() > 0) {
+    auto* p = reinterpret_cast<const void*>(&data_[0]);
+    parcel->Write(p, data_.size());
+  }
+}
+
+void Response::ReadFromParcel(tizen_base::Parcel* parcel) {
+  parcel->ReadInt32(&result_);
+  data_.clear();
+  uint32_t size = 0;
+  parcel->ReadUInt32(&size);
+  if (size > 0) {
+    auto* data = new (std::nothrow) uint8_t [size];
+    if (data == nullptr) {
+      _E("Out of memory");
+      return;
+    }
+
+    auto data_ptr = std::unique_ptr<uint8_t[]>(data);
+    parcel->Read(data, size);
+    std::copy(data, data + size, std::back_inserter(data_));
+  }
+}
+
+int32_t Response::GetResult() const {
+  return result_;
+}
+
+const std::vector<uint8_t>& Response::GetData() const {
+  return data_;
+}
+
+}  // namespace component_based
diff --git a/component_based/port/response.hh b/component_based/port/response.hh
new file mode 100644 (file)
index 0000000..77500ff
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 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 COMPONENT_BASED_PORT_RESPONSE_HH_
+#define COMPONENT_BASED_PORT_RESPONSE_HH_
+
+#include <parcel.hh>
+#include <parcelable.hh>
+
+#include <string>
+#include <vector>
+
+namespace component_based {
+
+class Response : public tizen_base::Parcelable {
+ public:
+  Response(int32_t result, std::vector<uint8_t> data);
+  Response();
+  virtual ~Response();
+
+  void WriteToParcel(tizen_base::Parcel* parcel) const override;
+  void ReadFromParcel(tizen_base::Parcel* parcel) override;
+
+  int32_t GetResult() const;
+  const std::vector<uint8_t>& GetData() const;
+
+ private:
+  int32_t result_;
+  std::vector<uint8_t> data_;
+};
+
+}  // namespace component_based
+
+#endif  // COMPONENT_BASED_PORT_RESPONSE_HH_
diff --git a/component_based/port/sender_info.cc b/component_based/port/sender_info.cc
new file mode 100644 (file)
index 0000000..24ccee7
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include "component_based/port/sender_info.hh"
+
+namespace component_based {
+
+SenderInfo::SenderInfo(std::string name, pid_t pid)
+    : name_(std::move(name)), pid_(pid) {
+}
+
+SenderInfo::~SenderInfo() = default;
+
+const std::string& SenderInfo::GetName() const {
+  return name_;
+}
+
+pid_t SenderInfo::GetPid() const {
+  return pid_;
+}
+
+}  // namespace component_based
diff --git a/component_based/port/sender_info.hh b/component_based/port/sender_info.hh
new file mode 100644 (file)
index 0000000..d9e67f6
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 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 COMPONENT_BASED_PORT_SENDER_INFO_HH_
+#define COMPONENT_BASED_PORT_SENDER_INFO_HH_
+
+#include <string>
+
+#include "component_based/port/export_api.hh"
+
+namespace component_based {
+
+class EXPORT_API SenderInfo {
+ public:
+  SenderInfo(std::string name, pid_t pid);
+  virtual ~SenderInfo();
+
+  const std::string& GetName() const;
+  pid_t GetPid() const;
+
+ private:
+  std::string name_;
+  pid_t pid_;
+};
+
+}  // namespace component_based
+
+#endif  // COMPONENT_BASED_PORT_SENDER_INFO_HH_
diff --git a/component_based/port/server.cc b/component_based/port/server.cc
new file mode 100644 (file)
index 0000000..e8f8809
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include <aul_component_port.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <iostream>
+
+#include "component_based/port/log_private.hh"
+#include "component_based/port/request.hh"
+#include "component_based/port/response.hh"
+#include "component_based/port/server.hh"
+
+namespace component_based {
+
+Server::Server(int fd, std::string name, IEvent* listener)
+  : fd_(fd),
+    name_(std::move(name)),
+    listener_(listener),
+    checker_(PrivilegeChecker::Create()) {
+  channel_ = g_io_channel_unix_new(fd_);
+  source_ = g_io_create_watch(channel_,
+      static_cast<GIOCondition>(G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_ERR));
+  g_source_set_callback(source_, reinterpret_cast<GSourceFunc>(GIOFunc), this,
+      nullptr);
+  g_source_set_priority(source_, G_PRIORITY_DEFAULT);
+  g_source_attach(source_, loop_.GetContext());
+  g_source_unref(source_);
+}
+
+Server::~Server() {
+  if (channel_) {
+    GError* error = nullptr;
+    g_io_channel_shutdown(channel_, TRUE, &error);
+    if (error) {
+      _E("g_io_channel_shutdown() is failed. error(%s)", error->message);
+      g_error_free(error);
+    }
+
+    g_io_channel_unref(channel_);
+  }
+
+  if (source_) {
+    if (g_source_is_destroyed(source_))
+      g_source_destroy(source_);
+  }
+
+  if (fd_ > 0)
+    close(fd_);
+
+  aul_component_port_destroy(name_.c_str());
+}
+
+void Server::Poll() {
+  loop_.Run();
+}
+
+void Server::Cancel() {
+  loop_.Quit();
+}
+
+void Server::AddPrivilege(const std::string& privilege) {
+  checker_->AddPrivilege(privilege);
+}
+
+Server* Server::Create(const std::string& name, IEvent* listener) {
+  int fd = -1;
+  int ret = aul_component_port_create(name.c_str(), &fd);
+  if (ret != AUL_R_OK) {
+    set_last_result(ret);
+    _E("aul_component_port_create() is failed. error(%d)", ret);
+    return nullptr;
+  }
+
+  ret = listen(fd, 128);
+  if (ret < 0) {
+    set_last_result(-errno);
+    _E("listen() is failed. port_name(%s), errno(%d)", name.c_str(), errno);
+    close(fd);
+    return nullptr;
+  }
+
+  return new Server(fd, std::string(name), listener);
+}
+
+Client* Server::Accept() {
+  struct sockaddr_un addr = { 0, };
+  auto* addr_ptr = reinterpret_cast<struct sockaddr*>(&addr);
+  socklen_t addr_size = sizeof(addr);
+  int client_fd = accept(fd_, addr_ptr, &addr_size);
+  if (client_fd < 0) {
+    _E("accept() is failed. errno(%d)", errno);
+    return nullptr;
+  }
+
+  struct ucred cred = { 0, };
+  socklen_t cred_size = sizeof(cred);
+  int ret = getsockopt(client_fd, SOL_SOCKET, SO_PEERCRED, &cred, &cred_size);
+  if (ret < 0) {
+    _E("getsockopt(SO_PEEDCRED) is failed. errno(%d)", errno);
+    close(client_fd);
+    return nullptr;
+  }
+
+  _W("client pid(%d), uid(%u)", cred.pid, cred.uid);
+  return new (std::nothrow) Client(client_fd, cred.pid);
+}
+
+int Server::CheckPrivilege(int fd) {
+  return checker_->Check(fd);
+}
+
+gboolean Server::GIOFunc(GIOChannel* source, GIOCondition cond, gpointer data) {
+  auto* handle = static_cast<Server*>(data);
+  auto client = std::unique_ptr<Client>(handle->Accept());
+  int ret = handle->CheckPrivilege(client->GetFd());
+  if (ret != 0) {
+    _E("Request is denied");
+    std::vector<uint8_t> dummy;
+    Response res(ret, dummy);
+    tizen_base::Parcel res_parcel;
+    res_parcel.WriteParcelable(res);
+    client->Send(res_parcel.GetRaw());
+    return G_SOURCE_CONTINUE;
+  }
+
+  auto* listener = handle->listener_;
+  if (listener) {
+    std::vector<uint8_t> buf;
+    client->Recv(buf);
+    auto* p = reinterpret_cast<void*>(&buf[0]);
+    tizen_base::Parcel parcel(p, buf.size());
+    Request req;
+    parcel.ReadParcelable(&req);
+    _W("Sender(%s), sync(%s)",
+        req.GetSender().c_str(), req.IsSync() ? "true" : "false");
+    if (req.IsSync()) {
+      std::vector<uint8_t> res_data;
+      listener->OnSyncRequestReceived(req.GetSender(), client->GetPid(),
+          req.GetData(), res_data);
+      Response res(0, res_data);
+      tizen_base::Parcel res_parcel;
+      res_parcel.WriteParcelable(res);
+      client->Send(res_parcel.GetRaw());
+    } else {
+      std::vector<uint8_t> dummy;
+      Response res(0, dummy);
+      tizen_base::Parcel res_parcel;
+      res_parcel.WriteParcelable(res);
+      client->Send(res_parcel.GetRaw());
+      listener->OnRequestReceived(req.GetSender(), client->GetPid(),
+          req.GetData());
+    }
+  }
+
+  return G_SOURCE_CONTINUE;
+}
+
+}  // namespace component_based
diff --git a/component_based/port/server.hh b/component_based/port/server.hh
new file mode 100644 (file)
index 0000000..023897c
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 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 COMPONENT_BASED_PORT_SERVER_HH_
+#define COMPONENT_BASED_PORT_SERVER_HH_
+
+#include <gio/gio.h>
+#include <glib.h>
+
+#include <memory>
+#include <string>
+
+#include "component_based/port/client.hh"
+#include "component_based/port/main_loop.hh"
+#include "component_based/port/privilege_checker.hh"
+
+namespace component_based {
+
+class Server {
+ public:
+  class IEvent {
+   public:
+    virtual void OnRequestReceived(const std::string& sender, pid_t pid,
+        const std::vector<uint8_t>& request) = 0;
+    virtual void OnSyncRequestReceived(const std::string& sender, pid_t pid,
+        const std::vector<uint8_t>& request,
+        std::vector<uint8_t>& response) = 0;
+  };
+
+  Server(int fd, std::string name, IEvent* listener);
+  virtual ~Server();
+
+  void Poll();
+  void Cancel();
+  void AddPrivilege(const std::string& privilege);
+
+  static Server* Create(const std::string& name, IEvent* listener);
+
+ private:
+  static gboolean GIOFunc(GIOChannel* source, GIOCondition cond, gpointer data);
+  Client* Accept();
+  int CheckPrivilege(int fd);
+
+ private:
+  int fd_;
+  std::string name_;
+  IEvent* listener_;
+  std::unique_ptr<PrivilegeChecker> checker_;
+  MainLoop loop_;
+  GIOChannel* channel_;
+  GSource* source_;
+};
+
+}  // namespace component_based
+
+#endif  // COMPONENT_BASED_PORT_SERVER_HH_
diff --git a/component_based/port/socket.cc b/component_based/port/socket.cc
new file mode 100644 (file)
index 0000000..043a8a6
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "component_based/port/log_private.hh"
+#include "component_based/port/socket.hh"
+
+namespace component_based {
+
+Socket::Socket(int fd) : fd_(fd) {
+}
+
+Socket::~Socket() {
+  if (fd_ > 0)
+    close(fd_);
+}
+
+int Socket::Send(const void* buf, size_t size) {
+  if (buf == nullptr || size == 0) {
+    _E("Invalid parameter");
+    return -EINVAL;
+  }
+
+  const uint8_t* buffer = static_cast<const uint8_t*>(buf);
+  size_t left = size;
+  while (left) {
+    ssize_t bytes = send(fd_, buffer, left, MSG_NOSIGNAL);
+    if (bytes < 0) {
+      int ret = -errno;
+      _E("send() is failed. fd(%d), errno(%d)", fd_, errno);
+      return ret;
+    }
+
+    left -= bytes;
+    buffer += bytes;
+  }
+
+  return 0;
+}
+
+int Socket::Read(void* buf, size_t size) {
+  if (buf == nullptr || size == 0) {
+    _E("Invalid parameter");
+    return -EINVAL;
+  }
+
+  uint8_t* buffer = static_cast<uint8_t*>(buf);
+  size_t left = size;
+  while (left) {
+    ssize_t bytes = read(fd_, buffer, left);
+    if (bytes == 0) {
+      _W("EOF. fd(%d)", fd_);
+      return -EIO;
+    } else if (bytes < 0) {
+      return -errno;
+    }
+
+    left -= bytes;
+    buffer += bytes;
+  }
+
+  return 0;
+}
+
+int Socket::GetFd() const {
+  return fd_;
+}
+
+std::string Socket::GetSocketPath(const std::string& name) {
+  return std::string("/run/aul/port/" + std::to_string(getuid()) +
+      "/." + name + "-port");
+}
+
+}  // namespace component_based
diff --git a/component_based/port/socket.hh b/component_based/port/socket.hh
new file mode 100644 (file)
index 0000000..86ee29b
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 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 COMPONENT_BASED_PORT_SOCKET_HH_
+#define COMPONENT_BASED_PORT_SOCKET_HH_
+
+#include <string>
+
+namespace component_based {
+
+class Socket {
+ public:
+  Socket(int fd);
+  virtual ~Socket();
+
+  virtual int Send(const void* buf, size_t size);
+  virtual int Read(void* buf, size_t size);
+
+  int GetFd() const;
+  static std::string GetSocketPath(const std::string& name);
+
+ private:
+  int fd_;
+};
+
+}  // namespace component_based
+
+#endif  // COMPONENT_BASED_PORT_SOCKET_HH_
diff --git a/component_based/port/stub.cc b/component_based/port/stub.cc
new file mode 100644 (file)
index 0000000..5bd9f97
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include "component_based/port/api/component_port.h"
+#include "component_based/port/exception.hh"
+#include "component_based/port/export_api.hh"
+#include "component_based/port/log_private.hh"
+#include "component_based/port/port.hh"
+
+namespace {
+using namespace component_based;
+
+class PortStub : public Port,
+                 public Port::IEvent {
+ public:
+  PortStub(std::string name)
+      : Port(std::move(name), this) {
+  }
+
+  virtual ~PortStub() = default;
+
+  void SetRequestCb(component_port_request_cb cb, void* user_data) {
+    request_cb_ = cb;
+    request_cb_user_data_ = user_data;
+  }
+
+  void SetSyncRequestCb(component_port_sync_request_cb cb, void* user_data) {
+    sync_request_cb_ = cb;
+    sync_request_cb_user_data_ = user_data;
+  }
+
+ private:
+  void OnRequest(const std::shared_ptr<SenderInfo>& sender,
+      const std::shared_ptr<tizen_base::Parcel>& request) override {
+    if (request_cb_) {
+      parcel_h parcel = static_cast<parcel_h>(request.get());
+      request_cb_(sender->GetName().c_str(), parcel, request_cb_user_data_);
+    }
+  }
+
+  void OnSyncRequest(const std::shared_ptr<SenderInfo>& sender,
+      const std::shared_ptr<tizen_base::Parcel>& request,
+      std::shared_ptr<tizen_base::Parcel>& response) override {
+    if (sync_request_cb_) {
+      parcel_h req_parcel = static_cast<parcel_h>(request.get());
+      parcel_h res_parcel = static_cast<parcel_h>(response.get());
+      sync_request_cb_(sender->GetName().c_str(), req_parcel, res_parcel,
+          request_cb_user_data_);
+    }
+  }
+
+ private:
+  component_port_request_cb request_cb_ = nullptr;
+  void* request_cb_user_data_ = nullptr;
+  component_port_sync_request_cb sync_request_cb_ = nullptr;
+  void* sync_request_cb_user_data_ = nullptr;
+};
+
+}  // namespace
+
+extern "C" EXPORT_API int component_port_create(const char* port_name,
+    component_port_h* port) {
+  if (port_name == nullptr || port == nullptr) {
+    _E("Invalid parameter");
+    return COMPONENT_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  ::PortStub* p = nullptr;
+  try {
+    p = new (std::nothrow) ::PortStub(std::string(port_name));
+    if (p == nullptr) {
+      _E("Out of memory");
+      return COMPONENT_PORT_ERROR_OUT_OF_MEMORY;
+    }
+  } catch (Exception& e) {
+    _E("Failed to create port");
+    return COMPONENT_PORT_ERROR_IO_ERROR;
+  }
+
+  *port = static_cast<component_port_h>(p);
+  return COMPONENT_PORT_ERROR_NONE;
+}
+
+extern "C" EXPORT_API int component_port_destroy(component_port_h port) {
+  if (port == nullptr) {
+    _E("Invalid parameter");
+    return COMPONENT_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  auto* p = static_cast<::PortStub*>(port);
+  delete p;
+  return COMPONENT_PORT_ERROR_NONE;
+}
+
+extern "C" EXPORT_API int component_port_set_request_cb(component_port_h port,
+    component_port_request_cb callback, void *user_data) {
+  if (port == nullptr || callback == nullptr) {
+    _E("Invalid parameter");
+    return COMPONENT_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  auto* p = static_cast<::PortStub*>(port);
+  p->SetRequestCb(callback, user_data);
+  return COMPONENT_PORT_ERROR_NONE;
+}
+
+extern "C" EXPORT_API int component_port_set_sync_request_cb(
+    component_port_h port, component_port_sync_request_cb callback,
+    void *user_data) {
+  if (port == nullptr || callback == nullptr) {
+    _E("Invalid parameter");
+    return COMPONENT_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  auto* p = static_cast<::PortStub*>(port);
+  p->SetSyncRequestCb(callback, user_data);
+  return COMPONENT_PORT_ERROR_NONE;
+}
+
+extern "C" EXPORT_API int component_port_add_privilege(component_port_h port,
+    const char *privilege) {
+  if (port == nullptr || privilege == nullptr) {
+    _E("Invalid parameter");
+    return COMPONENT_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  auto* p = static_cast<::PortStub*>(port);
+  p->AddPrivilege(std::string(privilege));
+  return COMPONENT_PORT_ERROR_NONE;
+}
+
+extern "C" EXPORT_API void component_port_wait_for_event(
+    component_port_h port) {
+  if (port == nullptr) {
+    _E("Invalid parameter");
+    set_last_result(COMPONENT_PORT_ERROR_INVALID_PARAMETER);
+    return;
+  }
+
+  _W("Wait for events...");
+  auto* p = static_cast<::PortStub*>(port);
+  p->WaitForEvent();
+  set_last_result(COMPONENT_PORT_ERROR_NONE);
+}
+
+extern "C" EXPORT_API void component_port_cancel(component_port_h port) {
+  if (port == nullptr) {
+    _E("Invaid parameter");
+    set_last_result(COMPONENT_PORT_ERROR_INVALID_PARAMETER);
+    return;
+  }
+
+  _W("Cancel!!!");
+  auto* p = static_cast<::PortStub*>(port);
+  p->Cancel();
+  set_last_result(COMPONENT_PORT_ERROR_NONE);
+}
+
+extern "C" EXPORT_API int component_port_send(component_port_h port,
+    const char *endpoint, int timeout, parcel_h request) {
+  if (port == nullptr || endpoint == nullptr || request == nullptr) {
+    _E("Invalid parameter");
+    return COMPONENT_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  void* raw = nullptr;
+  size_t size = 0;
+  parcel_get_raw(request, &raw, &size);
+  auto req = std::make_shared<tizen_base::Parcel>(raw, size);
+  auto* p = static_cast<::PortStub*>(port);
+  int ret = p->Send(endpoint, timeout, req);
+  if (ret != 0) {
+    if (ret == -EPERM) {
+      _E("Permission denied");
+      return COMPONENT_PORT_ERROR_PERMISSION_DENIED;
+    }
+
+    return COMPONENT_PORT_ERROR_IO_ERROR;
+  }
+
+  return COMPONENT_PORT_ERROR_NONE;
+}
+
+extern "C" EXPORT_API int component_port_send_sync(component_port_h port,
+    const char *endpoint, int timeout, parcel_h request, parcel_h *response) {
+  if (port == nullptr || endpoint == nullptr || request == nullptr ||
+      response == nullptr) {
+    _E("Invalid parameter");
+    return COMPONENT_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  void* raw = nullptr;
+  size_t size = 0;
+  parcel_get_raw(request, &raw, &size);
+  auto req = std::make_shared<tizen_base::Parcel>(raw, size);
+  auto res = std::make_shared<tizen_base::Parcel>();
+  auto* p = static_cast<::PortStub*>(port);
+  int ret = p->SendSync(endpoint, timeout, req, res);
+  if (ret != 0) {
+    if (ret == -EPERM) {
+      _E("Permission denied");
+      return COMPONENT_PORT_ERROR_PERMISSION_DENIED;
+    }
+
+    return COMPONENT_PORT_ERROR_IO_ERROR;
+  }
+
+  parcel_h res_parcel = nullptr;
+  parcel_create(&res_parcel);
+  auto& res_data = res->GetRaw();
+  auto* res_p = reinterpret_cast<const void*>(&res_data[0]);
+  parcel_burst_write(res_parcel, res_p, res_data.size());
+  *response = res_parcel;
+  return COMPONENT_PORT_ERROR_NONE;
+}
+
diff --git a/component_based/port/util.cc b/component_based/port/util.cc
new file mode 100644 (file)
index 0000000..b0278ec
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+#include "component_based/port/log_private.hh"
+#include "component_based/port/util.hh"
+
+namespace component_based {
+
+void Util::Hexdump(const std::string& tag, const std::vector<uint8_t>& data) {
+  unsigned int address = 0;
+  unsigned int row = 0;
+  unsigned int nread = 0;
+  std::vector<std::string> lines;
+  std::stringstream ds;
+  for (int i = 0; i <= 75; ++i)
+    ds << '=';
+  lines.push_back(ds.str());
+
+  while (true) {
+    std::stringstream ss;
+    ss << std::hex << std::setfill('0');
+    if (address >= data.size())
+      break;
+
+    ss << std::setw(8) << address;
+    nread = ((data.size() - address) > 16) ? 16 : (data.size() - address);
+
+    for (unsigned int i = 0; i < 16; ++i) {
+      if (i % 8 == 0)
+        ss << ' ';
+
+      if (i < nread) {
+        ss << ' ' << std::setw(2) <<
+          static_cast<int>(data[16 * row + i]);
+      } else {
+        ss << "   ";
+      }
+    }
+
+    ss << "  ";
+    for (unsigned int i = 0; i < nread ; ++i) {
+      if (data[16 * row + i] < 32)
+        ss << '.';
+      else
+        ss << data[16 * row + i];
+    }
+
+    address += 16;
+    row++;
+    lines.push_back(ss.str());
+  }
+  lines.push_back(ds.str());
+
+  _W("[%s] Hexdump", tag.c_str());
+  for (auto& s : lines)
+    _W("%s", s.c_str());
+  _W("");
+}
+
+}  // namespace component_based
diff --git a/component_based/port/util.hh b/component_based/port/util.hh
new file mode 100644 (file)
index 0000000..f91b9fb
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 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 COMPONENT_BASED_PORT_UTIL_HH_
+#define COMPONENT_BASED_PORT_UTIL_HH_
+
+#include <string>
+#include <vector>
+
+namespace component_based {
+
+class Util {
+ public:
+  static void Hexdump(const std::string& tag, const std::vector<uint8_t>& data);
+};
+
+}  // namespace component_based
+
+#endif  // COMPONENT_BASED_PORT_UTIL_HH_
diff --git a/packaging/component-based-port.manifest b/packaging/component-based-port.manifest
new file mode 100644 (file)
index 0000000..2a0cec5
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+  <request>
+    <domain name="_"/>
+  </request>
+</manifest>
index 1ac6832c95c3e97a81494e2901c113cd8f288380..275767618d1547bbffffe7f531c83f7fc669c3c4 100644 (file)
@@ -9,6 +9,7 @@ Source1001: %{name}.manifest
 Source1002: %{name}-application.manifest
 Source1003: %{name}-widget.manifest
 Source1004: %{name}-widget-application.manifest
+Source1005: %{name}-port.manifest
 
 Requires(post):   /sbin/ldconfig
 Requires(postun): /sbin/ldconfig
@@ -26,6 +27,9 @@ BuildRequires: pkgconfig(elementary)
 BuildRequires: pkgconfig(capi-appfw-app-common)
 BuildRequires: pkgconfig(widget_service)
 BuildRequires: pkgconfig(screen_connector_provider)
+BuildRequires: pkgconfig(parcel)
+BuildRequires: pkgconfig(cynara-client)
+BuildRequires: pkgconfig(cynara-creds-socket)
 
 %if 0%{?gcov:1}
 BuildRequires:  lcov
@@ -69,8 +73,6 @@ Requires: %{name}-application = %{version}-%{release}
 %description -n %{name}-application-devel
 Header & package configuration files to support development of the component-based application.
 
-
-
 #################################################
 # component-based-widget
 #################################################
@@ -90,7 +92,6 @@ Requires: %{name}-widget = %{version}-%{release}
 %description -n %{name}-widget-devel
 Header & package configuration files to support development of the component-based widget
 
-
 #################################################
 # component-based-widget-application
 #################################################
@@ -110,6 +111,24 @@ Requires: %{name}-widget-application = %{version}-%{release}
 %description -n %{name}-widget-application-devel
 Header & package configuration files to support development of the component-based efl widget application.
 
+#################################################
+# component-based-port
+#################################################
+%package -n %{name}-port
+Summary: Library for developing the component-based port
+Group: Application Framework/Core
+License: Apache-2.0
+
+%description -n %{name}-port
+Component-based port library package.
+
+%package -n %{name}-port-devel
+Summary: Component-based port development library (dev)
+Group: Development/Libraries
+Requires: %{name}-port = %{version}-%{release}
+
+%description -n %{name}-port-devel
+Component-based port library package. (devel)
 
 #################################################
 # unittests
@@ -140,6 +159,7 @@ cp %{SOURCE1001} .
 cp %{SOURCE1002} .
 cp %{SOURCE1003} .
 cp %{SOURCE1004} .
+cp %{SOURCE1005} .
 
 %build
 %if 0%{?gcov:1}
@@ -241,7 +261,6 @@ install -m 0644 gcov-obj/* %{buildroot}%{_datadir}/gcov/obj
 %{_libdir}/pkgconfig/component-based-application.pc
 %{_libdir}/libcomponent-based-application.so
 
-
 #################################################
 # component-based-widget
 #################################################
@@ -256,7 +275,6 @@ install -m 0644 gcov-obj/* %{buildroot}%{_datadir}/gcov/obj
 %{_libdir}/pkgconfig/component-based-core-widget-base.pc
 %{_libdir}/libcomponent-based-core-widget-base.so
 
-
 #################################################
 # component-based-widget-application
 #################################################
@@ -271,6 +289,20 @@ install -m 0644 gcov-obj/* %{buildroot}%{_datadir}/gcov/obj
 %{_libdir}/pkgconfig/component-based-widget-application.pc
 %{_libdir}/libcomponent-based-widget-application.so
 
+#################################################
+# component-based-port
+#################################################
+%files -n %{name}-port
+%license LICENSE
+%manifest %{name}-port.manifest
+%attr(0644,root,root) %{_libdir}/libcomponent-based-port.so.*
+
+%files -n %{name}-port-devel
+%{_includedir}/component_based/port/*.hh
+%{_includedir}/component_based/port/api/*.h
+%{_libdir}/pkgconfig/component-based-port.pc
+%{_libdir}/libcomponent-based-port.so
+
 #################################################
 # unittests
 #################################################