From 1bb3c0ebe08f2d5fd490256365e0aa917d53da2b Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Mon, 25 May 2020 14:44:09 +0900 Subject: [PATCH 01/16] Add testcase for code coverage Change-Id: I32ea09d152adc2f6619e7fa6c09c9161301d4de2 Signed-off-by: Hwankyu Jhun --- unit_tests/src/rpc_port_test.cc | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/unit_tests/src/rpc_port_test.cc b/unit_tests/src/rpc_port_test.cc index 666dfed..2694d7c 100644 --- a/unit_tests/src/rpc_port_test.cc +++ b/unit_tests/src/rpc_port_test.cc @@ -204,6 +204,41 @@ TEST_F(RpcPortBase, rpc_port_event_connect) { } /* + * @testcase rpc_port_event_connect_sync_P + * @description After the rpc_port_proxy_connect_sync() is called, + * the rambda function is called by connected events. + * @apicovered rpc_port_stub_add_connected_event_cb, rpc_port_stub_listen, + * rpc_port_proxy_add_connected_event_cb, rpc_port_proxy_connect_sync, + */ +TEST_F(RpcPortBase, rpc_port_event_connect_sync) { + int ret = rpc_port_stub_add_connected_event_cb(stub_handle_, + [](const char *sender, const char* instance, void *data) { + RpcPortBase* p = static_cast(data); + + p->touch_stub_connected_event_cb_ = true; + }, this); + ASSERT_EQ(ret, 0); + + ret = rpc_port_stub_listen(stub_handle_); + ASSERT_EQ(ret, 0); + + ret = rpc_port_proxy_add_connected_event_cb(proxy_handle_, + [](const char *ep, const char *port_name, rpc_port_h port, void *data) { + RpcPortBase* p = static_cast(data); + + p->touch_proxy_connected_event_cb_ = true; + }, this); + ASSERT_EQ(ret, 0); + + ret = rpc_port_proxy_connect_sync(proxy_handle_, "TestApp", "test_port"); + ASSERT_EQ(ret, 0); + + ASSERT_TRUE(touch_proxy_connected_event_cb_); + ASSERT_TRUE(touch_stub_connected_event_cb_); +} + + +/* * @testcase rpc_port_proxy_event_reject_n * @description After the rpc_port_proxy_connect() is called, * the rambda function is called by the rejected event. -- 2.7.4 From 5dfacd0aa3f31b71b87c0cc334e5596c30766cbf Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Mon, 25 May 2020 19:47:32 +0900 Subject: [PATCH 02/16] Exclude some lines for coverage measurement Change-Id: Ie9d73a23772ea8a80491d529af57efb538eb7e37 Signed-off-by: Hwankyu Jhun --- src/ac-internal.cc | 12 +++-- src/fdbroker-internal.cc | 128 +++++++++++++++++++++++++++++------------------ src/fdbroker-internal.h | 4 +- src/parcel-internal.cc | 6 +++ src/proxy-internal.cc | 32 ++++++++---- src/rpc-port-parcel.cc | 12 +++-- src/rpc-port.cc | 6 +++ src/stub-internal.cc | 14 ++++-- 8 files changed, 143 insertions(+), 71 deletions(-) diff --git a/src/ac-internal.cc b/src/ac-internal.cc index 2e97a9a..860190a 100644 --- a/src/ac-internal.cc +++ b/src/ac-internal.cc @@ -99,9 +99,11 @@ int AccessController::Check(GDBusConnection* connection, const char* sender, return ret; } +// LCOV_EXCL_START int AccessController::SetCache(const std::string& sender) { return -1; } +// LCOV_EXCL_STOP AccessController::Cynara::Cynara() : cynara_(nullptr, cynara_finish), client_(nullptr, std::free), @@ -109,7 +111,7 @@ AccessController::Cynara::Cynara() cynara* cynara_inst = nullptr; if (cynara_initialize(&cynara_inst, NULL) != CYNARA_API_SUCCESS) { - LOGE("cynara_initialize() is failed"); + LOGE("cynara_initialize() is failed"); // LCOV_EXL_LINE } else { cynara_.reset(cynara_inst); } @@ -123,8 +125,8 @@ int AccessController::Cynara::FetchCredsFromDBus(GDBusConnection* connection, int ret = cynara_creds_gdbus_get_user(connection, sender, USER_METHOD_DEFAULT, &user); if (ret != CYNARA_API_SUCCESS) { - LOGE("cynara_creds_gdbus_get_user() is failed : %d", ret); - return -1; + LOGE("cynara_creds_gdbus_get_user() is failed : %d", ret); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE } user_.reset(user); @@ -132,8 +134,8 @@ int AccessController::Cynara::FetchCredsFromDBus(GDBusConnection* connection, ret = cynara_creds_gdbus_get_client(connection, sender, CLIENT_METHOD_DEFAULT, &client); if (ret != CYNARA_API_SUCCESS) { - LOGE("cynara_creds_gdbus_get_client() is failed : %d", ret); - return -1; + LOGE("cynara_creds_gdbus_get_client() is failed : %d", ret); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE } client_.reset(client); diff --git a/src/fdbroker-internal.cc b/src/fdbroker-internal.cc index 647a39d..98b09e7 100644 --- a/src/fdbroker-internal.cc +++ b/src/fdbroker-internal.cc @@ -54,10 +54,12 @@ FdBroker::DBusConnectionManager& FdBroker::DBusConnectionManager::GetInst() { return dm; } +// LCOV_EXCL_START void FdBroker::DBusConnectionManager::Dispose() { if (!disposed_) Fini(); } +// LCOV_EXCL_STOP GDBusConnection* FdBroker::DBusConnectionManager::GetConnection() { return gdbus_conn_; @@ -73,12 +75,14 @@ void FdBroker::DBusConnectionManager::Init() { gdbus_conn_ = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error); if (gdbus_conn_ == nullptr) { + // LCOV_EXCL_START if (error != nullptr) { LOGE("Failed to get dbus [%s]", error->message); g_error_free(error); } return; + // LCOV_EXCL_STOP } disposed_ = false; @@ -93,12 +97,15 @@ void FdBroker::DBusConnectionManager::Fini() { disposed_ = true; } +// LCOV_EXCL_START FdBroker::DBusMock& FdBroker::DBusMock::GetInst() { static DBusMock mock; return mock; } +// LCOV_EXCL_STOP +// LCOV_EXCL_START int FdBroker::DBusMock::Send(const std::string& sender, const std::string& port, int fds[2]) { if (port == "wrong_port") @@ -109,7 +116,9 @@ int FdBroker::DBusMock::Send(const std::string& sender, ports_[port]->OnFdReceived(sender, fds); return 0; } +// LCOV_EXCL_STOP +// LCOV_EXCL_START int FdBroker::DBusMock::AddListener(const std::string& port, FdBroker::IEventListener* listener) { if (ports_.find(port) != ports_.end()) @@ -118,17 +127,22 @@ int FdBroker::DBusMock::AddListener(const std::string& port, ports_[port] = listener; return 0; } +// LCOV_EXCL_STOP +// LCOV_EXCL_START int FdBroker::DBusMock::Watch(FdBroker::IEventWatcher* watcher, const std::string& target_appid, const std::string& port_name) { watcher->OnPortAppeared(target_appid, port_name); return 0; } +// LCOV_EXCL_STOP +// LCOV_EXCL_START void FdBroker::DBusMock::Dispose() { ports_.clear(); } +// LCOV_EXCL_STOP FdBroker::SocketPair::SocketPair(bool mock) : mock_(mock) { @@ -146,13 +160,13 @@ FdBroker::SocketPair::~SocketPair() { int FdBroker::SocketPair::Request(const std::string& target_appid, const std::string& port_name) { if (mock_) { - return socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, socks_); + return socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, socks_); // LCOV_EXCL_LINE } if (aul_rpc_port_create_socket_pair(target_appid.c_str(), port_name.c_str(), &socks_) != AUL_R_OK) { - LOGE("error create socket pair"); - return -1; + LOGE("error create socket pair"); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE } return 0; @@ -184,9 +198,9 @@ int FdBroker::FdList::Add(int fd) { close(fd); if (err != NULL) { - LOGE("g_unix_fd_list_append [%s]", err->message); - g_error_free(err); - return -1; + LOGE("g_unix_fd_list_append [%s]", err->message); // LCOV_EXCL_LINE + g_error_free(err); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE } return 0; @@ -223,7 +237,7 @@ void FdBroker::Cancel() { } if (mock_) { - DBusMock::GetInst().Dispose(); + DBusMock::GetInst().Dispose(); // LCOV_EXCL_LINE } } @@ -253,8 +267,8 @@ int FdBroker::Send(const std::string& target_appid, if (!mock_ && aul_app_get_appid_bypid(getpid(), sender_appid, sizeof(sender_appid)) < 0) { - LOGE("Can't get appid"); - return -1; + LOGE("Can't get appid"); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE } if (main_sock_pair.Request(target_appid, port_name) != 0) @@ -263,6 +277,7 @@ int FdBroker::Send(const std::string& target_appid, return -1; if (mock_) { + // LCOV_EXCL_START int send_fds[2]; send_fds[0] = main_sock_pair.Detach(SocketPair::RECEIVER); send_fds[1] = delegate_sock_pair.Detach(SocketPair::RECEIVER); @@ -274,6 +289,7 @@ int FdBroker::Send(const std::string& target_appid, (*fds)[1] = delegate_sock_pair.Detach(SocketPair::SENDER); watcher_->OnPortConnected(watch_appid_, watch_port_name_); return (*fds)[0]; + // LCOV_EXCL_STOP } if (fd_list.Add(main_sock_pair.Detach(SocketPair::RECEIVER)) != 0) @@ -285,20 +301,20 @@ int FdBroker::Send(const std::string& target_appid, RPC_PORT_OBJECT_PATH, interface_name.c_str(), "send_message"); if (!msg) { - LOGE("Can't allocate new method call"); - return -1; + LOGE("Can't allocate new method call"); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE } if (cancellable_) { - g_cancellable_cancel(cancellable_); - g_object_unref(cancellable_); + g_cancellable_cancel(cancellable_); // LCOV_EXCL_LINE + g_object_unref(cancellable_); // LCOV_EXCL_LINE } cancellable_ = g_cancellable_new(); if (!cancellable_) { - LOGE("Failed to create GCancellable"); - g_object_unref(msg); - return -1; + LOGE("Failed to create GCancellable"); // LCOV_EXCL_LINE + g_object_unref(msg); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE } g_dbus_message_set_unix_fd_list(msg, fd_list.GetRaw()); @@ -314,6 +330,7 @@ int FdBroker::Send(const std::string& target_appid, return (*fds)[0]; } +// LCOV_EXCL_START int FdBroker::SendSync(const std::string& target_appid, const std::string& port_name, int (*fds)[2]) { @@ -449,6 +466,7 @@ int FdBroker::SendSync(const std::string& target_appid, return (*fds)[0]; } +// LCOV_EXCL_STOP void FdBroker::ReceiveMessage(const char* sender_appid, GDBusMethodInvocation* invocation) { @@ -461,12 +479,12 @@ void FdBroker::ReceiveMessage(const char* sender_appid, fd_list = g_dbus_message_get_unix_fd_list(msg); if (fd_list == nullptr) - return; + return; // LCOV_EXCL_LINE returned_fds = g_unix_fd_list_steal_fds(fd_list, &fd_len); if (returned_fds == nullptr || fd_len != 2) { - LOGE("fail to get fds. fd_len(%d)", fd_len); - return; + LOGE("fail to get fds. fd_len(%d)", fd_len); // LCOV_EXCL_LINE + return; // LCOV_EXCL_LINE } listener_->OnFdReceived(sender_appid, returned_fds); @@ -518,21 +536,21 @@ int FdBroker::GetOwnerId(const std::string& interface_name) { &error); if (error) { - LOGE("RequestName fail : %s", error->message); - g_error_free(error); - return -1; + LOGE("RequestName fail : %s", error->message); // LCOV_EXCL_LINE + g_error_free(error); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE } if (result == nullptr) { - LOGE("fail to get name NULL"); - return -1; + LOGE("fail to get name NULL"); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE } g_variant_get(result, "(u)", &owner_id); if (owner_id == 0) { - LOGE("Acquiring the own name is failed"); - g_variant_unref(result); - return -1; + LOGE("Acquiring the own name is failed"); // LCOV_EXCL_LINE + g_variant_unref(result); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE } LOGD("Acquiring the own name : %d", owner_id); @@ -552,8 +570,8 @@ int FdBroker::GetSenderPid(GDBusConnection *connection, const gchar *sender) { "/org/freedesktop/DBus", "org.freedesktop.DBus", "GetConnectionUnixProcessID"); if (!msg) { - LOGE("Can't allocate new method call"); - goto out; + LOGE("Can't allocate new method call"); // LCOV_EXCL_LINE + goto out; // LCOV_EXCL_LINE } g_dbus_message_set_body(msg, g_variant_new("(s)", sender)); @@ -561,11 +579,13 @@ int FdBroker::GetSenderPid(GDBusConnection *connection, const gchar *sender) { G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL, &err); if (!reply) { + // LCOV_EXCL_START if (err != NULL) { LOGE("Failed to get pid [%s]", err->message); g_error_free(err); } goto out; + // LCOV_EXCL_STOP } body = g_dbus_message_get_body(reply); @@ -636,29 +656,31 @@ int FdBroker::RegisterDbusInterface(const std::string& port_name) { int FdBroker::Listen(IEventListener* ev, const std::string& port_name) { if (listener_ != nullptr) { - LOGE("listener_ is not NULL"); - return RPC_PORT_ERROR_INVALID_PARAMETER; + LOGE("listener_ is not NULL"); // LCOV_EXCL_LINE + return RPC_PORT_ERROR_INVALID_PARAMETER; // LCOV_EXCL_LINE } if (ev == nullptr) { - LOGE("ev is NULL"); - return RPC_PORT_ERROR_INVALID_PARAMETER; + LOGE("ev is NULL"); // LCOV_EXCL_LINE + return RPC_PORT_ERROR_INVALID_PARAMETER; // LCOV_EXCL_LINE } if (mock_) { + // LCOV_EXCL_START int ret = DBusMock::GetInst().AddListener(port_name, ev); if (ret < 0) return ret; return RPC_PORT_ERROR_NONE; + // LCOV_EXCL_STOP } int ret = RegisterDbusInterface(port_name); if (ret != 0) { - LOGE("Failed to register dbus interface"); - return RPC_PORT_ERROR_IO_ERROR; + LOGE("Failed to register dbus interface"); // LCOV_EXCL_LINE + return RPC_PORT_ERROR_IO_ERROR; // LCOV_EXCL_LINE } listener_ = ev; @@ -678,15 +700,15 @@ void FdBroker::OnNameAppeared(GDBusConnection *connection, char owner_appid[255] = { 0, }; if (aul_app_get_appid_bypid(pid, owner_appid, sizeof(owner_appid)) < 0) { - LOGE("aul_app_get_appid_bypid failed %d", pid); - broker->watcher_->OnPortRejected(owner_appid); - return; + LOGE("aul_app_get_appid_bypid failed %d", pid); // LCOV_EXCL_LINE + broker->watcher_->OnPortRejected(owner_appid); // LCOV_EXCL_LINE + return; // LCOV_EXCL_LINE } if (broker->watch_appid_ != owner_appid) { - LOGE("invalid appid %s", owner_appid); - broker->watcher_->OnPortRejected(owner_appid); - return; + LOGE("invalid appid %s", owner_appid); // LCOV_EXCL_LINE + broker->watcher_->OnPortRejected(owner_appid); // LCOV_EXCL_LINE + return; // LCOV_EXCL_LINE } broker->watcher_->OnPortAppeared(broker->watch_appid_, @@ -715,19 +737,23 @@ int FdBroker::Watch(IEventWatcher* ev, const std::string& target_appid, watch_port_name_ = port_name; if (mock_) { + // LCOV_EXCL_START ret = DBusMock::GetInst().Watch(ev, target_appid, port_name); if (ret < 0) return -1; return 0; + // LCOV_EXCL_STOP } std::string interface_name = GetInterfaceName(target_appid, port_name); if (watcher_id_ > 0) { + // LCOV_EXCL_START g_bus_unwatch_name(watcher_id_); LOGD("Retry to watch name. stub %s:%s", target_appid.c_str(), port_name.c_str()); + // LCOV_EXCL_STOP } watcher_id_ = g_bus_watch_name_on_connection( @@ -739,9 +765,9 @@ int FdBroker::Watch(IEventWatcher* ev, const std::string& target_appid, this, NULL); if (watcher_id_ == 0) { - LOGE("Failed to watch connection(%s)", interface_name.c_str()); - watcher_ = nullptr; - return -1; + LOGE("Failed to watch connection(%s)", interface_name.c_str()); // LCOV_EXCL_LINE + watcher_ = nullptr; // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE } return 0; @@ -753,12 +779,14 @@ int FdBroker::Prepare(const std::string& target_appid, int ret = aul_rpc_port_prepare_stub(target_appid.c_str(), port_name.c_str()); if (ret != AUL_R_OK) { + // LCOV_EXCL_START LOGE("Failed to prepare stub %s:%s [ret : %d]", target_appid.c_str(), port_name.c_str(), ret); if (ret == AUL_R_EILLACC) return -EILLEGALACCESS; return ret; + // LCOV_EXCL_STOP } } @@ -781,12 +809,13 @@ void FdBroker::OnResultReceived(GObject* source_object, FdBroker* broker = static_cast(user_data); if (broker == nullptr) { - LOGW("Null broker"); - return; + LOGW("Null broker"); // LCOV_EXCL_LINE + return; // LCOV_EXCL_LINE } IEventWatcher* watcher = broker->watcher_; if (err) { + // LCOV_EXCL_START watcher->OnPortDisconnected(broker->watch_appid_, broker->watch_port_name_, true); g_error_free(err); @@ -797,19 +826,22 @@ void FdBroker::OnResultReceived(GObject* source_object, broker->cancellable_ = nullptr; } return; + // LCOV_EXCL_STOP } if (reply == nullptr) { - LOGW("Null reply"); - return; + LOGW("Null reply"); // LCOV_EXCL_LINE + return; // LCOV_EXCL_LINE } GVariant* reply_body = g_dbus_message_get_body(reply); if (reply_body == nullptr) { + // LCOV_EXCL_START LOGE("g_dbus_message_get_body() is failed"); watcher->OnPortDisconnected(broker->watch_appid_, broker->watch_port_name_); g_object_unref(reply); return; + // LCOV_EXCL_STOP } int ret; diff --git a/src/fdbroker-internal.h b/src/fdbroker-internal.h index a248736..0e5e325 100644 --- a/src/fdbroker-internal.h +++ b/src/fdbroker-internal.h @@ -107,8 +107,8 @@ class FdBroker { void Dispose(); private: - DBusMock() = default; - ~DBusMock() = default; + DBusMock() = default; // LCOV_EXCL_LINE + ~DBusMock() = default; // LCOV_EXCL_LINE private: std::map ports_; diff --git a/src/parcel-internal.cc b/src/parcel-internal.cc index 54f2d99..319b921 100644 --- a/src/parcel-internal.cc +++ b/src/parcel-internal.cc @@ -151,18 +151,24 @@ void Parcel::Read(unsigned char* buf, unsigned int size) { reader_ += size; } +// LCOV_EXCL_START void Parcel::ResetReader() { reader_ = 0; } +// LCOV_EXCL_STOP +// LCOV_EXCL_START void Parcel::Clear() { data_.clear(); reader_ = 0; } +// LCOV_EXCL_STOP +// LCOV_EXCL_START void Parcel::Reset(const unsigned char* buf, unsigned int size) { Clear(); Write(buf, size); } +// LCOV_EXCL_STOP } // namespace rpc_port diff --git a/src/proxy-internal.cc b/src/proxy-internal.cc index fa6f3ed..3d45bc2 100644 --- a/src/proxy-internal.cc +++ b/src/proxy-internal.cc @@ -41,8 +41,8 @@ Proxy::Proxy(bool mock) Proxy::~Proxy() { LOGD("Proxy::~Proxy"); if (conn_timer_) { - g_source_remove(conn_timer_); - conn_timer_ = 0; + g_source_remove(conn_timer_); // LCOV_EXCL_LINE + conn_timer_ = 0; // LCOV_EXCL_LINE } } @@ -126,6 +126,7 @@ void Proxy::OnPortAppeared(const std::string& appid, fds_[1] = 0; int r = fd_broker_.Send(appid, port_name, &fds_); if (r <= 0) { + // LCOV_EXCL_START IEventListener* listener = listener_; listener_ = nullptr; if (r == -EILLEGALACCESS) @@ -133,6 +134,7 @@ void Proxy::OnPortAppeared(const std::string& appid, else listener->OnDisconnected(appid); return; + // LCOV_EXCL_STOP } LOGW("[__OnPortAppeared__] fds[0]: %d, fds[1]: %d", fds_[0], fds_[1]); @@ -149,8 +151,8 @@ void Proxy::OnPortConnected(const std::string& appid, LOGW("[__OnPortConnected__] endpoint(%s), port_name(%s)", appid.c_str(), port_name.c_str()); if (!listener_) { - LOGW("listener is null"); - return; + LOGW("listener is null"); // LCOV_EXCL_LINE + return; // LCOV_EXCL_LINE } main_port_.reset(new ProxyPort(this, fds_[0], appid, false)); @@ -158,6 +160,7 @@ void Proxy::OnPortConnected(const std::string& appid, listener_->OnConnected(appid, main_port_.get()); } +// LCOV_EXCL_START void Proxy::OnPortDisconnected(const std::string& appid, const std::string& port_name, bool cancel) { LOGW("[__OnPortDisconnected__] endporint(%s), port_name(%s)", @@ -177,6 +180,7 @@ void Proxy::OnPortDisconnected(const std::string& appid, listener_ = nullptr; listener->OnDisconnected(appid); } +// LCOV_EXCL_STOP int Proxy::Connect(std::string appid, std::string port_name, IEventListener* ev) { @@ -184,8 +188,8 @@ int Proxy::Connect(std::string appid, std::string port_name, return RPC_PORT_ERROR_INVALID_PARAMETER; if (listener_ != nullptr) { - LOGD("Already connected"); - return RPC_PORT_ERROR_INVALID_PARAMETER; + LOGD("Already connected"); // LCOV_EXCL_LINE + return RPC_PORT_ERROR_INVALID_PARAMETER; // LCOV_EXCL_LINE } listener_ = ev; @@ -193,22 +197,25 @@ int Proxy::Connect(std::string appid, std::string port_name, port_name_ = std::move(port_name); if (conn_timer_) - g_source_remove(conn_timer_); + g_source_remove(conn_timer_); // LCOV_EXCL_LINE conn_timer_ = g_timeout_add(10 * 1000, DbusNameTimeout, this); int r = fd_broker_.Watch(this, target_appid_, port_name_); if (r < 0) { + // LCOV_EXCL_START g_source_remove(conn_timer_); listener_ = nullptr; if (r == -EILLEGALACCESS) return RPC_PORT_ERROR_PERMISSION_DENIED; return RPC_PORT_ERROR_IO_ERROR; + // LCOV_EXCL_STOP } return RPC_PORT_ERROR_NONE; } +// LCOV_EXCL_START int Proxy::ConnectSync(std::string appid, std::string port_name, IEventListener* ev) { if (ev == nullptr) @@ -249,7 +256,9 @@ int Proxy::ConnectSync(std::string appid, std::string port_name, return RPC_PORT_ERROR_NONE; } +// LCOV_EXCL_STOP +// LCOV_EXCL_START gboolean Proxy::DbusNameTimeout(gpointer user_data) { Proxy* obj = static_cast(user_data); @@ -264,6 +273,7 @@ gboolean Proxy::DbusNameTimeout(gpointer user_data) { return G_SOURCE_REMOVE; } +// LCOV_EXCL_STOP Proxy::ProxyPort::ProxyPort(Proxy* parent, int fd, const std::string& id, bool receive) : Port(fd, id), parent_(parent) { @@ -287,18 +297,20 @@ int Proxy::ProxyPort::Watch(bool receive) { gioc_ = g_io_channel_unix_new(fd); if (!gioc_) { - LOGE("Error is %s", strerror_r(errno, buf, sizeof(buf))); - return -1; + LOGE("Error is %s", strerror_r(errno, buf, sizeof(buf))); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE } disconn_src_ = g_io_add_watch(gioc_, (GIOCondition)(G_IO_ERR | G_IO_HUP | G_IO_NVAL), Proxy::OnSocketDisconnected, parent_); if (disconn_src_ == 0) { + // LCOV_EXCL_START LOGE("Failed to add watch on socket"); g_io_channel_unref(gioc_); gioc_ = nullptr; return -1; + // LCOV_EXCL_STOP } if (!receive) @@ -308,12 +320,14 @@ int Proxy::ProxyPort::Watch(bool receive) { (GIOCondition)(G_IO_IN), Proxy::OnDataReceived, parent_); if (src_ == 0) { + // LCOV_EXCL_START LOGE("Failed to add watch on socket"); g_source_remove(disconn_src_); disconn_src_ = 0; g_io_channel_unref(gioc_); gioc_ = nullptr; return -1; + // LCOV_EXCL_STOP } return 0; diff --git a/src/rpc-port-parcel.cc b/src/rpc-port-parcel.cc index f906779..13b7cc2 100644 --- a/src/rpc-port-parcel.cc +++ b/src/rpc-port-parcel.cc @@ -59,8 +59,8 @@ RPC_API int rpc_port_parcel_create_from_port(rpc_port_parcel_h* h, buf = new unsigned char[len]; ret = rpc_port_read(port, buf, len); if (ret != 0) { - delete[] buf; - return ret; + delete[] buf; // LCOV_EXCL_LINE + return ret; // LCOV_EXCL_LINE } } @@ -377,6 +377,7 @@ RPC_API int rpc_port_parcel_burst_write(rpc_port_parcel_h h, return RPC_PORT_ERROR_NONE; } +// LCOV_EXCL_START RPC_API int rpc_port_parcel_reset_reader(rpc_port_parcel_h h) { if (h == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; @@ -387,7 +388,9 @@ RPC_API int rpc_port_parcel_reset_reader(rpc_port_parcel_h h) { return RPC_PORT_ERROR_NONE; } +// LCOV_EXCL_STOP +// LCOV_EXCL_START RPC_API int rpc_port_parcel_to_array(rpc_port_parcel_h h, void **array, unsigned int *size) { if (h == nullptr || !array || !size) @@ -406,7 +409,9 @@ RPC_API int rpc_port_parcel_to_array(rpc_port_parcel_h h, void **array, return RPC_PORT_ERROR_NONE; } +// LCOV_EXCL_STOP +// LCOV_EXCL_START RPC_API int rpc_port_parcel_from_array(rpc_port_parcel_h h, const void *array, unsigned int size) { if (h == nullptr || !array || size == 0) @@ -417,4 +422,5 @@ RPC_API int rpc_port_parcel_from_array(rpc_port_parcel_h h, const void *array, p->Reset(reinterpret_cast(array), size); return RPC_PORT_ERROR_NONE; -} \ No newline at end of file +} +// LCOV_EXCL_STOP diff --git a/src/rpc-port.cc b/src/rpc-port.cc index 0b00a1f..932b0a3 100644 --- a/src/rpc-port.cc +++ b/src/rpc-port.cc @@ -205,12 +205,14 @@ RPC_API int rpc_port_proxy_create(rpc_port_proxy_h* h) { return RPC_PORT_ERROR_NONE; } +// LCOV_EXCL_START RPC_API int rpc_port_proxy_create_mockup(rpc_port_proxy_h* h) { auto p = new ::ProxyExt(true); *h = p; return 0; } +// LCOV_EXL_STOP RPC_API int rpc_port_proxy_destroy(rpc_port_proxy_h h) { if (h == nullptr) @@ -233,6 +235,7 @@ RPC_API int rpc_port_proxy_connect(rpc_port_proxy_h h, const char* appid, return p->Connect(appid, port, p); } +// LCOV_EXCL_START RPC_API int rpc_port_proxy_connect_sync(rpc_port_proxy_h h, const char* appid, const char* port) { if (h == nullptr || appid == nullptr || port == nullptr) @@ -243,6 +246,7 @@ RPC_API int rpc_port_proxy_connect_sync(rpc_port_proxy_h h, const char* appid, return p->ConnectSync(appid, port, p); } +// LCOV_EXCL_STOP RPC_API int rpc_port_proxy_add_connected_event_cb(rpc_port_proxy_h h, rpc_port_proxy_connected_event_cb cb, void *user_data) { @@ -329,6 +333,7 @@ RPC_API int rpc_port_stub_create(rpc_port_stub_h* h, const char* port_name) { return RPC_PORT_ERROR_NONE; } +// LCOV_EXCL_START RPC_API int rpc_port_stub_create_mockup(rpc_port_stub_h* h, const char* port_name) { if (h == nullptr || port_name == nullptr) @@ -339,6 +344,7 @@ RPC_API int rpc_port_stub_create_mockup(rpc_port_stub_h* h, *h = p; return 0; } +//LCOV_EXCL_STOP RPC_API int rpc_port_stub_destroy(rpc_port_stub_h h) { if (h == nullptr) diff --git a/src/stub-internal.cc b/src/stub-internal.cc index 2630364..8b0476a 100644 --- a/src/stub-internal.cc +++ b/src/stub-internal.cc @@ -78,7 +78,7 @@ std::shared_ptr Stub::FindDelegatePort( } } - return {}; + return {}; // LCOV_EXCL_LINE } void Stub::RemoveAcceptedPorts(std::string instance) { @@ -107,7 +107,7 @@ gboolean Stub::OnDataReceived(GIOChannel *gio, GIOCondition cond, stub->RemoveAcceptedPorts(p->GetInstance()); if (aul_rpc_port_notify_rpc_finished() != AUL_R_OK) - LOGW("Failed to notify rpc finished"); + LOGW("Failed to notify rpc finished"); // LCOV_EXCL_LINE return FALSE; } @@ -121,7 +121,7 @@ gboolean Stub::OnDataReceived(GIOChannel *gio, GIOCondition cond, stub->RemoveAcceptedPorts(p->GetInstance()); if (aul_rpc_port_notify_rpc_finished() != AUL_R_OK) - LOGW("Failed to notify rpc finished"); + LOGW("Failed to notify rpc finished"); // LCOV_EXCL_LINE return FALSE; } @@ -143,7 +143,7 @@ gboolean Stub::OnSocketDisconnected(GIOChannel *gio, GIOCondition cond, if (p->GetFd() == fd) { stub->listener_->OnDisconnected(p->GetId(), p->GetInstance()); if (aul_rpc_port_notify_rpc_finished() != AUL_R_OK) - LOGW("Failed to notify rpc finished"); + LOGW("Failed to notify rpc finished"); // LCOV_EXCL_LINE stub->RemoveAcceptedPorts(p->GetInstance()); break; } @@ -197,18 +197,22 @@ int Stub::AcceptedPort::Watch(bool receive) { gioc_ = g_io_channel_unix_new(fd); if (!gioc_) { + // LCOV_EXCL_START LOGE("Error is %s", strerror_r(errno, buf, sizeof(buf))); return -1; + // LCOV_EXCL_STOP } disconn_src_ = g_io_add_watch(gioc_, (GIOCondition)(G_IO_ERR | G_IO_HUP | G_IO_NVAL), Stub::OnSocketDisconnected, parent_); if (disconn_src_ == 0) { + // LCOV_EXCL_START LOGE("fail to add watch on socket"); g_io_channel_unref(gioc_); gioc_ = nullptr; return -1; + // LCOV_EXCL_STOP } if (!receive) @@ -218,12 +222,14 @@ int Stub::AcceptedPort::Watch(bool receive) { (GIOCondition)(G_IO_IN), Stub::OnDataReceived, parent_); if (src_ == 0) { + // LCOV_EXCL_START LOGE("fail to add watch on socket"); g_source_remove(disconn_src_); disconn_src_ = 0; g_io_channel_unref(gioc_); gioc_ = nullptr; return -1; + // LCOV_EXCL_STOP } return 0; -- 2.7.4 From aeed9cb0205ab3621190188c44aacf6863b119b4 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Mon, 1 Jun 2020 09:30:13 +0900 Subject: [PATCH 03/16] Release version 1.3.39 Changes: - Add set/unset private sharing - Add testcase for code coverage - Exclude some lines for coverage measurement Change-Id: Ifb849a2b9b03498fb6b8175e557d648d04208ed6 Signed-off-by: Hwankyu Jhun --- packaging/rpc-port.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/rpc-port.spec b/packaging/rpc-port.spec index 1004166..28cf833 100644 --- a/packaging/rpc-port.spec +++ b/packaging/rpc-port.spec @@ -1,6 +1,6 @@ Name: rpc-port Summary: RPC Port library -Version: 1.3.38 +Version: 1.3.39 Release: 0 Group: Application Framework/Libraries License: Apache-2.0 -- 2.7.4 From 25ff486feb0a909631a1f4dfdcdb4b9f294c61a7 Mon Sep 17 00:00:00 2001 From: hyunho Date: Mon, 1 Jun 2020 16:42:23 +0900 Subject: [PATCH 04/16] Add set_private_sharing_array API - rpc_port_set_private_sharing_array Change-Id: I5ca3e6f1708e56b5909de20dffca66ee298e7c69 Signed-off-by: hyunho --- include/rpc-port-internal.h | 4 +++- src/port-internal.cc | 10 +++++++++- src/port-internal.h | 3 ++- src/rpc-port.cc | 13 +++++++++++-- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/include/rpc-port-internal.h b/include/rpc-port-internal.h index 7bb91af..51f8edf 100644 --- a/include/rpc-port-internal.h +++ b/include/rpc-port-internal.h @@ -30,9 +30,11 @@ int rpc_port_stub_create_mockup(rpc_port_stub_h *h, const char *port_name); int rpc_port_proxy_connect_sync(rpc_port_proxy_h h, const char *appid, const char *port_name); -int rpc_port_set_private_sharing(rpc_port_h port, const char *paths[], +int rpc_port_set_private_sharing_array(rpc_port_h port, const char *paths[], unsigned int size); +int rpc_port_set_private_sharing(rpc_port_h port, const char *path); + int rpc_port_unset_private_sharing(rpc_port_h port); #ifdef __cplusplus diff --git a/src/port-internal.cc b/src/port-internal.cc index 55f2dbe..8619a99 100644 --- a/src/port-internal.cc +++ b/src/port-internal.cc @@ -60,13 +60,21 @@ Port::~Port() { close(fd_); } -int Port::SetPrivateSharing(const char *paths[], unsigned int size) { +int Port::SetPrivateSharing(const char* paths[], unsigned int size) { int ret = aul_rpc_port_set_private_sharing(id_.c_str(), paths, size); if (ret != 0) return RPC_PORT_ERROR_IO_ERROR; return RPC_PORT_ERROR_NONE; } +int Port::SetPrivateSharing(const char* path) { + const char* file_list[1] = {path}; + int ret = aul_rpc_port_set_private_sharing(id_.c_str(), file_list, 1); + if (ret != 0) + return RPC_PORT_ERROR_IO_ERROR; + return RPC_PORT_ERROR_NONE; +} + int Port::UnsetPrivateSharing() { int ret = aul_rpc_port_unset_private_sharing(id_.c_str()); if (ret != 0) diff --git a/src/port-internal.h b/src/port-internal.h index 2f0ec39..db94da9 100644 --- a/src/port-internal.h +++ b/src/port-internal.h @@ -31,7 +31,8 @@ class Port { Port(int fd, std::string id); virtual ~Port(); - int SetPrivateSharing(const char *paths[], unsigned int size); + int SetPrivateSharing(const char* paths[], unsigned int size); + int SetPrivateSharing(const char* path); int UnsetPrivateSharing(); int Read(void* buf, unsigned int size); diff --git a/src/rpc-port.cc b/src/rpc-port.cc index 932b0a3..9964b96 100644 --- a/src/rpc-port.cc +++ b/src/rpc-port.cc @@ -454,8 +454,8 @@ RPC_API int rpc_port_stub_get_port(rpc_port_stub_h h, return RPC_PORT_ERROR_NONE; } -RPC_API int rpc_port_set_private_sharing(rpc_port_h h, - const char *paths[], unsigned int size) { +RPC_API int rpc_port_set_private_sharing_array(rpc_port_h h, + const char* paths[], unsigned int size) { if (h == nullptr || paths == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; @@ -464,6 +464,15 @@ RPC_API int rpc_port_set_private_sharing(rpc_port_h h, return port->SetPrivateSharing(paths, size); } +RPC_API int rpc_port_set_private_sharing(rpc_port_h h, const char* path) { + if (h == nullptr || path == nullptr) + return RPC_PORT_ERROR_INVALID_PARAMETER; + + auto port = static_cast(h); + + return port->SetPrivateSharing(path); +} + RPC_API int rpc_port_unset_private_sharing(rpc_port_h h) { if (h == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; -- 2.7.4 From b6ffdcd731598fc10e0bf4371cff0a2db84d3746 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Wed, 3 Jun 2020 13:18:16 +0900 Subject: [PATCH 05/16] Add rpc-port-util tool Usage: $ rpc-port-util -n e.g. $ rpc-port-util -n Message Change-Id: I19ffecef1648a3e1ba61891de606a75796b1d5be Signed-off-by: Hwankyu Jhun --- CMakeLists.txt | 5 + conf/rpc-port.conf.in | 17 ++ packaging/rpc-port.manifest | 3 + packaging/rpc-port.spec | 2 + src/debug-port-internal.cc | 358 +++++++++++++++++++++++++++++++++++++++ src/debug-port-internal.hh | 143 ++++++++++++++++ src/log-private.hh | 37 ++++ src/port-internal.cc | 4 +- src/port-internal.h | 6 + src/proxy-internal.cc | 45 ++--- src/proxy-internal.h | 2 +- src/rpc-port.cc | 26 ++- src/shared-queue-internal.hh | 79 +++++++++ src/stub-internal.cc | 40 ++--- src/stub-internal.h | 3 +- utils/CMakeLists.txt | 34 ++++ utils/src/debug-port.cc | 390 +++++++++++++++++++++++++++++++++++++++++++ utils/src/debug-port.hh | 87 ++++++++++ utils/src/log-private.hh | 37 ++++ utils/src/logger.cc | 131 +++++++++++++++ utils/src/logger.hh | 62 +++++++ utils/src/main.cc | 66 ++++++++ utils/src/message.cc | 103 ++++++++++++ utils/src/message.hh | 55 ++++++ utils/src/options.cc | 122 ++++++++++++++ utils/src/options.hh | 67 ++++++++ 26 files changed, 1873 insertions(+), 51 deletions(-) create mode 100644 conf/rpc-port.conf.in create mode 100644 src/debug-port-internal.cc create mode 100644 src/debug-port-internal.hh create mode 100644 src/log-private.hh create mode 100644 src/shared-queue-internal.hh create mode 100644 utils/CMakeLists.txt create mode 100644 utils/src/debug-port.cc create mode 100644 utils/src/debug-port.hh create mode 100644 utils/src/log-private.hh create mode 100644 utils/src/logger.cc create mode 100644 utils/src/logger.hh create mode 100644 utils/src/main.cc create mode 100644 utils/src/message.cc create mode 100644 utils/src/message.hh create mode 100644 utils/src/options.cc create mode 100644 utils/src/options.hh diff --git a/CMakeLists.txt b/CMakeLists.txt index bdc8943..82d5c9e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,9 @@ INSTALL(TARGETS ${this_target} DESTINATION ${LIB_INSTALL_DIR}) INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/include/ DESTINATION include/rpc-port FILES_MATCHING PATTERN "*.h") INSTALL(DIRECTORY ${LIBRARY_OUTPUT_PATH}/ DESTINATION ${LIB_INSTALL_DIR} FILES_MATCHING PATTERN "*.so*") +CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/conf/rpc-port.conf.in ${CMAKE_SOURCE_DIR}/conf/rpc-port.conf @ONLY) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/conf/rpc-port.conf DESTINATION /etc/dbus-1/system.d) + IF(NOT DEFINED MINIMUM_BUILD) ENABLE_TESTING() SET(RPC_PORT_UNITTESTS rpc-port_unittests) @@ -65,3 +68,5 @@ ADD_TEST(NAME ${RPC_PORT_UNITTESTS} COMMAND ${RPC_PORT_UNITTESTS} ADD_SUBDIRECTORY(unit_tests) ADD_DEPENDENCIES(${RPC_PORT_UNITTESTS} rpc-port) ENDIF(NOT DEFINED MINIMUM_BUILD) + +ADD_SUBDIRECTORY(utils) diff --git a/conf/rpc-port.conf.in b/conf/rpc-port.conf.in new file mode 100644 index 0000000..2447548 --- /dev/null +++ b/conf/rpc-port.conf.in @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + diff --git a/packaging/rpc-port.manifest b/packaging/rpc-port.manifest index 75b0fa5..2aab1dc 100644 --- a/packaging/rpc-port.manifest +++ b/packaging/rpc-port.manifest @@ -2,4 +2,7 @@ + + + diff --git a/packaging/rpc-port.spec b/packaging/rpc-port.spec index 28cf833..494c1a3 100644 --- a/packaging/rpc-port.spec +++ b/packaging/rpc-port.spec @@ -117,6 +117,8 @@ install -m 0644 gcov-obj/* %{buildroot}%{_datadir}/gcov/obj %manifest %{name}.manifest %attr(0644,root,root) %{_libdir}/lib%{name}.so.* %license LICENSE.APLv2 +%{_bindir}/rpc-port-util +%config %{_sysconfdir}/dbus-1/system.d/rpc-port.conf %files devel %{_includedir}/rpc-port/*.h diff --git a/src/debug-port-internal.cc b/src/debug-port-internal.cc new file mode 100644 index 0000000..dc1b0ba --- /dev/null +++ b/src/debug-port-internal.cc @@ -0,0 +1,358 @@ +/* + * 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 +#include +#include +#include + +#include "debug-port-internal.hh" +#include "log-private.hh" +#include "parcel-internal.h" + +namespace rpc_port { +namespace internal { + +static const char PATH_RPC_PORT_UTIL_SOCK[] = + "/run/aul/daemons/.rpc-port-util-sock"; +static const char RPC_PORT_SIGNAL_PATH[] = "/Org/Tizen/RPC/Port/Signal"; +static const char RPC_PORT_SIGNAL_INTERFACE[] = "org.tizen.rpc.port.signal"; +static const char RPC_PORT_SIGNAL_DEBUG[] = "Debug"; +static const char RPC_PORT_SIGNAL_NEW[] = "New"; + +DebugPort::~DebugPort() { + if (!disposed_) + Dispose(); +} + +void DebugPort::Dispose() { + Unwatch(); + Unsubscribe(); + JoinThread(); + disposed_ = true; +} + +bool DebugPort::IsConnected() { + std::lock_guard lock(GetMutex()); + return connected_; +} + +void DebugPort::AddSession(std::string port_name, std::string destination, + int main_port, int delegate_port) { + std::lock_guard lock(GetMutex()); + sessions_.emplace_back( + new DebugPort::Session( + port_name, destination, main_port, delegate_port)); +} + +void DebugPort::RemoveSession(int port) { + std::lock_guard lock(GetMutex()); + auto iter = sessions_.begin(); + while (iter != sessions_.end()) { + if ((*iter)->GetMainPort() == port || + (*iter)->GetDelegatePort() == port) { + _W("Remove session. port(%d)", port); + iter = sessions_.erase(iter); + break; + } + + ++iter; + } +} + +std::shared_ptr DebugPort::FindSession(int port) { + std::lock_guard lock(GetMutex()); + for (auto& s : sessions_) { + if (s->GetMainPort() == port || s->GetDelegatePort() == port) + return s; + } + + return {}; +} + +int DebugPort::Send(int port, bool is_read, uint32_t seq, + const void* buf, unsigned int size) { + std::lock_guard lock(GetMutex()); + if (!IsConnected()) + return -1; + + auto session = FindSession(port); + if (session.get() == nullptr) { + _E("Failed to find session. port(%d)", port); + return -1; + } + + // time + port_name + destination + is_delegate + port + is_read + seq + size + data + Parcel parcel; + parcel.WriteInt64(time(nullptr)); + parcel.WriteString(session->GetPortName().c_str()); + parcel.WriteString(session->GetDestination().c_str()); + parcel.WriteBool(session->GetDelegatePort() == port); + parcel.WriteInt32(port); + parcel.WriteBool(is_read); + parcel.WriteInt32(seq); + parcel.WriteInt32(size); + parcel.Write(static_cast(buf), size); + + queue_.Push(std::make_shared(parcel)); + return 0; +} + +void DebugPort::Init() { + Subscribe(); + EmitSignal(RPC_PORT_SIGNAL_NEW); + is_running_ = false; + disposed_ = false; +} + +int DebugPort::Connect() { + int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd < 0) { + _E("socket() is failed. errno(%d)", errno); + return -1; + } + + struct sockaddr_un addr = { 0, }; + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", PATH_RPC_PORT_UTIL_SOCK); + + int ret = connect(fd, reinterpret_cast(&addr), + sizeof(addr)); + if (ret < 0) { + _E("connect() is failed. fd(%d), errno(%d)", fd, errno); + close(fd); + return -1; + } + + return fd; +} + +int DebugPort::Watch(int fd) { + GIOChannel* io = g_io_channel_unix_new(fd); + if (io == nullptr) { + _E("g_io_channel_unix_new() is failed"); + return -1; + } + + GIOCondition cond = static_cast( + (G_IO_ERR | G_IO_HUP | G_IO_NVAL)); + guint tag = g_io_add_watch(io, cond, OnDebugPortDisconnectedCb, this); + if (tag == 0) { + _E("g_io_add_watch() is failed"); + g_io_channel_unref(io); + return -1; + } + + io_ = io; + watch_tag_ = tag; + return 0; +} + +void DebugPort::Unwatch() { + if (watch_tag_) { + g_source_remove(watch_tag_); + watch_tag_ = 0; + } + + if (io_) { + g_io_channel_unref(io_); + io_ = nullptr; + } +} + +gboolean DebugPort::OnDebugPortDisconnectedCb(GIOChannel* io, + GIOCondition cond, gpointer data) { + _W("cond(%d)", static_cast(cond)); + auto* debug_port = static_cast(data); + std::lock_guard lock(debug_port->GetMutex()); + debug_port->SetConnectionStatus(false); + debug_port->watch_tag_ = 0; + debug_port->Unwatch(); + debug_port->port_.reset(); + _W("Disconnected"); + return G_SOURCE_REMOVE; +} + +GDBusConnection* DebugPort::GetConnection() { + if (conn_) + return conn_; + + GError* error = nullptr; + conn_ = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error); + if (conn_ == nullptr) { + _E("g_bus_get_sync() is failed. error(%s)", + error ? error->message : "unknown"); + g_clear_error(&error); + return nullptr; + } + + return conn_; +} + +void DebugPort::Subscribe() { + GDBusConnection* conn = GetConnection(); + if (conn == nullptr) + return; + + subs_tag_ = g_dbus_connection_signal_subscribe(conn, + nullptr, + RPC_PORT_SIGNAL_INTERFACE, + RPC_PORT_SIGNAL_DEBUG, + RPC_PORT_SIGNAL_PATH, + nullptr, + G_DBUS_SIGNAL_FLAGS_NONE, + OnGDBusSignalCb, + this, + nullptr); + if (subs_tag_ == 0) { + _E("g_dbus_connection_signal_subscribe() is failed"); + return; + } + + _D("tag(%u)", subs_tag_); +} + +void DebugPort::Unsubscribe() { + if (subs_tag_) + g_dbus_connection_signal_unsubscribe(conn_, subs_tag_); + + if (conn_) + g_object_unref(conn_); +} + +void DebugPort::EmitSignal(std::string signal) { + GDBusConnection* conn = GetConnection(); + if (conn == nullptr) + return; + + GError* error = nullptr; + gboolean ret = g_dbus_connection_emit_signal(conn, + nullptr, + RPC_PORT_SIGNAL_PATH, + RPC_PORT_SIGNAL_INTERFACE, + signal.c_str(), + nullptr, + &error); + if (ret != TRUE) { + _E("g_dbus_connection_emit_signal() is failed. error(%s)", + error ? error->message : "unknown"); + g_clear_error(&error); + return; + } + + ret = g_dbus_connection_flush_sync(conn, nullptr, &error); + if (ret != TRUE) { + _E("g_dbus_connection_flush_sync() is failed. error(%s)", + error ? error->message : "unknown"); + g_clear_error(&error); + return; + } + + _W("EmitSignal(%s)", signal.c_str()); +} + +void DebugPort::OnGDBusSignalCb(GDBusConnection *connection, + const gchar* sender_name, + const gchar* object_path, + const gchar* interface_name, + const gchar* signal_name, + GVariant* parameters, + gpointer user_data) { + _W("signal_name(%s)", signal_name); + std::string signal(signal_name); + if (signal != RPC_PORT_SIGNAL_DEBUG) + return; + + gchar* port_name = nullptr; + gint pid = -1; + g_variant_get(parameters, "(&si)", &port_name, &pid); + _W("port_name(%s), pid(%d)", port_name, pid); + + if (pid != 0 && pid != getpid()) { + _W("Invalid pid(%d)", pid); + return; + } + + auto* debug_port = static_cast(user_data); + int fd = debug_port->Connect(); + if (fd < 0) + return; + + std::lock_guard lock(debug_port->GetMutex()); + debug_port->port_.reset(new Port(fd, signal)); + int ret = debug_port->Watch(fd); + if (ret < 0) + return; + + debug_port->CreateThread(); + debug_port->SetConnectionStatus(true); + _W("Connected"); +} + +void DebugPort::SetConnectionStatus(bool status) { + std::lock_guard lock(GetMutex()); + connected_ = status; +} + +void DebugPort::CreateThread() { + if (is_running_) + return; + + thread_ = std::thread([&]() { + _W("START"); + do { + std::shared_ptr parcel; + queue_.WaitAndPop(parcel); + int len = parcel->GetRaw().size(); + if (len == 0) { + _W("Done"); + break; + } + + if (!IsConnected()) + continue; + + int ret = port_->Write(reinterpret_cast(&len), sizeof(len)); + if (ret < 0) { + _E("Failed to write size"); + SetConnectionStatus(false); + continue; + } + + ret = port_->Write(&*parcel->GetRaw().cbegin(), len); + if (ret < 0) { + _E("Failed to write data"); + SetConnectionStatus(false); + } + } while (true); + _W("END"); + }); + + is_running_ = true; +} + +void DebugPort::JoinThread() { + if (is_running_) + queue_.Push(std::shared_ptr(new Parcel())); + + if (thread_.joinable()) { + _W("Join thread"); + thread_.join(); + } +} + +} // namespace internal +} // namespace rpc_port diff --git a/src/debug-port-internal.hh b/src/debug-port-internal.hh new file mode 100644 index 0000000..3fa25e7 --- /dev/null +++ b/src/debug-port-internal.hh @@ -0,0 +1,143 @@ +/* + * 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 DEBUG_PORT_INTERNAL_HH_ +#define DEBUG_PORT_INTERNAL_HH_ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "parcel-internal.h" +#include "port-internal.h" +#include "shared-queue-internal.hh" + +namespace rpc_port { +namespace internal { + +class DebugPort { + private: + DebugPort() = default; + ~DebugPort(); + + public: + class Session { + public: + Session(std::string port_name, std::string destination, + int main_port, int delegate_port) + : port_name_(std::move(port_name)), + destination_(std::move(destination)), + main_port_(main_port), + delegate_port_(delegate_port) { + } + virtual ~Session() = default; + + const std::string& GetPortName() { + return port_name_; + } + + const std::string& GetDestination() { + return destination_; + } + + int GetMainPort() { + return main_port_; + } + + int GetDelegatePort() { + return delegate_port_; + } + + private: + std::string port_name_; + std::string destination_; + int main_port_; + int delegate_port_; + }; + + static DebugPort& GetInst() { + static DebugPort inst; + + std::lock_guard lock(inst.GetMutex()); + if (inst.disposed_) + inst.Init(); + return inst; + } + + void Dispose(); + bool IsConnected(); + + void AddSession(std::string port_name, std::string destination, + int main_port, int delegate_port); + void RemoveSession(int port); + + int Send(int port, bool is_read, uint32_t seq, + const void* buf, unsigned int size); + + private: + std::recursive_mutex& GetMutex() const { + return mutex_; + } + + void Init(); + int Connect(); + int Watch(int fd); + void Unwatch(); + GDBusConnection* GetConnection(); + void Subscribe(); + void Unsubscribe(); + void EmitSignal(std::string signal); + void SetConnectionStatus(bool status); + void CreateThread(); + void JoinThread(); + + std::shared_ptr FindSession(int port); + + static gboolean OnDebugPortDisconnectedCb(GIOChannel* io, + GIOCondition cond, gpointer data); + static void OnGDBusSignalCb(GDBusConnection *connection, + const gchar* sender_name, + const gchar* object_path, + const gchar* interface_name, + const gchar* signal_name, + GVariant* parameters, + gpointer user_data); + + private: + bool disposed_ = true; + bool connected_ = false; + GDBusConnection* conn_ = nullptr; + guint subs_tag_ = 0; + std::unique_ptr port_; + GIOChannel* io_ = nullptr; + guint watch_tag_ = 0; + std::list> sessions_; + std::thread thread_; + std::atomic is_running_; + SharedQueue> queue_; + mutable std::recursive_mutex mutex_; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // DEBUG_PORT_INTERNAL_HH_ diff --git a/src/log-private.hh b/src/log-private.hh new file mode 100644 index 0000000..6c6b2d6 --- /dev/null +++ b/src/log-private.hh @@ -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 LOG_PRIVATE_HH_ +#define LOG_PRIVATE_HH_ + +#include + +#undef LOG_TAG +#define LOG_TAG "RPC_PORT" + +#undef _E +#define _E LOGE + +#undef _W +#define _W LOGW + +#undef _I +#define _I LOGI + +#undef _D +#define _D LOGD + +#endif // LOG_PRIVATE_HH_ diff --git a/src/port-internal.cc b/src/port-internal.cc index 8619a99..b1adf36 100644 --- a/src/port-internal.cc +++ b/src/port-internal.cc @@ -45,7 +45,7 @@ namespace rpc_port { namespace internal { Port::Port(int fd, std::string id) - : fd_(fd), id_(std::move(id)) { + : fd_(fd), id_(std::move(id)), instance_(""), seq_(0) { char uuid[37]; uuid_t u; uuid_generate(u); @@ -54,7 +54,7 @@ Port::Port(int fd, std::string id) } Port::Port(int fd, std::string id, std::string instance) - : fd_(fd), id_(std::move(id)), instance_(std::move(instance)) {} + : fd_(fd), id_(std::move(id)), instance_(std::move(instance)), seq_(0) {} Port::~Port() { close(fd_); diff --git a/src/port-internal.h b/src/port-internal.h index db94da9..5c4fb1f 100644 --- a/src/port-internal.h +++ b/src/port-internal.h @@ -21,6 +21,7 @@ #include #include #include +#include namespace rpc_port { namespace internal { @@ -53,10 +54,15 @@ class Port { return instance_; } + uint32_t GetSeq() { + return ++seq_; + } + private: int fd_; std::string id_; std::string instance_; + std::atomic seq_; mutable std::recursive_mutex mutex_; }; diff --git a/src/proxy-internal.cc b/src/proxy-internal.cc index 3d45bc2..dcbe1bf 100644 --- a/src/proxy-internal.cc +++ b/src/proxy-internal.cc @@ -22,14 +22,10 @@ #include #include +#include "debug-port-internal.hh" +#include "log-private.hh" #include "proxy-internal.h" -#ifdef LOG_TAG -#undef LOG_TAG -#endif - -#define LOG_TAG "RPC_PORT" - #define EILLEGALACCESS 127 namespace rpc_port { @@ -39,7 +35,7 @@ Proxy::Proxy(bool mock) : fd_broker_(mock) {} Proxy::~Proxy() { - LOGD("Proxy::~Proxy"); + _D("Proxy::~Proxy"); if (conn_timer_) { g_source_remove(conn_timer_); // LCOV_EXCL_LINE conn_timer_ = 0; // LCOV_EXCL_LINE @@ -52,7 +48,7 @@ gboolean Proxy::OnSocketDisconnected(GIOChannel *gio, GIOCondition cond, IEventListener* listener = proxy->listener_; int fd = g_io_channel_unix_get_fd(gio); - LOGW("Socket was disconnected. fd(%d)", fd); + _W("Socket was disconnected. fd(%d)", fd); if (proxy->main_port_.get()->GetFd() == fd) { proxy->listener_ = nullptr; @@ -71,6 +67,7 @@ gboolean Proxy::OnSocketDisconnected(GIOChannel *gio, GIOCondition cond, proxy->main_port_.reset(); proxy->delegate_port_.reset(); } + DebugPort::GetInst().RemoveSession(fd); return FALSE; } @@ -83,13 +80,14 @@ gboolean Proxy::OnDataReceived(GIOChannel *gio, GIOCondition cond, if (proxy->delegate_port_.get()->GetFd() == fd) { if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) { - LOGW("Socket was disconnected by stub. fd(%d)", fd); + _W("Socket was disconnected by stub. fd(%d)", fd); IEventListener* listener = proxy->listener_; proxy->listener_ = nullptr; proxy->delegate_port_.get()->SetSource(0); if (listener) listener->OnDisconnected(proxy->target_appid_); + DebugPort::GetInst().RemoveSession(proxy->main_port_->GetFd()); proxy->main_port_.reset(); proxy->delegate_port_.reset(); return FALSE; @@ -113,7 +111,7 @@ void Proxy::OnPortRejected(const std::string& appid) { void Proxy::OnPortAppeared(const std::string& appid, const std::string& port_name) { - LOGD("endpoint(%s), port_name(%s)", appid.c_str(), port_name.c_str()); + _D("endpoint(%s), port_name(%s)", appid.c_str(), port_name.c_str()); if (conn_timer_) { g_source_remove(conn_timer_); conn_timer_ = 0; @@ -137,33 +135,34 @@ void Proxy::OnPortAppeared(const std::string& appid, // LCOV_EXCL_STOP } - LOGW("[__OnPortAppeared__] fds[0]: %d, fds[1]: %d", fds_[0], fds_[1]); + _W("[__OnPortAppeared__] fds[0]: %d, fds[1]: %d", fds_[0], fds_[1]); } void Proxy::OnPortVanished(const std::string& appid, const std::string& port_name) { - LOGW("[__OnPortVanished__] endpoint(%s), port_name(%s)", + _W("[__OnPortVanished__] endpoint(%s), port_name(%s)", appid.c_str(), port_name.c_str()); } void Proxy::OnPortConnected(const std::string& appid, const std::string& port_name) { - LOGW("[__OnPortConnected__] endpoint(%s), port_name(%s)", + _W("[__OnPortConnected__] endpoint(%s), port_name(%s)", appid.c_str(), port_name.c_str()); if (!listener_) { - LOGW("listener is null"); // LCOV_EXCL_LINE + _W("listener is null"); // LCOV_EXCL_LINE return; // LCOV_EXCL_LINE } main_port_.reset(new ProxyPort(this, fds_[0], appid, false)); delegate_port_.reset(new ProxyPort(this, fds_[1], appid)); listener_->OnConnected(appid, main_port_.get()); + DebugPort::GetInst().AddSession(port_name, appid, fds_[0], fds_[1]); } // LCOV_EXCL_START void Proxy::OnPortDisconnected(const std::string& appid, const std::string& port_name, bool cancel) { - LOGW("[__OnPortDisconnected__] endporint(%s), port_name(%s)", + _W("[__OnPortDisconnected__] endporint(%s), port_name(%s)", appid.c_str(), port_name.c_str()); if (cancel) { @@ -172,13 +171,14 @@ void Proxy::OnPortDisconnected(const std::string& appid, } if (!listener_) { - LOGW("listener is null"); + _W("listener is null"); return; } IEventListener* listener = listener_; listener_ = nullptr; listener->OnDisconnected(appid); + DebugPort::GetInst().RemoveSession(fds_[0]); } // LCOV_EXCL_STOP @@ -188,7 +188,7 @@ int Proxy::Connect(std::string appid, std::string port_name, return RPC_PORT_ERROR_INVALID_PARAMETER; if (listener_ != nullptr) { - LOGD("Already connected"); // LCOV_EXCL_LINE + _D("Already connected"); // LCOV_EXCL_LINE return RPC_PORT_ERROR_INVALID_PARAMETER; // LCOV_EXCL_LINE } @@ -222,7 +222,7 @@ int Proxy::ConnectSync(std::string appid, std::string port_name, return RPC_PORT_ERROR_INVALID_PARAMETER; if (listener_ != nullptr) { - LOGW("Already connected"); + _W("Already connected"); return RPC_PORT_ERROR_INVALID_PARAMETER; } @@ -253,6 +253,7 @@ int Proxy::ConnectSync(std::string appid, std::string port_name, main_port_.reset(new ProxyPort(this, fds_[0], target_appid_, false)); delegate_port_.reset(new ProxyPort(this, fds_[1], target_appid_)); listener_->OnConnected(target_appid_, main_port_.get()); + DebugPort::GetInst().AddSession(port_name, appid, fds_[0], fds_[1]); return RPC_PORT_ERROR_NONE; } @@ -262,7 +263,7 @@ int Proxy::ConnectSync(std::string appid, std::string port_name, gboolean Proxy::DbusNameTimeout(gpointer user_data) { Proxy* obj = static_cast(user_data); - LOGW("[__DbusNameTimeout__] endpoint(%s)", obj->target_appid_.c_str()); + _W("[__DbusNameTimeout__] endpoint(%s)", obj->target_appid_.c_str()); obj->conn_timer_ = 0; if (obj->listener_) { IEventListener* listener = obj->listener_; @@ -297,7 +298,7 @@ int Proxy::ProxyPort::Watch(bool receive) { gioc_ = g_io_channel_unix_new(fd); if (!gioc_) { - LOGE("Error is %s", strerror_r(errno, buf, sizeof(buf))); // LCOV_EXCL_LINE + _E("Error is %s", strerror_r(errno, buf, sizeof(buf))); // LCOV_EXCL_LINE return -1; // LCOV_EXCL_LINE } @@ -306,7 +307,7 @@ int Proxy::ProxyPort::Watch(bool receive) { Proxy::OnSocketDisconnected, parent_); if (disconn_src_ == 0) { // LCOV_EXCL_START - LOGE("Failed to add watch on socket"); + _E("Failed to add watch on socket"); g_io_channel_unref(gioc_); gioc_ = nullptr; return -1; @@ -321,7 +322,7 @@ int Proxy::ProxyPort::Watch(bool receive) { Proxy::OnDataReceived, parent_); if (src_ == 0) { // LCOV_EXCL_START - LOGE("Failed to add watch on socket"); + _E("Failed to add watch on socket"); g_source_remove(disconn_src_); disconn_src_ = 0; g_io_channel_unref(gioc_); diff --git a/src/proxy-internal.h b/src/proxy-internal.h index 61c1318..63cbf52 100644 --- a/src/proxy-internal.h +++ b/src/proxy-internal.h @@ -24,8 +24,8 @@ #include #include -#include "port-internal.h" #include "fdbroker-internal.h" +#include "port-internal.h" namespace rpc_port { namespace internal { diff --git a/src/rpc-port.cc b/src/rpc-port.cc index 9964b96..cba0110 100644 --- a/src/rpc-port.cc +++ b/src/rpc-port.cc @@ -182,8 +182,18 @@ RPC_API int rpc_port_read(rpc_port_h h, void* buf, unsigned int size) { return RPC_PORT_ERROR_INVALID_PARAMETER; auto port = static_cast(h); + uint32_t seq = 0; + int ret = port->Read(reinterpret_cast(&seq), sizeof(seq)); + if (ret < 0) + return ret; - return port->Read(buf, size); + ret = port->Read(buf, size); + if (ret < 0) + return ret; + + auto& debug_port = DebugPort::GetInst(); + debug_port.Send(port->GetFd(), true, seq, buf, size); + return RPC_PORT_ERROR_NONE; } RPC_API int rpc_port_write(rpc_port_h h, const void* buf, unsigned int size) { @@ -191,8 +201,18 @@ RPC_API int rpc_port_write(rpc_port_h h, const void* buf, unsigned int size) { return RPC_PORT_ERROR_INVALID_PARAMETER; auto port = static_cast(h); + uint32_t seq = port->GetSeq(); + int ret = port->Write(reinterpret_cast(&seq), sizeof(seq)); + if (ret < 0) + return ret; + + ret = port->Write(buf, size); + if (ret < 0) + return ret; - return port->Write(buf, size); + auto& debug_port = DebugPort::GetInst(); + debug_port.Send(port->GetFd(), false, seq, buf, size); + return RPC_PORT_ERROR_NONE; } RPC_API int rpc_port_proxy_create(rpc_port_proxy_h* h) { @@ -480,4 +500,4 @@ RPC_API int rpc_port_unset_private_sharing(rpc_port_h h) { auto port = static_cast(h); return port->UnsetPrivateSharing(); -} \ No newline at end of file +} diff --git a/src/shared-queue-internal.hh b/src/shared-queue-internal.hh new file mode 100644 index 0000000..2ea1a87 --- /dev/null +++ b/src/shared-queue-internal.hh @@ -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. + */ + +#ifndef SHARED_QUEUE_INTERNAL_HH_ +#define SHARED_QUEUE_INTERNAL_HH_ + +#include +#include +#include +#include + +namespace rpc_port { +namespace internal { + +template +class SharedQueue { + public: + SharedQueue() = default; + virtual ~SharedQueue() = default; + + void Push(T item) { + std::lock_guard lock(mutex_); + queue_.push(item); + cond_var_.notify_one(); + } + + bool TryAndPop(T& item) { + std::lock_guard lock(mutex_); + if (queue_.empty()) + return false; + + item = queue_.front(); + queue_.pop_front(); + + return true; + } + + void WaitAndPop(T& item) { + std::unique_lock lock(mutex_); + while (queue_.empty()) + cond_var_.wait(lock); + + item = queue_.front(); + queue_.pop(); + } + + bool Empty() { + std::lock_guard lock(mutex_); + return queue_.empty(); + } + + int Size() { + std::lock_guard lock(mutex_); + return queue_.size(); + } + + private: + std::queue queue_; + mutable std::mutex mutex_; + std::condition_variable cond_var_; +}; + +} // namespace internal +} // namespace rpc_port + +#endif // SHARED_QUEUE_INTERNAL_HH_ diff --git a/src/stub-internal.cc b/src/stub-internal.cc index 8b0476a..f73f3d2 100644 --- a/src/stub-internal.cc +++ b/src/stub-internal.cc @@ -14,32 +14,26 @@ * limitations under the License. */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - #include #include #include #include #include +#include "debug-port-internal.hh" +#include "log-private.hh" #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, bool mock) - : fd_broker_(mock), port_name_(port_name) {} + : fd_broker_(mock), + port_name_(port_name) { +} Stub::~Stub() { - LOGD("Stub::~Stub"); + _D("Stub::~Stub"); } int Stub::Listen(IEventListener* ev) { @@ -86,6 +80,7 @@ void Stub::RemoveAcceptedPorts(std::string instance) { while (iter != ports_.end()) { if ((*iter)->GetInstance().compare(instance) == 0) { LOGI("Close: fd(%d)", (*iter)->GetFd()); + DebugPort::GetInst().RemoveSession((*iter)->GetFd()); iter = ports_.erase(iter); } else { iter++; @@ -102,12 +97,12 @@ gboolean Stub::OnDataReceived(GIOChannel *gio, GIOCondition cond, for (auto& p : stub->ports_) { if (p->GetFd() == fd && !p->IsDelegate()) { if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) { - LOGW("Socket was disconnected from proxy. fd(%d)", fd); + _W("Socket was disconnected from proxy. fd(%d)", fd); stub->listener_->OnDisconnected(p->GetId(), p->GetInstance()); stub->RemoveAcceptedPorts(p->GetInstance()); if (aul_rpc_port_notify_rpc_finished() != AUL_R_OK) - LOGW("Failed to notify rpc finished"); // LCOV_EXCL_LINE + _W("Failed to notify rpc finished"); // LCOV_EXCL_LINE return FALSE; } @@ -116,12 +111,12 @@ gboolean Stub::OnDataReceived(GIOChannel *gio, GIOCondition cond, p.get()); if (ret != 0) { - LOGW("Invalid protocol"); + _W("Invalid protocol"); stub->listener_->OnDisconnected(p->GetId(), p->GetInstance()); stub->RemoveAcceptedPorts(p->GetInstance()); if (aul_rpc_port_notify_rpc_finished() != AUL_R_OK) - LOGW("Failed to notify rpc finished"); // LCOV_EXCL_LINE + _W("Failed to notify rpc finished"); // LCOV_EXCL_LINE return FALSE; } @@ -138,12 +133,12 @@ gboolean Stub::OnSocketDisconnected(GIOChannel *gio, GIOCondition cond, Stub* stub = static_cast(data); int fd = g_io_channel_unix_get_fd(gio); - LOGW("Socket was disconnected. fd(%d)", fd); + _W("Socket was disconnected. fd(%d)", fd); for (auto& p : stub->ports_) { if (p->GetFd() == fd) { stub->listener_->OnDisconnected(p->GetId(), p->GetInstance()); if (aul_rpc_port_notify_rpc_finished() != AUL_R_OK) - LOGW("Failed to notify rpc finished"); // LCOV_EXCL_LINE + _W("Failed to notify rpc finished"); // LCOV_EXCL_LINE stub->RemoveAcceptedPorts(p->GetInstance()); break; } @@ -153,7 +148,7 @@ gboolean Stub::OnSocketDisconnected(GIOChannel *gio, GIOCondition cond, } void Stub::OnFdReceived(const std::string& sender, int fds[2]) { - LOGW("[__OnFdReceived__] fds[0]: %d, fds[1]: %d", fds[0], fds[1]); + _W("[__OnFdReceived__] fds[0]: %d, fds[1]: %d", fds[0], fds[1]); auto* main_port = new AcceptedPort(this, false, fds[0], sender, true); ports_.emplace_back(main_port); ports_.emplace_back(new AcceptedPort(this, true, fds[1], sender, @@ -164,6 +159,7 @@ void Stub::OnFdReceived(const std::string& sender, int fds[2]) { break; } } + DebugPort::GetInst().AddSession(port_name_, sender, fds[0], fds[1]); } Stub::AcceptedPort::AcceptedPort(Stub* parent, bool isDelegate, int fd, @@ -198,7 +194,7 @@ int Stub::AcceptedPort::Watch(bool receive) { gioc_ = g_io_channel_unix_new(fd); if (!gioc_) { // LCOV_EXCL_START - LOGE("Error is %s", strerror_r(errno, buf, sizeof(buf))); + _E("Error is %s", strerror_r(errno, buf, sizeof(buf))); return -1; // LCOV_EXCL_STOP } @@ -208,7 +204,7 @@ int Stub::AcceptedPort::Watch(bool receive) { Stub::OnSocketDisconnected, parent_); if (disconn_src_ == 0) { // LCOV_EXCL_START - LOGE("fail to add watch on socket"); + _E("fail to add watch on socket"); g_io_channel_unref(gioc_); gioc_ = nullptr; return -1; @@ -223,7 +219,7 @@ int Stub::AcceptedPort::Watch(bool receive) { Stub::OnDataReceived, parent_); if (src_ == 0) { // LCOV_EXCL_START - LOGE("fail to add watch on socket"); + _E("fail to add watch on socket"); g_source_remove(disconn_src_); disconn_src_ = 0; g_io_channel_unref(gioc_); diff --git a/src/stub-internal.h b/src/stub-internal.h index cff2e7b..54022d2 100644 --- a/src/stub-internal.h +++ b/src/stub-internal.h @@ -25,8 +25,9 @@ #include #include -#include "port-internal.h" +#include "debug-port-internal.hh" #include "fdbroker-internal.h" +#include "port-internal.h" namespace rpc_port { namespace internal { diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt new file mode 100644 index 0000000..c639ff2 --- /dev/null +++ b/utils/CMakeLists.txt @@ -0,0 +1,34 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) +PROJECT(rpc-port-util CXX) + +INCLUDE(FindPkgConfig) +pkg_check_modules(rpc-port-util REQUIRED + aul + bundle + dlog + glib-2.0 +) + +FOREACH(flag ${rpc-port-util_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -Wall -Werror -Winline -fPIE") + +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} -std=c++14") +SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") +SET(CMAKE_CXX_FLAGS_RELEASE "-O2") +SET(SOURCES "") + +ADD_DEFINITIONS("-DFULLVER=\"${FULLVER}\"") + +INCLUDE_DIRECTORIES( + ${CMAKE_CURRENT_SOURCE_DIR}/../ + ${CMAKE_CURRENT_SOURCE_DIR}/../include + ) + +AUX_SOURCE_DIRECTORY(src SOURCES) +ADD_EXECUTABLE(${PROJECT_NAME} ${SOURCES}) + +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${rpc-port-util_LDFLAGS} "-pie" rpc-port) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION /usr/bin) diff --git a/utils/src/debug-port.cc b/utils/src/debug-port.cc new file mode 100644 index 0000000..7a5229b --- /dev/null +++ b/utils/src/debug-port.cc @@ -0,0 +1,390 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include +#include + +#include "debug-port.hh" +#include "log-private.hh" +#include "message.hh" + +namespace rpc_port { +namespace util { + +static const char PATH_RPC_PORT_UTIL_SOCK[] = + "/run/aul/daemons/.rpc-port-util-sock"; +static const char RPC_PORT_SIGNAL_PATH[] = "/Org/Tizen/RPC/Port/Signal"; +static const char RPC_PORT_SIGNAL_INTERFACE[] = "org.tizen.rpc.port.signal"; +static const char RPC_PORT_SIGNAL_DEBUG[] = "Debug"; +static const char RPC_PORT_SIGNAL_NEW[] = "New"; + +class DisconnectedEvent { + public: + DisconnectedEvent(int pid, int fd, void* data) + : pid_(pid), fd_(fd), data_(data) { + } + + int GetPid() { + return pid_; + } + + int GetFd() { + return fd_; + } + + void* GetData() { + return data_; + } + + private: + int pid_; + int fd_; + void* data_; +}; + +DebugPort::DebugPort(std::string port_name, int pid) + : port_name_(std::move(port_name)), + pid_(pid) { + Subscribe(); + + int fd = CreateSocket(); + if (fd < 0) { + _E("Failed to create socket"); + exit(EXIT_FAILURE); + } + + fd_ = fd; + Watch(fd_); +} + +DebugPort::~DebugPort() { + Unwatch(); + + if (fd_ > 0) + close(fd_); + + Unsubscribe(); +} + +void DebugPort::EmitSignal() { + GDBusConnection* conn = GetConnection(); + if (conn == nullptr) + return; + + GError* error = nullptr; + gboolean ret = g_dbus_connection_emit_signal(conn, + nullptr, + RPC_PORT_SIGNAL_PATH, + RPC_PORT_SIGNAL_INTERFACE, + RPC_PORT_SIGNAL_DEBUG, + g_variant_new("(si)", port_name_.c_str(), pid_), + &error); + if (ret != TRUE) { + _E("g_dbus_connection_emit_signal() is failed. error(%s)", + error ? error->message : "Unknown"); + g_clear_error(&error); + return; + } + + ret = g_dbus_connection_flush_sync(conn, nullptr, &error); + if (ret != TRUE) { + _E("g_dbus_connection_flush_sync() is failed. error(%s)", + error ? error->message : "Unknown"); + g_clear_error(&error); + return; + } + + _W("EmitSignal"); +} + +GDBusConnection* DebugPort::GetConnection() { + if (conn_) + return conn_; + + GError* error = nullptr; + conn_ = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error); + if (conn_ == nullptr) { + _E("g_bus_get_sync() is failed. error(%s)", + error ? error->message : "Unknown"); + g_clear_error(&error); + return nullptr; + } + + return conn_; +} + +void DebugPort::Subscribe() { + GDBusConnection* conn = GetConnection(); + if (conn == nullptr) + return; + + subs_tag_ = g_dbus_connection_signal_subscribe(conn, + nullptr, + RPC_PORT_SIGNAL_INTERFACE, + RPC_PORT_SIGNAL_NEW, + RPC_PORT_SIGNAL_PATH, + nullptr, + G_DBUS_SIGNAL_FLAGS_NONE, + OnGDBusSignalCb, + this, + nullptr); + if (subs_tag_ == 0) { + _E("g_dbus_connection_signal_subscribe() is failed"); + return; + } + + _W("tag(%u)", subs_tag_); +} + +void DebugPort::Unsubscribe() { + if (subs_tag_) + g_dbus_connection_signal_unsubscribe(conn_, subs_tag_); + + if (conn_) + g_object_unref(conn_); +} + +int DebugPort::CreateSocket() { + int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd < 0) { + _E("socket() is failed. errno(%d)", errno); + return -1; + } + + struct sockaddr_un addr = { 0, }; + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", PATH_RPC_PORT_UTIL_SOCK); + unlink(addr.sun_path); + + int ret = bind(fd, reinterpret_cast(&addr), sizeof(addr)); + if (ret < 0) { + _E("bind() is failed. fd(%d), errno(%d)", fd, errno); + close(fd); + return -1; + } + + ret = listen(fd, 128); + if (ret < 0) { + _E("listen() is failed. fd(%d), errno(%d)", fd, errno); + close(fd); + return -1; + } + + ret = chmod(addr.sun_path, S_ISVTX | S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | + S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH); + if (ret < 0) + _E("chmod() is failed. errno(%d)", errno); + + return fd; +} + +void DebugPort::OnDataReceived(int pid, rpc_port_parcel_h parcel) { + if (pid_ != 0 && pid_ != pid) + return; + + long long time = 0; + rpc_port_parcel_read_int64(parcel, &time); + time_t sent_time = static_cast(time); + + char* port_name = nullptr; + rpc_port_parcel_read_string(parcel, &port_name); + std::unique_ptr port_name_ptr(port_name, + std::free); + if (port_name == nullptr) + return; + + if (port_name != port_name_) + return; + + char* destination = nullptr; + rpc_port_parcel_read_string(parcel, &destination); + std::unique_ptr destination_ptr(destination, + std::free); + + bool is_delegate = false; + rpc_port_parcel_read_bool(parcel, &is_delegate); + + int port = -1; + rpc_port_parcel_read_int32(parcel, &port); + + bool is_read = false; + rpc_port_parcel_read_bool(parcel, &is_read); + + uint32_t seq = 0; + rpc_port_parcel_read_int32(parcel, reinterpret_cast(&seq)); + + unsigned int size = 0; + rpc_port_parcel_read_int32(parcel, reinterpret_cast(&size)); + if (size == 0) { + _E("Invalid size"); + return; + } + + auto* buf = new unsigned char[size]; + rpc_port_parcel_burst_read(parcel, buf, size); + std::vector data(buf, buf + size); + delete[] buf; + + auto* msg = new Message(sent_time, pid, port_name, destination, is_delegate, + port, is_read, seq, data); + g_idle_add([](gpointer data) -> gboolean { + auto* msg = static_cast(data); + msg->Print(); + delete msg; + return G_SOURCE_REMOVE; + }, msg); +} + +void DebugPort::OnDisconnected(int pid, int fd) { + auto* event = new DisconnectedEvent(pid, fd, this); + g_idle_add([](gpointer data) -> gboolean { + auto* event = static_cast(data); + auto* debug_port = static_cast(event->GetData()); + debug_port->RemoveLogger(event->GetPid(), event->GetFd()); + delete event; + return G_SOURCE_REMOVE; + }, event); +} + +void DebugPort::OnGDBusSignalCb(GDBusConnection *connection, + const gchar* sender_name, + const gchar* object_path, + const gchar* interface_name, + const gchar* signal_name, + GVariant* parameters, + gpointer user_data) { + _E("signal_name(%s)", signal_name); + std::string signal(signal_name); + if (signal != RPC_PORT_SIGNAL_NEW) + return; + + auto* debug_port = static_cast(user_data); + debug_port->EmitSignal(); +} + +int DebugPort::Watch(int fd) { + GIOChannel* io = g_io_channel_unix_new(fd); + if (io == nullptr) { + _E("g_io_channel_unix_new() is failed"); + return -1; + } + + GIOCondition cond = static_cast( + (G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL)); + guint tag = g_io_add_watch(io, cond, OnDebugPortConnectedCb, this); + if (tag == 0) { + _E("g_io_add_watch() is failed"); + g_io_channel_unref(io); + return -1; + } + + io_ = io; + watch_tag_ = tag; + return 0; +} + +void DebugPort::Unwatch() { + if (watch_tag_) { + g_source_remove(watch_tag_); + watch_tag_ = 0; + } + + if (io_) { + g_io_channel_unref(io_); + io_ = nullptr; + } +} + +int DebugPort::Accept(struct ucred* cred) { + struct sockaddr_un addr = { 0, }; + socklen_t socklen = sizeof(addr); + int client_fd = accept(fd_, reinterpret_cast(&addr), + &socklen); + if (client_fd < 0) { + _E("accept() is failed. errno(%d)", errno); + return -1; + } + + socklen = sizeof(struct ucred); + int ret = getsockopt(client_fd, SOL_SOCKET, SO_PEERCRED, + cred, &socklen); + if (ret < 0) { + _E("Failed to get peer information. client_fd(%d), errno(%d)", + client_fd, errno); + close(client_fd); + return -1; + } + + struct timeval tv = { 5, 200 * 1000 }; + ret = setsockopt(client_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + if (ret < 0) { + _E("Failed to set socket option. client_fd(%d), errno(%d)", + client_fd, errno); + close(client_fd); + return -1; + } + + return client_fd; +} + +gboolean DebugPort::OnDebugPortConnectedCb(GIOChannel* io, + GIOCondition cond, + gpointer data) { + _E("cond(%d)", static_cast(cond)); + + if (cond & (G_IO_IN | G_IO_PRI)) { + auto* debug_port = static_cast(data); + struct ucred cred = { 0, }; + int client_fd = debug_port->Accept(&cred); + if (client_fd < 0) + return G_SOURCE_CONTINUE; + + debug_port->AddLogger(cred.pid, client_fd); + } + + return G_SOURCE_CONTINUE; +} + +void DebugPort::AddLogger(int pid, int fd) { + std::lock_guard lock(GetMutex()); + loggers_.emplace_back(new Logger(pid, fd, this)); + _W("Logger added. pid(%d), fd(%d)", pid, fd); +} + +void DebugPort::RemoveLogger(int pid, int fd) { + std::lock_guard lock(GetMutex()); + auto iter = loggers_.begin(); + while (iter != loggers_.end()) { + if ((*iter)->GetPid() == pid && + (*iter)->GetFd() == fd) { + _W("Logger removed. pid(%d), fd(%d)", pid, fd); + iter = loggers_.erase(iter); + break; + } + + ++iter; + } +} + +} // namespace util +} // namespace rpc_port diff --git a/utils/src/debug-port.hh b/utils/src/debug-port.hh new file mode 100644 index 0000000..5c85bb4 --- /dev/null +++ b/utils/src/debug-port.hh @@ -0,0 +1,87 @@ +/* + * 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 DEBUG_PORT_HH_ +#define DEBUG_PORT_HH_ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "logger.hh" + +namespace rpc_port { +namespace util { + +class DebugPort : public Logger::IEvent { + public: + DebugPort(std::string port_name, int pid); + virtual ~DebugPort(); + + void EmitSignal(); + + private: + GDBusConnection* GetConnection(); + void Subscribe(); + void Unsubscribe(); + int CreateSocket(); + int Watch(int fd); + void Unwatch(); + int Accept(struct ucred* cred); + void AddLogger(int pid, int fd); + void RemoveLogger(int pid, int fd); + + void OnDataReceived(int pid, rpc_port_parcel_h parcel) override; + void OnDisconnected(int pid, int fd) override; + + static void OnGDBusSignalCb(GDBusConnection *connection, + const gchar* sender_name, + const gchar* object_path, + const gchar* interface_name, + const gchar* signal_name, + GVariant* parameters, + gpointer user_data); + static gboolean OnDebugPortConnectedCb(GIOChannel* io, + GIOCondition cond, + gpointer data); + + std::recursive_mutex& GetMutex() const { + return mutex_; + } + + private: + std::string port_name_; + int pid_; + GDBusConnection* conn_ = nullptr; + guint subs_tag_ = 0; + int fd_ = -1; + GIOChannel* io_ = nullptr; + guint watch_tag_ = 0; + std::list> loggers_; + mutable std::recursive_mutex mutex_; +}; + +} // namespace util +} // namespace rpc_port + +#endif // DEBUG_PORT_HH_ diff --git a/utils/src/log-private.hh b/utils/src/log-private.hh new file mode 100644 index 0000000..c959ebf --- /dev/null +++ b/utils/src/log-private.hh @@ -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 LOG_PRIVATE_HH_ +#define LOG_PRIVATE_HH_ + +#include + +#undef LOG_TAG +#define LOG_TAG "RPC_PORT_UTIL" + +#undef _E +#define _E LOGE + +#undef _W +#define _W LOGW + +#undef _I +#define _I LOGI + +#undef _D +#define _D LOGD + +#endif // LOG_PRIVATE_HH_ diff --git a/utils/src/logger.cc b/utils/src/logger.cc new file mode 100644 index 0000000..c9c9a92 --- /dev/null +++ b/utils/src/logger.cc @@ -0,0 +1,131 @@ +/* + * 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 +#include + +#include "log-private.hh" +#include "logger.hh" + +namespace rpc_port { +namespace util { + +Logger::Logger(int pid, int fd, IEvent* listener) + : pid_(pid), fd_(fd), listener_(listener) { + thread_ = std::thread([&]() { + GMainContext* context = g_main_context_new(); + GIOChannel* io = g_io_channel_unix_new(fd_); + GIOCondition cond = static_cast( + G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_ERR | G_IO_NVAL); + GSource* source = g_io_create_watch(io, cond); + g_source_set_callback(source, (GSourceFunc)OnDataReceivedCb, this, + nullptr); + g_source_set_priority(source, G_PRIORITY_DEFAULT); + g_source_attach(source, context); + g_source_unref(source); + + loop_ = g_main_loop_new(context, FALSE); + g_main_context_push_thread_default(context); + + g_main_loop_run(loop_); + + if (!g_source_is_destroyed(source)) + g_source_destroy(source); + + g_io_channel_unref(io); + + g_main_context_pop_thread_default(context); + g_main_loop_unref(loop_); + g_main_context_unref(context); + }); +} + +Logger::~Logger() { + if (g_main_loop_is_running(loop_)) + g_main_loop_quit(loop_); + + thread_.join(); + + if (fd_ > 0) + close(fd_); +} + +int Logger::GetPid() { + return pid_; +} + +int Logger::GetFd() { + return fd_; +} + +int Logger::Read(void* buf, unsigned int size) { + char* buffer = static_cast(buf); + unsigned int left = size; + while (left) { + ssize_t read_size = read(fd_, buffer, left); + if (read_size <= 0) { + _E("Failed to read data. fd(%d), errno(%d)", fd_, errno); + return -1; + } + + left -= read_size; + buffer += read_size; + } + return 0; +} + +rpc_port_parcel_h Logger::Read() +{ + int size = 0; + int ret = Read(reinterpret_cast(&size), sizeof(size)); + if (ret < 0) + return nullptr; + + auto* buf = new unsigned char[size]; + ret = Read(static_cast(buf), size); + if (ret < 0) { + delete[] buf; + return nullptr; + } + + rpc_port_parcel_h parcel = nullptr; + rpc_port_parcel_create(&parcel); + rpc_port_parcel_burst_write(parcel, buf, size); + delete[] buf; + return parcel; +} + +gboolean Logger::OnDataReceivedCb(GIOChannel* io, + GIOCondition cond, gpointer data) { + auto* logger = static_cast(data); + auto* listener = logger->listener_; + int fd = g_io_channel_unix_get_fd(io); + int pid = logger->pid_; + + if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) { + _E("Error(%d), fd(%d)", cond, fd); + listener->OnDisconnected(pid, fd); + return G_SOURCE_REMOVE; + } + + rpc_port_parcel_h parcel = logger->Read(); + listener->OnDataReceived(pid, parcel); + rpc_port_parcel_destroy(parcel); + return G_SOURCE_CONTINUE; +} + +} // namespace util +} // namespace rpc_port diff --git a/utils/src/logger.hh b/utils/src/logger.hh new file mode 100644 index 0000000..325536b --- /dev/null +++ b/utils/src/logger.hh @@ -0,0 +1,62 @@ +/* + * 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 LOGGER_HH_ +#define LOGGER_HH_ + +#include +#include +#include + +#include +#include +#include + +namespace rpc_port { +namespace util { + +class Logger { + public: + class IEvent { + public: + virtual void OnDataReceived(int pid, rpc_port_parcel_h parcel) = 0; + virtual void OnDisconnected(int pid, int fd) = 0; + }; + + Logger(int pid, int fd, IEvent* listener); + virtual ~Logger(); + + int GetPid(); + int GetFd(); + + private: + int Read(void* buf, unsigned int size); + rpc_port_parcel_h Read(); + static gboolean OnDataReceivedCb(GIOChannel* io, + GIOCondition cond, gpointer data); + + private: + int pid_; + int fd_; + IEvent* listener_; + std::thread thread_; + GMainLoop* loop_ = nullptr; +}; + +} // namespace util +} // namespace rpc_port + +#endif // LOGGER_HH_ diff --git a/utils/src/main.cc b/utils/src/main.cc new file mode 100644 index 0000000..d038565 --- /dev/null +++ b/utils/src/main.cc @@ -0,0 +1,66 @@ +/* + * 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 + +#include "debug-port.hh" +#include "log-private.hh" +#include "options.hh" + +using namespace rpc_port; +using namespace rpc_port::util; + +namespace { + +class MainLoop { + public: + MainLoop() { + loop_ = g_main_loop_new(nullptr, FALSE); + } + + ~MainLoop() { + g_main_loop_unref(loop_); + } + + void Run() { + g_main_loop_run(loop_); + } + + void Quit() { + g_main_loop_quit(loop_); + } + + private: + GMainLoop* loop_; +}; + +} // namespace + +int main(int argc, char** argv) { + std::unique_ptr options = Options::Parse(argc, argv); + if (!options) { + _E("options is nullptr"); + exit(1); + } + + DebugPort debug_port(options->GetPortName(), options->GetPid()); + debug_port.EmitSignal(); + + MainLoop loop; + loop.Run(); + + return 0; +} diff --git a/utils/src/message.cc b/utils/src/message.cc new file mode 100644 index 0000000..17fa647 --- /dev/null +++ b/utils/src/message.cc @@ -0,0 +1,103 @@ +/* + * 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 + +#include +#include +#include +#include + +#include "message.hh" + +namespace rpc_port { +namespace util { + +Message::Message(time_t time, int pid, std::string port_name, + std::string destination, bool is_delegate, int port, bool is_read, + uint32_t seq, std::vector data) + : time_(time), + pid_(pid), + port_name_(std::move(port_name)), + destination_(std::move(destination)), + is_delegate_(is_delegate), + port_(port), + is_read_(is_read), + seq_(seq), + data_(std::move(data)) { +} + +Message::~Message() = default; + +void Message::Print() { + struct tm sent_time; + localtime_r(&time_, &sent_time); + char buf[50]; + fprintf(stdout, "%s", asctime_r(&sent_time, buf)); + fprintf(stdout, "[%s / %s:%d] [%u] ", + port_name_.c_str(), + is_delegate_ ? "delegate" : "main", + port_, + seq_); + if (is_read_) + fprintf(stdout, "%s -> %d \n", destination_.c_str(), pid_); + else + fprintf(stdout, "%d -> %s \n", pid_, destination_.c_str()); + + Hexdump(); +} + +void Message::Hexdump() { + unsigned int address = 0; + unsigned int row = 0; + unsigned int nread = 0; + std::cout << std::hex << std::setfill('0'); + while (true) { + if (address >= data_.size()) + break; + + std::cout << 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) + std::cout << ' '; + + if (i < nread) { + std::cout << ' ' << std::setw(2) << + static_cast(data_[16 * row + i]); + } else { + std::cout << " "; + } + } + + std::cout << " "; + for (unsigned int i = 0; i < nread ; ++i) { + if (data_[16 * row + i] < 32) + std::cout << '.'; + else + std::cout << data_[16 * row + i]; + } + + std::cout << std::endl; + address += 16; + row++; + } + std::cout << std::endl; +} + +} // namespace util +} // namespace rpc_port diff --git a/utils/src/message.hh b/utils/src/message.hh new file mode 100644 index 0000000..9157b2b --- /dev/null +++ b/utils/src/message.hh @@ -0,0 +1,55 @@ +/* + * 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 MESSAGE_HH_ +#define MESSAGE_HH_ + +#include + +#include +#include + +namespace rpc_port { +namespace util { + +class Message { + public: + Message(time_t time, int pid, std::string port_name, std::string destination, + bool is_delegate, int port, bool is_read, uint32_t seq, + std::vector data); + virtual ~Message(); + + void Print(); + + private: + void Hexdump(); + + private: + time_t time_; + int pid_; + std::string port_name_; + std::string destination_; + bool is_delegate_; + int port_; + bool is_read_; + uint32_t seq_; + std::vector data_; +}; + +} // namespace util +} // namespace rpc_port + +#endif // MESSAGE_HH_ diff --git a/utils/src/options.cc b/utils/src/options.cc new file mode 100644 index 0000000..69bc185 --- /dev/null +++ b/utils/src/options.cc @@ -0,0 +1,122 @@ +/* + * 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 + +#include +#include +#include + +#include "options.hh" + +namespace rpc_port { +namespace util { + +Options::Options() { + help_ = R"__option_cb( +Usage: + rpc-port-util [OPTION...] + +Help Options: + -h, --help Show help options + +Additional Options: + -n, --name= Port name + -p, --pid= Process ID + +Application Options: + -v, --version Show version information +)__option_cb"; +} + +void Options::PrintUsage() { + std::cerr << help_ << std::endl; +} + +void Options::PrintVersion() { + std::cerr << "rpc-port-util " << FULLVER << std::endl; +} + +void Options::PrintSample() { + std::cerr << "rpc-port-util -n Message " << std::endl; +} + +std::unique_ptr Options::Parse(int argc, char** argv) { + int cmd[CMD_MAX] = { 0, }; + int opt[OPT_MAX] = { 0, }; + auto options = std::unique_ptr(new Options()); + int option_index = 0; + + struct option long_options[] = { + {"version", no_argument, NULL, 'v'}, + {"help", no_argument, NULL, 'h'}, + {"name", required_argument, NULL, 'n'}, + {"pid", required_argument, NULL, 'p'}, + {0, 0, 0, 0} + }; + + while (true) { + int c = getopt_long(argc, argv, "vhn:p:", long_options, + &option_index); + if (c == -1) + break; + + switch (c) { + case 0: + break; + + case 'v': + cmd[CMD_VERSION] = 1; + break; + + case 'h': + cmd[CMD_HELP] = 1; + break; + + case 'n': + opt[OPT_NAME] = 1; + options->port_name_ = optarg; + break; + + case 'p': + opt[OPT_PID] = 1; + options->pid_ = std::stoi(optarg); + break; + + default: + cmd[CMD_HELP] = 1; + } + } + + if (cmd[CMD_VERSION]) { + options->PrintVersion(); + return std::unique_ptr(nullptr); + } + + if (cmd[CMD_HELP]) { + options->PrintUsage(); + return std::unique_ptr(nullptr); + } else if (!opt[OPT_NAME]) { + std::cerr << "Select a port name" << std::endl; + options->PrintSample(); + return std::unique_ptr(nullptr); + } + + return options; +} + +} // namespace util +} // namespace rpc_port diff --git a/utils/src/options.hh b/utils/src/options.hh new file mode 100644 index 0000000..4e4612c --- /dev/null +++ b/utils/src/options.hh @@ -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. + */ + +#ifndef OPTIONS_HH_ +#define OPTIONS_HH_ + +#include +#include + +namespace rpc_port { +namespace util { + +class Options { + public: + Options(); + ~Options() = default; + + static std::unique_ptr Parse(int argc, char** argv); + + std::string GetPortName() const { + return port_name_; + } + + int GetPid() { + return pid_; + } + + private: + enum Cmd { + CMD_VERSION, + CMD_HELP, + CMD_MAX + }; + + enum Opt { + OPT_NAME, + OPT_PID, + OPT_MAX + }; + + void PrintUsage(); + void PrintVersion(); + void PrintSample(); + + private: + std::string port_name_; + int pid_ = 0; + std::string help_; +}; + +} // namespace util +} // namespace rpc_port + +#endif // OPTIONS_HH_ -- 2.7.4 From 003a4211131afd965e9de0213d317ec962f19f35 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Wed, 10 Jun 2020 19:02:27 +0900 Subject: [PATCH 06/16] Release version 1.4.0 Changes: - Add set_private_sharing_array API - Add rpc-port-util tool Change-Id: I23e7c521eaba8481abe8cdcb16c273cb3911aa08 Signed-off-by: Hwankyu Jhun --- packaging/rpc-port.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/rpc-port.spec b/packaging/rpc-port.spec index 494c1a3..a23358e 100644 --- a/packaging/rpc-port.spec +++ b/packaging/rpc-port.spec @@ -1,6 +1,6 @@ Name: rpc-port Summary: RPC Port library -Version: 1.3.39 +Version: 1.4.0 Release: 0 Group: Application Framework/Libraries License: Apache-2.0 -- 2.7.4 From 241cb4cd3c5647515594de8f0b9bd91b9ee5f8c6 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Fri, 12 Jun 2020 07:40:48 +0900 Subject: [PATCH 07/16] Fix wrong dbuspolicy conf Change-Id: Id18ec2988f053afeffcc9d6e30d35d7de5f6087b Signed-off-by: Hwankyu Jhun --- conf/rpc-port.conf.in | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/conf/rpc-port.conf.in b/conf/rpc-port.conf.in index 2447548..6511090 100644 --- a/conf/rpc-port.conf.in +++ b/conf/rpc-port.conf.in @@ -2,9 +2,12 @@ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> + + + + - -- 2.7.4 From 3e94e59582ac7d7f257f588e724e1f9bcc7735d0 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Fri, 12 Jun 2020 09:58:01 +0900 Subject: [PATCH 08/16] Release version 1.4.1 Changes: - Fix wrong dbuspolicy conf Change-Id: Ibf2db31c52c4a8524c2083c7c45a5046cd0adee3 Signed-off-by: Hwankyu Jhun --- packaging/rpc-port.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/rpc-port.spec b/packaging/rpc-port.spec index a23358e..d287a85 100644 --- a/packaging/rpc-port.spec +++ b/packaging/rpc-port.spec @@ -1,6 +1,6 @@ Name: rpc-port Summary: RPC Port library -Version: 1.4.0 +Version: 1.4.1 Release: 0 Group: Application Framework/Libraries License: Apache-2.0 -- 2.7.4 From e1b9d934c3cd4a8d279ac8366fa349e6da59442b Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Tue, 16 Jun 2020 07:58:36 +0900 Subject: [PATCH 09/16] Add debugging logs Change-Id: I8e52a130112ef96cb474635f7bdf27a5f6b2e4f4 Signed-off-by: Hwankyu Jhun --- src/rpc-port.cc | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/rpc-port.cc b/src/rpc-port.cc index cba0110..257123e 100644 --- a/src/rpc-port.cc +++ b/src/rpc-port.cc @@ -19,9 +19,10 @@ #include #include -#include "rpc-port.h" +#include "log-private.hh" #include "port-internal.h" #include "proxy-internal.h" +#include "rpc-port.h" #include "stub-internal.h" #undef RPC_API @@ -219,8 +220,8 @@ RPC_API int rpc_port_proxy_create(rpc_port_proxy_h* h) { if (h == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; + _W("rpc_port_proxy_create(%p)", h); auto p = new ::ProxyExt(); - *h = p; return RPC_PORT_ERROR_NONE; } @@ -238,8 +239,8 @@ RPC_API int rpc_port_proxy_destroy(rpc_port_proxy_h h) { if (h == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; + _W("rpc_port_proxy_destroy(%p)", h); auto p = static_cast<::ProxyExt*>(h); - delete p; return RPC_PORT_ERROR_NONE; } @@ -249,6 +250,7 @@ RPC_API int rpc_port_proxy_connect(rpc_port_proxy_h h, const char* appid, if (h == nullptr || appid == nullptr || port == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; + _W("rpc_port_proxy_connect(%p, %s, %s)", h, appid, port); auto p = static_cast<::ProxyExt*>(h); std::lock_guard lock(p->GetMutex()); @@ -261,6 +263,7 @@ RPC_API int rpc_port_proxy_connect_sync(rpc_port_proxy_h h, const char* appid, if (h == nullptr || appid == nullptr || port == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; + _W("rpc_port_proxy_connect(%p, %s, %s)", h, appid, port); auto p = static_cast<::ProxyExt*>(h); std::lock_guard lock(p->GetMutex()); @@ -347,8 +350,8 @@ RPC_API int rpc_port_stub_create(rpc_port_stub_h* h, const char* port_name) { if (h == nullptr || port_name == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; + _W("rpc_port_stub_create(%p, %s)", h, port_name); auto p = new ::StubExt(port_name); - *h = p; return RPC_PORT_ERROR_NONE; } @@ -370,8 +373,8 @@ RPC_API int rpc_port_stub_destroy(rpc_port_stub_h h) { if (h == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; + _W("rpc_port_stub_destroy(%p)", h); auto p = static_cast<::StubExt*>(h); - delete p; return RPC_PORT_ERROR_NONE; } @@ -380,6 +383,7 @@ RPC_API int rpc_port_stub_listen(rpc_port_stub_h h) { if (h == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; + _W("rpc_port_stub_listen(%p)", h); auto p = static_cast<::StubExt*>(h); std::lock_guard lock(p->GetMutex()); -- 2.7.4 From be4e9e27d08f542718b780611ac53f817ddc7dc2 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Wed, 17 Jun 2020 09:56:08 +0900 Subject: [PATCH 10/16] Release version 1.4.2 Changes: - Add debugging logs Change-Id: Ie095b09e7624fa3c47e9bb3b770c938493286668 Signed-off-by: Hwankyu Jhun --- packaging/rpc-port.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/rpc-port.spec b/packaging/rpc-port.spec index d287a85..d528496 100644 --- a/packaging/rpc-port.spec +++ b/packaging/rpc-port.spec @@ -1,6 +1,6 @@ Name: rpc-port Summary: RPC Port library -Version: 1.4.1 +Version: 1.4.2 Release: 0 Group: Application Framework/Libraries License: Apache-2.0 -- 2.7.4 From dcaadb698055fb38a6d6182a5318bdf6a3729d71 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Fri, 19 Jun 2020 11:19:27 +0900 Subject: [PATCH 11/16] Fix thread safe issue To avoid thread safe issues, FdBrokerManager class is added. While calling the callback functions, the FdBroker ptr is checked whether the ptr is valid or not. Change-Id: Ib7c10ec94d3dc5c2e2ae7389619a0ed0416657df Signed-off-by: Hwankyu Jhun --- src/fdbroker-internal.cc | 60 +++++++++++++++++++++++++++++++++++++++++++++--- src/fdbroker-internal.h | 24 +++++++++++++++++-- 2 files changed, 79 insertions(+), 5 deletions(-) diff --git a/src/fdbroker-internal.cc b/src/fdbroker-internal.cc index 98b09e7..54ed899 100644 --- a/src/fdbroker-internal.cc +++ b/src/fdbroker-internal.cc @@ -25,6 +25,8 @@ #include #include +#include + #include "fdbroker-internal.h" #ifdef LOG_TAG @@ -210,13 +212,20 @@ GUnixFDList* FdBroker::FdList::GetRaw() { return fd_list_; } +FdBroker::FdBroker(bool mock) : mock_(mock) { + FdBrokerManager::GetInst().Add(this); +} + FdBroker::~FdBroker() { Cancel(); } void FdBroker::Cancel() { + std::lock_guard lock(mutex_); LOGI("FdBroker::Cancel!"); + FdBrokerManager::GetInst().Remove(this); + if (cancellable_) { LOGW("Cancel the send request"); g_cancellable_cancel(cancellable_); @@ -497,6 +506,12 @@ void FdBroker::OnReceiveDbusMethod(GDBusConnection *conn, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) { FdBroker* broker = static_cast(user_data); + if (!FdBrokerManager::GetInst().Exist(broker)) { + LOGE("No such broker(%p)", broker); + return; + } + + std::lock_guard lock(broker->mutex_); int ret = -1; char sender_appid[255]; int sender_pid; @@ -696,6 +711,12 @@ void FdBroker::OnNameAppeared(GDBusConnection *connection, const gchar *name_owner, gpointer user_data) { FdBroker* broker = static_cast(user_data); + if (!FdBrokerManager::GetInst().Exist(broker)) { + LOGE("No such broker(%p)", broker); + return; + } + + std::lock_guard lock(broker->mutex_); int pid = broker->GetSenderPid(connection, name_owner); char owner_appid[255] = { 0, }; @@ -719,6 +740,12 @@ void FdBroker::OnNameVanished(GDBusConnection *connection, const gchar *name, gpointer user_data) { FdBroker* broker = static_cast(user_data); + if (!FdBrokerManager::GetInst().Exist(broker)) { + LOGE("No such broker(%p)", broker); + return; + } + + std::lock_guard lock(broker->mutex_); broker->watcher_->OnPortVanished(broker->watch_appid_, broker->watch_port_name_); } @@ -796,6 +823,7 @@ int FdBroker::Prepare(const std::string& target_appid, void FdBroker::OnResultReceived(GObject* source_object, GAsyncResult* res, gpointer user_data) { + LOGW("OnResultReceived() : FdBroker(%p)", user_data); GDBusConnection* conn = reinterpret_cast(source_object); GError* err = nullptr; GDBusMessage* reply = g_dbus_connection_send_message_with_reply_finish(conn, @@ -808,10 +836,12 @@ void FdBroker::OnResultReceived(GObject* source_object, } FdBroker* broker = static_cast(user_data); - if (broker == nullptr) { - LOGW("Null broker"); // LCOV_EXCL_LINE - return; // LCOV_EXCL_LINE + if (!FdBrokerManager::GetInst().Exist(broker)) { + LOGE("No such FdBroker(%p)", broker); + return; } + + std::lock_guard lock(broker->mutex_); IEventWatcher* watcher = broker->watcher_; if (err) { @@ -857,5 +887,29 @@ void FdBroker::OnResultReceived(GObject* source_object, LOGD("[Reply : %d]", ret); } +FdBrokerManager& FdBrokerManager::GetInst() { + static FdBrokerManager inst; + return inst; +} + +void FdBrokerManager::Add(FdBroker* broker) { + std::lock_guard lock(mutex_); + brokers_.push_back(broker); +} + +void FdBrokerManager::Remove(FdBroker* broker) { + std::lock_guard lock(mutex_); + brokers_.remove(broker); +} + +bool FdBrokerManager::Exist(FdBroker* broker) { + std::lock_guard lock(mutex_); + auto iter = std::find(brokers_.begin(), brokers_.end(), broker); + if (iter != brokers_.end()) + return true; + + return false; +} + } // namespace internal } // namespace rpc_port diff --git a/src/fdbroker-internal.h b/src/fdbroker-internal.h index 0e5e325..8ddec5a 100644 --- a/src/fdbroker-internal.h +++ b/src/fdbroker-internal.h @@ -22,9 +22,12 @@ #include #include -#include #include #include +#include +#include +#include +#include #include "ac-internal.h" #include "rpc-port.h" @@ -53,7 +56,7 @@ class FdBroker { bool cancel = false) = 0; }; - explicit FdBroker(bool mock = false) : mock_(mock) {} + explicit FdBroker(bool mock = false); ~FdBroker(); static void Dispose() { @@ -182,6 +185,23 @@ class FdBroker { std::string watch_appid_; std::string watch_port_name_; GCancellable* cancellable_ = nullptr; + mutable std::recursive_mutex mutex_; +}; + +class FdBrokerManager { + private: + FdBrokerManager() = default; + ~FdBrokerManager() = default; + + public: + static FdBrokerManager& GetInst(); + void Add(FdBroker* broker); + void Remove(FdBroker* broker); + bool Exist(FdBroker* broker); + + private: + std::list brokers_; + mutable std::recursive_mutex mutex_; }; } // namespace internal -- 2.7.4 From 9b62659c5fc8bdac20f1dc6ae845a9c58c070b98 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Fri, 19 Jun 2020 15:10:54 +0900 Subject: [PATCH 12/16] Release version 1.4.3 Changes: - Fix thread safe issue Change-Id: I0d01bbf6666a3d972895502cd685835749fd2f5d Signed-off-by: Hwankyu Jhun --- packaging/rpc-port.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/rpc-port.spec b/packaging/rpc-port.spec index d528496..3711908 100644 --- a/packaging/rpc-port.spec +++ b/packaging/rpc-port.spec @@ -1,6 +1,6 @@ Name: rpc-port Summary: RPC Port library -Version: 1.4.2 +Version: 1.4.3 Release: 0 Group: Application Framework/Libraries License: Apache-2.0 -- 2.7.4 From a9a55261b6e31db16ba8b6c6f8c5724c5056ef64 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Fri, 19 Jun 2020 16:31:45 +0900 Subject: [PATCH 13/16] Fix wrong implementation The FdBroker ptr has to be removed when the FdBroker instance is removed. The FdBroker.Cancel() method can be invoked from the Proxy instance directly. The exceptions about the registration handle are added in the callback functions related to gdbus. Change-Id: Ieb96e393550e3cfa25d29cc4c97ae207cad1dba8 Signed-off-by: Hwankyu Jhun --- src/fdbroker-internal.cc | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/fdbroker-internal.cc b/src/fdbroker-internal.cc index 54ed899..daf3090 100644 --- a/src/fdbroker-internal.cc +++ b/src/fdbroker-internal.cc @@ -217,6 +217,7 @@ FdBroker::FdBroker(bool mock) : mock_(mock) { } FdBroker::~FdBroker() { + FdBrokerManager::GetInst().Remove(this); Cancel(); } @@ -224,8 +225,6 @@ void FdBroker::Cancel() { std::lock_guard lock(mutex_); LOGI("FdBroker::Cancel!"); - FdBrokerManager::GetInst().Remove(this); - if (cancellable_) { LOGW("Cancel the send request"); g_cancellable_cancel(cancellable_); @@ -507,11 +506,16 @@ void FdBroker::OnReceiveDbusMethod(GDBusConnection *conn, gpointer user_data) { FdBroker* broker = static_cast(user_data); if (!FdBrokerManager::GetInst().Exist(broker)) { - LOGE("No such broker(%p)", broker); + LOGE("No such FdBroker(%p)", broker); return; } std::lock_guard lock(broker->mutex_); + if (broker->registration_id_ == 0) { + LOGE("Invalid context. FdBroker(%p)", broker); + return; + } + int ret = -1; char sender_appid[255]; int sender_pid; @@ -712,11 +716,16 @@ void FdBroker::OnNameAppeared(GDBusConnection *connection, gpointer user_data) { FdBroker* broker = static_cast(user_data); if (!FdBrokerManager::GetInst().Exist(broker)) { - LOGE("No such broker(%p)", broker); + LOGE("No such FdBroker(%p)", broker); return; } std::lock_guard lock(broker->mutex_); + if (broker->watcher_id_ == 0) { + LOGE("Invalid context. FdBroker(%p)", broker); + return; + } + int pid = broker->GetSenderPid(connection, name_owner); char owner_appid[255] = { 0, }; @@ -741,11 +750,16 @@ void FdBroker::OnNameVanished(GDBusConnection *connection, gpointer user_data) { FdBroker* broker = static_cast(user_data); if (!FdBrokerManager::GetInst().Exist(broker)) { - LOGE("No such broker(%p)", broker); + LOGE("No such FdBroker(%p)", broker); return; } std::lock_guard lock(broker->mutex_); + if (broker->watcher_id_ == 0) { + LOGE("Invalid context. FdBroker(%p)", broker); + return; + } + broker->watcher_->OnPortVanished(broker->watch_appid_, broker->watch_port_name_); } @@ -842,6 +856,11 @@ void FdBroker::OnResultReceived(GObject* source_object, } std::lock_guard lock(broker->mutex_); + if (broker->cancellable_ == nullptr) { + LOGE("Invalid context. Fdbroker(%p)", broker); + return; + } + IEventWatcher* watcher = broker->watcher_; if (err) { -- 2.7.4 From 46d44b8ccd28e9705181b14de353e715fa38e486 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Mon, 22 Jun 2020 09:44:26 +0900 Subject: [PATCH 14/16] Move connection timer to FdBroker To make the thread safe Proxy class, the connection timer is moved to the FdBroker class. Change-Id: I035a5947edac4224b2b096f31520c3aca3ed8862 Signed-off-by: Hwankyu Jhun --- src/fdbroker-internal.cc | 66 ++++++++++++++++++++++++++++++++++++++++-------- src/fdbroker-internal.h | 5 +++- src/proxy-internal.cc | 34 ++----------------------- src/proxy-internal.h | 3 ++- 4 files changed, 64 insertions(+), 44 deletions(-) diff --git a/src/fdbroker-internal.cc b/src/fdbroker-internal.cc index daf3090..c280339 100644 --- a/src/fdbroker-internal.cc +++ b/src/fdbroker-internal.cc @@ -232,6 +232,11 @@ void FdBroker::Cancel() { cancellable_ = nullptr; } + if (conn_timer_ > 0) { + g_source_remove(conn_timer_); + conn_timer_ = 0; + } + if (watcher_id_ > 0) { g_bus_unwatch_name(watcher_id_); watcher_id_ = 0; @@ -726,19 +731,30 @@ void FdBroker::OnNameAppeared(GDBusConnection *connection, return; } + if (broker->conn_timer_ > 0) { + g_source_remove(broker->conn_timer_); + broker->conn_timer_ = 0; + } + int pid = broker->GetSenderPid(connection, name_owner); char owner_appid[255] = { 0, }; if (aul_app_get_appid_bypid(pid, owner_appid, sizeof(owner_appid)) < 0) { - LOGE("aul_app_get_appid_bypid failed %d", pid); // LCOV_EXCL_LINE - broker->watcher_->OnPortRejected(owner_appid); // LCOV_EXCL_LINE - return; // LCOV_EXCL_LINE + // LCOV_EXCL_START + LOGE("aul_app_get_appid_bypid failed %d", pid); + broker->watcher_->OnPortRejected(owner_appid, + RPC_PORT_ERROR_IO_ERROR); + return; + // LCOV_EXCL_STOP } if (broker->watch_appid_ != owner_appid) { - LOGE("invalid appid %s", owner_appid); // LCOV_EXCL_LINE - broker->watcher_->OnPortRejected(owner_appid); // LCOV_EXCL_LINE - return; // LCOV_EXCL_LINE + // LCOV_EXCL_START + LOGE("invalid appid %s", owner_appid); + broker->watcher_->OnPortRejected(owner_appid, + RPC_PORT_ERROR_IO_ERROR); + return; + // LCOV_EXCL_STOP } broker->watcher_->OnPortAppeared(broker->watch_appid_, @@ -766,6 +782,7 @@ void FdBroker::OnNameVanished(GDBusConnection *connection, int FdBroker::Watch(IEventWatcher* ev, const std::string& target_appid, const std::string& port_name) { + std::lock_guard lock(mutex_); if (ev == nullptr) return -1; @@ -777,6 +794,11 @@ int FdBroker::Watch(IEventWatcher* ev, const std::string& target_appid, watch_appid_ = target_appid; watch_port_name_ = port_name; + if (conn_timer_ > 0) + g_source_remove(conn_timer_); + + conn_timer_ = g_timeout_add(10 * 1000, OnDbusNameTimeout, this); + if (mock_) { // LCOV_EXCL_START ret = DBusMock::GetInst().Watch(ev, target_appid, port_name); @@ -806,9 +828,11 @@ int FdBroker::Watch(IEventWatcher* ev, const std::string& target_appid, this, NULL); if (watcher_id_ == 0) { - LOGE("Failed to watch connection(%s)", interface_name.c_str()); // LCOV_EXCL_LINE - watcher_ = nullptr; // LCOV_EXCL_LINE - return -1; // LCOV_EXCL_LINE + // LCOV_EXCL_START + LOGE("Failed to watch connection(%s)", interface_name.c_str()); + watcher_ = nullptr; + return -1; + // LCOV_EXCL_STOP } return 0; @@ -898,7 +922,8 @@ void FdBroker::OnResultReceived(GObject* source_object, g_object_unref(reply); if (ret != 0) { LOGE("Access Denied[sender_appid : %s]", broker->watch_appid_.c_str()); - watcher->OnPortRejected(broker->watch_appid_); + watcher->OnPortRejected(broker->watch_appid_, + RPC_PORT_ERROR_PERMISSION_DENIED); return; } @@ -906,6 +931,27 @@ void FdBroker::OnResultReceived(GObject* source_object, LOGD("[Reply : %d]", ret); } +gboolean FdBroker::OnDbusNameTimeout(gpointer user_data) { + FdBroker* broker = static_cast(user_data); + if (!FdBrokerManager::GetInst().Exist(broker)) { + LOGE("No such FdBroker(%p)", broker); + return G_SOURCE_REMOVE; + } + + std::lock_guard lock(broker->mutex_); + if (broker->conn_timer_ == 0) { + LOGE("Invalid context. FdBroker(%p)", broker); + return G_SOURCE_REMOVE; + } + + broker->conn_timer_ = 0; + broker->Cancel(); + auto* watcher = broker->watcher_; + watcher->OnPortRejected(broker->watch_appid_, RPC_PORT_ERROR_IO_ERROR); + + return G_SOURCE_REMOVE; +} + FdBrokerManager& FdBrokerManager::GetInst() { static FdBrokerManager inst; return inst; diff --git a/src/fdbroker-internal.h b/src/fdbroker-internal.h index 8ddec5a..881df3a 100644 --- a/src/fdbroker-internal.h +++ b/src/fdbroker-internal.h @@ -48,7 +48,8 @@ class FdBroker { const std::string& port_name) = 0; virtual void OnPortVanished(const std::string& appid, const std::string& port_name) = 0; - virtual void OnPortRejected(const std::string& appid) = 0; + virtual void OnPortRejected(const std::string& appid, + int error) = 0; virtual void OnPortConnected(const std::string& appid, const std::string& port_name) = 0; virtual void OnPortDisconnected(const std::string& appid, @@ -174,6 +175,7 @@ class FdBroker { static void OnResultReceived(GObject* source_object, GAsyncResult* res, gpointer user_data); + static gboolean OnDbusNameTimeout(gpointer user_data); private: IEventListener* listener_ = nullptr; @@ -185,6 +187,7 @@ class FdBroker { std::string watch_appid_; std::string watch_port_name_; GCancellable* cancellable_ = nullptr; + guint conn_timer_ = 0; mutable std::recursive_mutex mutex_; }; diff --git a/src/proxy-internal.cc b/src/proxy-internal.cc index dcbe1bf..040116d 100644 --- a/src/proxy-internal.cc +++ b/src/proxy-internal.cc @@ -36,10 +36,6 @@ Proxy::Proxy(bool mock) Proxy::~Proxy() { _D("Proxy::~Proxy"); - if (conn_timer_) { - g_source_remove(conn_timer_); // LCOV_EXCL_LINE - conn_timer_ = 0; // LCOV_EXCL_LINE - } } gboolean Proxy::OnSocketDisconnected(GIOChannel *gio, GIOCondition cond, @@ -100,22 +96,18 @@ gboolean Proxy::OnDataReceived(GIOChannel *gio, GIOCondition cond, return TRUE; } -void Proxy::OnPortRejected(const std::string& appid) { +void Proxy::OnPortRejected(const std::string& appid, int error) { if (listener_ == nullptr) return; IEventListener* listener = listener_; listener_ = nullptr; - listener->OnRejected(appid, RPC_PORT_ERROR_PERMISSION_DENIED); + listener->OnRejected(appid, error); } void Proxy::OnPortAppeared(const std::string& appid, const std::string& port_name) { _D("endpoint(%s), port_name(%s)", appid.c_str(), port_name.c_str()); - if (conn_timer_) { - g_source_remove(conn_timer_); - conn_timer_ = 0; - } if (listener_ == nullptr) return; @@ -196,14 +188,9 @@ int Proxy::Connect(std::string appid, std::string port_name, target_appid_ = std::move(appid); port_name_ = std::move(port_name); - if (conn_timer_) - g_source_remove(conn_timer_); // LCOV_EXCL_LINE - conn_timer_ = g_timeout_add(10 * 1000, DbusNameTimeout, this); - int r = fd_broker_.Watch(this, target_appid_, port_name_); if (r < 0) { // LCOV_EXCL_START - g_source_remove(conn_timer_); listener_ = nullptr; if (r == -EILLEGALACCESS) return RPC_PORT_ERROR_PERMISSION_DENIED; @@ -259,23 +246,6 @@ int Proxy::ConnectSync(std::string appid, std::string port_name, } // LCOV_EXCL_STOP -// LCOV_EXCL_START -gboolean Proxy::DbusNameTimeout(gpointer user_data) { - Proxy* obj = static_cast(user_data); - - _W("[__DbusNameTimeout__] endpoint(%s)", obj->target_appid_.c_str()); - obj->conn_timer_ = 0; - if (obj->listener_) { - IEventListener* listener = obj->listener_; - obj->listener_ = nullptr; - obj->fd_broker_.Cancel(); - listener->OnRejected(obj->target_appid_, RPC_PORT_ERROR_IO_ERROR); - } - - return G_SOURCE_REMOVE; -} -// LCOV_EXCL_STOP - Proxy::ProxyPort::ProxyPort(Proxy* parent, int fd, const std::string& id, bool receive) : Port(fd, id), parent_(parent) { Watch(receive); diff --git a/src/proxy-internal.h b/src/proxy-internal.h index 63cbf52..485373e 100644 --- a/src/proxy-internal.h +++ b/src/proxy-internal.h @@ -86,7 +86,8 @@ class Proxy : public FdBroker::IEventWatcher { const std::string& port_name) override; void OnPortVanished(const std::string& appid, const std::string& port_name) override; - void OnPortRejected(const std::string& appid) override; + void OnPortRejected(const std::string& appid, + int error) override; void OnPortConnected(const std::string& appid, const std::string& port_name) override; void OnPortDisconnected(const std::string& appid, -- 2.7.4 From 1b7990ba34a4e69fdc859234b18044fd23b09aa0 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Mon, 22 Jun 2020 11:25:29 +0900 Subject: [PATCH 15/16] Release version 1.4.4 Changes: - Fix wrong implementation - Move connection timer to FdBroker Change-Id: I8f371395a7438e838dfaee6fd15a7a0153ca7d10 Signed-off-by: Hwankyu Jhun --- packaging/rpc-port.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/rpc-port.spec b/packaging/rpc-port.spec index 3711908..eef2376 100644 --- a/packaging/rpc-port.spec +++ b/packaging/rpc-port.spec @@ -1,6 +1,6 @@ Name: rpc-port Summary: RPC Port library -Version: 1.4.3 +Version: 1.4.4 Release: 0 Group: Application Framework/Libraries License: Apache-2.0 -- 2.7.4 From c0a87a7720a15f8b88878b8772207e1ca0641749 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Tue, 23 Jun 2020 07:31:11 +0900 Subject: [PATCH 16/16] Fix wrong log messages Change-Id: I56aacaaf7f96cc6a370bfae7595d4c54c7a918a2 Signed-off-by: Hwankyu Jhun --- src/rpc-port.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rpc-port.cc b/src/rpc-port.cc index 257123e..efae3d6 100644 --- a/src/rpc-port.cc +++ b/src/rpc-port.cc @@ -220,9 +220,9 @@ RPC_API int rpc_port_proxy_create(rpc_port_proxy_h* h) { if (h == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; - _W("rpc_port_proxy_create(%p)", h); auto p = new ::ProxyExt(); *h = p; + _W("rpc_port_proxy_create(%p)", p); return RPC_PORT_ERROR_NONE; } @@ -350,9 +350,9 @@ RPC_API int rpc_port_stub_create(rpc_port_stub_h* h, const char* port_name) { if (h == nullptr || port_name == nullptr) return RPC_PORT_ERROR_INVALID_PARAMETER; - _W("rpc_port_stub_create(%p, %s)", h, port_name); auto p = new ::StubExt(port_name); *h = p; + _W("rpc_port_stub_create(%p, %s)", p, port_name); return RPC_PORT_ERROR_NONE; } -- 2.7.4