--- /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 <aul.h>
+#include <dlog.h>
+
+#include "fdbroker-internal.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "RPC_PORT"
+
+
+#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 {
+
+FdBroker::DBusConnectionManager& FdBroker::DBusConnectionManager::GetInst() {
+ static DBusConnectionManager dm;
+
+ if (dm.disposed_) {
+ dm.Init();
+ }
+
+ return dm;
+}
+
+void FdBroker::DBusConnectionManager::Dispose() {
+ if (!disposed_)
+ Fini();
+}
+
+GDBusConnection* FdBroker::DBusConnectionManager::GetConnection() {
+ return gdbus_conn_;
+}
+
+FdBroker::DBusConnectionManager::~DBusConnectionManager() {
+ if (!disposed_)
+ Fini();
+}
+
+void FdBroker::DBusConnectionManager::Init() {
+ GError* error = nullptr;
+
+ gdbus_conn_ = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
+ if (gdbus_conn_ == nullptr) {
+ if (error != nullptr) {
+ LOGE("Failed to get dbus [%s]", error->message);
+ g_error_free(error);
+ }
+
+ return;
+ }
+
+ disposed_ = false;
+}
+
+void FdBroker::DBusConnectionManager::Fini() {
+ if (gdbus_conn_ != nullptr) {
+ g_object_unref(gdbus_conn_);
+ gdbus_conn_ = nullptr;
+ }
+
+ disposed_ = true;
+}
+
+FdBroker::SocketPair::SocketPair() {
+ 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() {
+ if (aul_request_message_port_socket_pair(socks_) != AUL_R_OK) {
+ LOGE("error create socket pair");
+ return -1;
+ }
+
+ 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) {
+ LOGE("g_unix_fd_list_append [%s]", err->message);
+ g_error_free(err);
+ return -1;
+ }
+
+ return 0;
+}
+
+GUnixFDList* FdBroker::FdList::GetRaw() {
+ return fd_list_;
+}
+
+FdBroker::~FdBroker() {
+ if (registration_id_ > 0) {
+ g_dbus_connection_unregister_object(
+ DBusConnectionManager::GetInst().GetConnection(),
+ registration_id_);
+ }
+}
+
+std::string FdBroker::GetInterfaceName(const std::string& target_appid,
+ const std::string& port_name) {
+ std::string interface_name = RPC_PORT_INTERFACE_PREFIX;
+
+ interface_name += target_appid;
+ interface_name += "_" + port_name;
+
+ return interface_name;
+}
+
+int FdBroker::Send(const std::string& target_appid,
+ const std::string& port_name) {
+ std::string interface_name = GetInterfaceName(target_appid, port_name);
+ GDBusMessage *msg;
+ GError *err = nullptr;
+ GVariant *body;
+ SocketPair sock_pair;
+ FdList fd_list;
+ char sender_appid[255];
+
+ if (aul_app_get_appid_bypid(getpid(), sender_appid, sizeof(sender_appid)) < 0)
+ return -1;
+
+ if (sock_pair.Request() != 0)
+ return -1;
+
+ if (fd_list.Add(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) {
+ LOGE("Can't allocate new method call");
+ return -1;
+ }
+
+ body = g_variant_new("(s)", sender_appid);
+ g_dbus_message_set_unix_fd_list(msg, fd_list.GetRaw());
+ g_dbus_message_set_body(msg, body);
+ g_dbus_connection_send_message(DBusConnectionManager::GetInst().GetConnection(),
+ msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+ nullptr, &err);
+ if (err != nullptr) {
+ LOGE("No reply. error = %s", err->message);
+ g_error_free(err);
+ g_object_unref(msg);
+ return -1;
+ }
+
+ int fd = sock_pair.Detach(SocketPair::SENDER);
+ g_object_unref(msg);
+
+ return fd;
+}
+
+void FdBroker::ReceiveMessage(GVariant* parameters,
+ GDBusMethodInvocation* invocation) {
+ char* sender_appid = nullptr;
+ GDBusMessage* msg;
+ GUnixFDList* fd_list;
+ int fd_len;
+ int* returned_fds = nullptr;
+
+ g_variant_get(parameters, "(&s)", &sender_appid);
+
+ if (sender_appid == nullptr) {
+ LOGE("Invalid argument : sender_appid is NULL");
+ return;
+ }
+
+ msg = g_dbus_method_invocation_get_message(invocation);
+ fd_list = g_dbus_message_get_unix_fd_list(msg);
+
+ if (fd_list == nullptr)
+ return;
+
+ returned_fds = g_unix_fd_list_steal_fds(fd_list, &fd_len);
+ if (returned_fds == nullptr) {
+ LOGE("fail to get fds");
+ return;
+ }
+
+ listener_->OnFdReceived(sender_appid, returned_fds[0]);
+ 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) {
+ FdBroker* broker = static_cast<FdBroker*>(user_data);
+
+ broker->ReceiveMessage(parameters, invocation);
+ g_dbus_method_invocation_return_value(invocation, nullptr);
+}
+
+int FdBroker::GetOwnerId(const std::string& interface_name) {
+ int owner_id = 0;
+ GError *error = NULL;
+
+ GVariant* result = g_dbus_connection_call_sync(
+ DBusConnectionManager::GetInst().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) {
+ LOGE("RequestName fail : %s", error->message);
+ g_error_free(error);
+ return -1;
+ }
+
+ if (result == nullptr) {
+ LOGE("fail to get name NULL");
+ return -1;
+ }
+
+ g_variant_get(result, "(u)", &owner_id);
+ if (owner_id == 0) {
+ LOGE("Acquiring the own name is failed");
+ g_variant_unref(result);
+ return -1;
+ }
+
+ LOGD("Acquiring the own name : %d", owner_id);
+ g_variant_unref(result);
+
+ return owner_id;
+}
+
+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='s' name='sender_appid' direction='in'/>"
+ " </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);
+
+ if (GetOwnerId(interface_name) < 0) {
+ LOGE("Failed to get owner id");
+ return -1;
+ }
+
+ 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) {
+ LOGE("g_dbus_node_info_new_for_xml() is failed.");
+ return -1;
+ }
+
+ registration_id_ = g_dbus_connection_register_object(
+ DBusConnectionManager::GetInst().GetConnection(),
+ RPC_PORT_OBJECT_PATH, introspection_data->interfaces[0],
+ &interface_vtable, this, nullptr, nullptr);
+
+ g_dbus_node_info_unref(introspection_data);
+ if (registration_id_ == 0) {
+ LOGE("Failed to g_dbus_connection_register_object");
+ return -1;
+ }
+
+ return 0;
+}
+
+int FdBroker::Listen(IEventListener* ev, const std::string& port_name) {
+ if (listener_ != nullptr) {
+ LOGE("listener_ is not NULL");
+ return -1;
+ }
+
+ if (ev == nullptr) {
+ LOGE("ev is NULL");
+ return -1;
+ }
+
+ int ret = RegisterDbusInterface(port_name);
+
+ if (ret != 0) {
+ LOGE("Failed to register dbus interface");
+ return -1;
+ }
+
+ listener_ = ev;
+ return 0;
+}
+
+} // namespace internal
+} // namespace rpc_port
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2017 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 <string>
+#include <memory>
+
+namespace rpc_port {
+namespace internal {
+
+class FdBroker {
+ public:
+ class IEventListener {
+ public:
+ virtual void OnFdReceived(const std::string& sender, int fd) = 0;
+ };
+
+ FdBroker() = default;
+ ~FdBroker();
+
+ static void Dispose() {
+ DBusConnectionManager::GetInst().Dispose();
+ }
+
+ int Send(const std::string& target_appid, const std::string& port_name);
+ int Listen(IEventListener* ev, const std::string& port_name);
+
+ private:
+ class DBusConnectionManager {
+ public:
+ DBusConnectionManager(const DBusConnectionManager&) = delete;
+ DBusConnectionManager& operator = (const DBusConnectionManager&) = delete;
+
+ static DBusConnectionManager& GetInst();
+ void Dispose();
+ GDBusConnection* GetConnection();
+
+ private:
+ DBusConnectionManager() = default;
+ ~DBusConnectionManager();
+
+ void Init();
+ void Fini();
+
+ private:
+ bool disposed_ = true;
+ GDBusConnection* gdbus_conn_ = nullptr;
+ };
+
+ class SocketPair {
+ public:
+ enum Type {
+ SENDER = 0,
+ RECEIVER = 1
+ };
+
+ SocketPair();
+ ~SocketPair();
+
+ int Request();
+ int Get(Type t) const;
+ int Detach(Type t);
+
+ private:
+ int socks_[2];
+ };
+
+ 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 RegisterDbusInterface(const std::string& port_name);
+ void ReceiveMessage(GVariant* parameters, GDBusMethodInvocation* invocation);
+ std::string GetInterfaceName(const std::string& target_appid,
+ const std::string& port_name);
+
+ private:
+ IEventListener* listener_ = nullptr;
+ int registration_id_ = 0;
+};
+
+} // namespace internal
+} // namespace rpc_port
+
+#endif // FDBROKER_INTERNAL_H_
* limitations under the License.
*/
-#ifndef __PARCEL_INTERNAL_H__
-#define __PARCEL_INTERNAL_H__
+#ifndef PARCEL_INTERNAL_H_
+#define PARCEL_INTERNAL_H_
#include <bundle.h>
} // namespace rpc_port
-#endif // __PARCEL_INTERNAL_H__
\ No newline at end of file
+#endif // PARCEL_INTERNAL_H_
\ No newline at end of file
--- /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 <sys/socket.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <poll.h>
+#include <unistd.h>
+#include <dlog.h>
+
+#include "port-internal.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "RPC_PORT"
+
+#define MAX_RETRY_CNT 10
+#define SEND_TIMEOUT 500
+
+namespace rpc_port {
+namespace internal {
+
+Port::Port(int fd, const std::string& id)
+ : fd_(fd), id_(id) {}
+
+Port::~Port() {
+ close(fd_);
+}
+
+int Port::Read(void* buf, unsigned int size) {
+ unsigned int left = size;
+ ssize_t nb;
+ int retry_cnt = 0;
+ const struct timespec TRY_SLEEP_TIME = { 0, 500 * 1000 * 1000 };
+ int bytes_read = 0;
+ char* buffer = static_cast<char*>(buf);
+
+ while (left && (retry_cnt < MAX_RETRY_CNT)) {
+ nb = read(fd_, buffer, left);
+ if (nb == 0) {
+ LOGE("read_socket: ...read EOF, socket closed %d: nb %d\n", fd_, nb);
+ return -1;
+ } else if (nb == -1) {
+ if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
+ LOGE("read_socket: %d errno, sleep and retry ...", errno);
+ retry_cnt++;
+ nanosleep(&TRY_SLEEP_TIME, 0);
+ continue;
+ }
+ LOGE("read_socket: ...error fd %d: errno %d\n", fd_, errno);
+ return -1;
+ }
+
+ left -= nb;
+ buffer += nb;
+ bytes_read += nb;
+ retry_cnt = 0;
+ }
+
+ if (left != 0) {
+ LOGE("error fd %d: retry_cnt %d", fd_, retry_cnt);
+ return -1;
+ }
+
+ return 0;
+}
+
+int Port::Write(const void* buf, unsigned int size) {
+ unsigned int left = size;
+ ssize_t nb;
+ int retry_cnt = 0;
+ struct pollfd fds[1];
+ int ret;
+ int bytes_write = 0;
+ const char* buffer = static_cast<const char*>(buf);
+
+ fds[0].fd = fd_;
+ fds[0].events = POLLOUT;
+ fds[0].revents = 0;
+
+ ret = poll(fds, 1, SEND_TIMEOUT);
+ if (ret == 0) {
+ LOGE("write_socket: : fd %d poll timeout", fd_);
+ return -1;
+ }
+
+ while (left && (retry_cnt < MAX_RETRY_CNT)) {
+ nb = write(fd_, buffer, left);
+ if (nb == -1) {
+ if (errno == EINTR) {
+ LOGE("write_socket: EINTR error continue ...");
+ retry_cnt++;
+ continue;
+ }
+
+ LOGE("write_socket: ...error fd %d: errno %d\n", fd_, errno);
+ return -1;
+ }
+
+ left -= nb;
+ buffer += nb;
+ bytes_write += nb;
+ retry_cnt = 0;
+ }
+
+ if (left != 0) {
+ LOGE("error fd %d: retry_cnt %d", fd_, retry_cnt);
+ return -1;
+ }
+
+ return 0;
+}
+
+} // namespace internal
+} // namespace rpc_port
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2017 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 PORT_INTERNAL_H_
+#define PORT_INTERNAL_H_
+
+#include <string>
+#include <memory>
+
+namespace rpc_port {
+namespace internal {
+
+class Port {
+ public:
+ Port(int fd, const std::string& id);
+ virtual ~Port();
+
+ int Read(void* buf, unsigned int size);
+ int Write(const void* buf, unsigned int size);
+ int GetFd() const {
+ return fd_;
+ }
+
+ const std::string& GetId() const {
+ return id_;
+ }
+
+ private:
+ int fd_;
+ std::string id_;
+};
+
+} // namespace internal
+} // namespace rpc_port
+
+#endif // PORT_INTERNAL_H_
--- /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 <dlog.h>
+
+#include "proxy-internal.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "RPC_PORT"
+
+namespace rpc_port {
+namespace internal {
+
+Proxy::~Proxy() {
+ if (src_id_ > 0)
+ g_source_remove(src_id_);
+
+ if (gioc_ != nullptr) {
+ g_io_channel_shutdown(gioc_, TRUE, nullptr);
+ g_io_channel_unref(gioc_);
+ }
+}
+
+gboolean Proxy::OnSocketDisconnected(GIOChannel *gio, GIOCondition cond,
+ gpointer data) {
+ Proxy* proxy = static_cast<Proxy*>(data);
+
+ proxy->listener_->OnDisconnected(proxy->target_appid_);
+ proxy->src_id_ = 0;
+
+ return FALSE;
+}
+
+int Proxy::Watch(int fd) {
+ char buf[1024];
+
+ gioc_ = g_io_channel_unix_new(fd);
+ if (!gioc_) {
+ LOGE("Error is %s\n", strerror_r(errno, buf, sizeof(buf)));
+ return -1;
+ }
+
+ src_id_ = g_io_add_watch(gioc_,
+ (GIOCondition)(G_IO_ERR | G_IO_HUP | G_IO_NVAL),
+ OnSocketDisconnected, this);
+ if (src_id_ == 0) {
+ LOGE("fail to add watch on socket");
+ g_io_channel_shutdown(gioc_, TRUE, nullptr);
+ g_io_channel_unref(gioc_);
+ gioc_ = nullptr;
+ return -1;
+ }
+
+ return 0;
+}
+
+void Proxy::Connect(const std::string appid, const std::string& port_name,
+ IEventListener* ev) {
+ if (ev == nullptr || listener_ != nullptr)
+ return;
+
+ listener_ = ev;
+ target_appid_ = appid;
+ int fd = fd_broker_.Send(appid, port_name);
+
+ if (fd <= 0) {
+ listener_->OnRejected(appid);
+ listener_ = nullptr;
+ return;
+ }
+
+ port_.reset(new Port(fd, port_name));
+ listener_->OnConnected(appid, *port_);
+ Watch(fd);
+}
+
+} // namespace internal
+} // namespace rpc_port
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2017 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 PROXY_INTERNAL_H_
+#define PROXY_INTERNAL_H_
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <glib-unix.h>
+
+#include <string>
+#include <memory>
+
+#include "port-internal.h"
+#include "fdbroker-internal.h"
+
+namespace rpc_port {
+namespace internal {
+
+class Proxy {
+ public:
+ ~Proxy();
+
+ class IEventListener {
+ public:
+ virtual void OnConnected(const std::string& endpoint, Port& port) = 0;
+ virtual void OnDisconnected(const std::string& endpoint) = 0;
+ virtual void OnRejected(const std::string& endpoint) = 0;
+ };
+
+ void Connect(const std::string appid, const std::string& port_name,
+ IEventListener* ev);
+ std::shared_ptr<Port> GetPort() const {
+ return port_;
+ }
+
+ private:
+ static gboolean OnSocketDisconnected(GIOChannel *gio, GIOCondition cond,
+ gpointer data);
+ int Watch(int fd);
+
+ private:
+ std::shared_ptr<Port> port_;
+ IEventListener* listener_ = nullptr;
+ FdBroker fd_broker_;
+ std::string target_appid_;
+ GIOChannel* gioc_ = nullptr;
+ int src_id_ = 0;
+};
+
+} // namespace internal
+} // namespace rpc_port
+
+#endif // PROXY_INTERNAL_H_
--- /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 <dlog.h>
+
+#include "stub-internal.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "RPC_PORT"
+
+namespace rpc_port {
+namespace internal {
+
+Stub::Stub(const std::string& port_name)
+ : port_name_(port_name) {}
+
+Stub::~Stub() {}
+
+void Stub::Listen(IEventListener* ev) {
+ if (ev == nullptr)
+ return;
+
+ listener_ = ev;
+ fd_broker_.Listen(this, port_name_);
+}
+
+gboolean Stub::OnDataReceived(GIOChannel *gio, GIOCondition cond,
+ gpointer data) {
+ Stub* stub = static_cast<Stub*>(data);
+ int fd = g_io_channel_unix_get_fd(gio);
+
+ for (auto& p : stub->ports_) {
+ if (p->GetFd() == fd) {
+ stub->listener_->OnReceived(p->GetId(), *p);
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+gboolean Stub::OnSocketDisconnected(GIOChannel *gio, GIOCondition cond,
+ gpointer data) {
+ Stub* stub = static_cast<Stub*>(data);
+ int fd = g_io_channel_unix_get_fd(gio);
+
+ for (auto& p : stub->ports_) {
+ if (p->GetFd() == fd) {
+ stub->listener_->OnDisconnected(p->GetId());
+ stub->ports_.remove(p);
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+void Stub::OnFdReceived(const std::string& sender, int fd) {
+ ports_.emplace_back(new AcceptedPort(this, fd, sender));
+ listener_->OnConnected(sender);
+}
+
+Stub::AcceptedPort::AcceptedPort(Stub* parent, int fd, const std::string& id)
+ : Port(fd, id), parent_(parent) {
+ Watch();
+}
+
+Stub::AcceptedPort::~AcceptedPort() {
+ if (disconn_src_ > 0)
+ g_source_remove(disconn_src_);
+
+ if (src_ > 0)
+ g_source_remove(src_);
+
+ if (gioc_ != nullptr) {
+ g_io_channel_shutdown(gioc_, TRUE, nullptr);
+ g_io_channel_unref(gioc_);
+ }
+}
+
+int Stub::AcceptedPort::Watch() {
+ char buf[1024];
+ int fd = GetFd();
+
+ gioc_ = g_io_channel_unix_new(fd);
+ if (!gioc_) {
+ LOGE("Error is %s", strerror_r(errno, buf, sizeof(buf)));
+ return -1;
+ }
+
+ disconn_src_= g_io_add_watch(gioc_,
+ (GIOCondition)(G_IO_ERR | G_IO_HUP | G_IO_NVAL),
+ Stub::OnSocketDisconnected, parent_);
+ if (disconn_src_ == 0) {
+ LOGE("fail to add watch on socket");
+ g_io_channel_shutdown(gioc_, TRUE, nullptr);
+ g_io_channel_unref(gioc_);
+ gioc_ = nullptr;
+ return -1;
+ }
+
+ src_= g_io_add_watch(gioc_,
+ (GIOCondition)(G_IO_IN),
+ Stub::OnDataReceived, parent_);
+ if (src_ == 0) {
+ LOGE("fail to add watch on socket");
+ g_source_remove(disconn_src_);
+ disconn_src_ = 0;
+ g_io_channel_shutdown(gioc_, TRUE, nullptr);
+ g_io_channel_unref(gioc_);
+ gioc_ = nullptr;
+ return -1;
+ }
+
+ return 0;
+}
+
+} // namespace internal
+} // namespace rpc_port
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2017 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 STUB_INTERNAL_H_
+#define STUB_INTERNAL_H_
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <glib-unix.h>
+
+#include <string>
+#include <list>
+#include <memory>
+
+#include "port-internal.h"
+#include "fdbroker-internal.h"
+
+namespace rpc_port {
+namespace internal {
+
+class Stub : private FdBroker::IEventListener {
+ public:
+ class IEventListener {
+ public:
+ virtual void OnConnected(const std::string& sender) = 0;
+ virtual void OnDisconnected(const std::string& sender) = 0;
+ virtual void OnReceived(const std::string& sender, Port& port) = 0;
+ };
+
+ Stub(const std::string& port_name);
+ ~Stub();
+
+ void Listen(IEventListener* ev);
+
+ private:
+ class AcceptedPort : public Port {
+ public:
+ AcceptedPort(Stub* parent, int fd, const std::string& id);
+ virtual ~AcceptedPort();
+
+ private:
+ int Watch();
+
+ private:
+ GIOChannel* gioc_ = nullptr;
+ int disconn_src_ = 0;
+ int src_ = 0;
+ Stub* parent_;
+ };
+
+ static gboolean OnDataReceived(GIOChannel *gio, GIOCondition cond,
+ gpointer data);
+ static gboolean OnSocketDisconnected(GIOChannel *gio, GIOCondition cond,
+ gpointer data);
+
+ void OnFdReceived(const std::string& sender, int fd) override;
+
+ private:
+ std::list<std::shared_ptr<Port>> ports_;
+ IEventListener* listener_;
+ FdBroker fd_broker_;
+ std::string port_name_;
+};
+
+} // namespace internal
+} // namespace rpc_port
+
+#endif // STUB_INTERNAL_H_