2 * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <sys/socket.h>
20 #include <sys/types.h>
27 #include "aul-internal.hh"
28 #include "debug-port-internal.hh"
29 #include "exception-internal.hh"
30 #include "include/rpc-port-internal.h"
31 #include "log-private.hh"
32 #include "proxy-internal.hh"
33 #include "request-internal.hh"
34 #include "response-internal.hh"
36 #define EILLEGALACCESS 127
42 constexpr const char kPortTypeMain[] = "main";
43 constexpr const char kPortTypeDelegate[] = "delegate";
45 std::string GenInstance() {
49 uuid_unparse(u, uuid);
50 return std::string(uuid) + "@" + Aul::GetAppId(getpid());
53 int SendRequest(ClientSocket* client, const Request& request) {
54 tizen_base::Parcel parcel;
55 parcel.WriteParcelable(const_cast<Request&>(request));
56 const std::vector<uint8_t>& raw = parcel.GetRaw();
57 size_t size = raw.size();
58 int ret = client->Send(reinterpret_cast<void*>(&size), sizeof(size));
60 _E("Send() is failed. error(%d)", ret);
64 ret = client->Send(raw.data(), raw.size());
66 _E("Send() is failed. error(%d)", ret);
73 int ReceiveResponse(ClientSocket* client, Response** response) {
75 int ret = client->Receive(reinterpret_cast<void*>(&size), sizeof(size));
77 _E("Receive() is failed. error(%d)", ret);
81 std::vector<uint8_t> buf(size);
82 ret = client->Receive(buf.data(), size);
84 _E("Receive() is failed. error(%d)", ret);
88 tizen_base::Parcel parcel(buf.data(), buf.size());
89 *response = new (std::nothrow) Response();
90 if (*response == nullptr) {
95 parcel.ReadParcelable(*response);
102 _D("Proxy::Proxy()");
106 std::lock_guard<std::recursive_mutex> lock(GetMutex());
107 _D("Proxy::~Proxy()");
114 int Proxy::Connect(bool sync) {
115 std::lock_guard<std::recursive_mutex> lock(GetMutex());
119 std::string port_path = Aul::GetPortPath(real_appid_, port_name_,
120 rpc_port_get_target_uid());
121 std::string instance = GenInstance();
124 main_client_.reset(Client::Create(this, port_path));
125 if (main_client_.get() == nullptr)
126 return RPC_PORT_ERROR_IO_ERROR;
128 Request request(instance.c_str(), kPortTypeMain);
129 int ret = SendRequest(main_client_.get(), request);
131 return RPC_PORT_ERROR_IO_ERROR;
134 Response* response = nullptr;
135 ret = ReceiveResponse(main_client_.get(), &response);
137 return RPC_PORT_ERROR_IO_ERROR;
139 std::unique_ptr<Response> response_auto(response);
140 if (response->GetResult() != 0) {
141 _E("Permission denied");
142 return RPC_PORT_ERROR_PERMISSION_DENIED;
145 main_client_->SetNonblock();
146 fds_[0] = main_client_->RemoveFd();
148 ret = main_client_->Watch();
150 return RPC_PORT_ERROR_IO_ERROR;
154 delegate_client_.reset(Client::Create(this, port_path));
155 if (delegate_client_.get() == nullptr)
156 return RPC_PORT_ERROR_IO_ERROR;
158 request.SetPortType(kPortTypeDelegate);
159 ret = SendRequest(delegate_client_.get(), request);
161 return RPC_PORT_ERROR_IO_ERROR;
164 Response* response = nullptr;
165 ret = ReceiveResponse(delegate_client_.get(), &response);
167 return RPC_PORT_ERROR_IO_ERROR;
169 std::unique_ptr<Response> response_auto(response);
170 if (response->GetResult() != 0) {
171 _E("Permission denied");
172 return RPC_PORT_ERROR_PERMISSION_DENIED;
175 delegate_client_->SetNonblock();
176 fds_[1] = delegate_client_->RemoveFd();
178 ret = delegate_client_->Watch();
180 return RPC_PORT_ERROR_IO_ERROR;
183 return RPC_PORT_ERROR_NONE;
186 int Proxy::Connect(std::string appid, std::string port_name,
187 IEventListener* listener) {
188 if (listener == nullptr)
189 return RPC_PORT_ERROR_INVALID_PARAMETER;
191 std::lock_guard<std::recursive_mutex> lock(GetMutex());
192 if (listener_ != nullptr) {
193 _D("Already requested");
194 return RPC_PORT_ERROR_INVALID_PARAMETER;
197 listener_ = listener;
198 target_appid_ = std::move(appid);
199 port_name_ = std::move(port_name);
200 SetRealAppId(target_appid_);
203 int ret = Aul::PrepareStub(real_appid_, port_name_,
204 rpc_port_get_target_uid());
205 if (ret != RPC_PORT_ERROR_NONE) {
213 return RPC_PORT_ERROR_IO_ERROR;
216 return RPC_PORT_ERROR_NONE;
219 int Proxy::ConnectSync(std::string appid, std::string port_name,
220 IEventListener* listener) {
221 if (listener == nullptr)
222 return RPC_PORT_ERROR_INVALID_PARAMETER;
224 if (listener_ != nullptr) {
225 _W("Already requested");
226 return RPC_PORT_ERROR_INVALID_PARAMETER;
229 std::lock_guard<std::recursive_mutex> lock(GetMutex());
230 listener_ = listener;
231 target_appid_ = std::move(appid);
232 port_name_ = std::move(port_name);
233 SetRealAppId(target_appid_);
235 int ret = Aul::PrepareStub(real_appid_, port_name_,
236 rpc_port_get_target_uid());
237 if (ret != RPC_PORT_ERROR_NONE) {
243 int retry_count = 20;
245 exist = Aul::ExistPort(real_appid_, port_name_, rpc_port_get_target_uid());
251 } while (retry_count > 0);
254 _E("%s:%s is not ready", real_appid_.c_str(), port_name_.c_str());
256 return RPC_PORT_ERROR_IO_ERROR;
260 if (ret != RPC_PORT_ERROR_NONE) {
265 main_port_.reset(new ProxyPort(this, fds_[0], target_appid_, false));
266 delegate_port_.reset(new ProxyPort(this, fds_[1], target_appid_));
267 DebugPort::GetInst()->AddSession(port_name, target_appid_, fds_[0], fds_[1]);
268 listener_->OnConnected(target_appid_, main_port_.get());
269 return RPC_PORT_ERROR_NONE;
272 void Proxy::DisconnectPort() {
273 std::lock_guard<std::recursive_mutex> lock(GetMutex());
274 if (main_port_.get() != nullptr) {
275 DebugPort::GetInst()->RemoveSession(main_port_->GetFd());
281 std::lock_guard<std::recursive_mutex> lock(GetMutex());
282 int ret = aul_rpc_port_usr_add_watch(real_appid_.c_str(), port_name_.c_str(),
283 OnPortAppeared, OnPortVanished, this, rpc_port_get_target_uid(),
285 if (ret != AUL_R_OK) {
286 _E("aul_rpc_port_usr_add_watch() is failed. error(%d)", ret);
295 void Proxy::Cancel() {
296 std::lock_guard<std::recursive_mutex> lock(GetMutex());
298 aul_rpc_port_remove_watch(watch_handle_);
299 watch_handle_ = nullptr;
303 void Proxy::SetRealAppId(const std::string& alias_appid) {
304 std::lock_guard<std::recursive_mutex> lock(GetMutex());
305 if (!real_appid_.empty())
308 char* appid = nullptr;
309 int ret = aul_svc_get_appid_by_alias_appid(alias_appid.c_str(), &appid);
310 if (ret != AUL_SVC_RET_OK) {
311 real_appid_ = alias_appid;
315 std::unique_ptr<char, decltype(std::free)*> appid_ptr(appid, std::free);
316 real_appid_ = std::string(appid);
317 _W("alias_appid(%s), real_appid(%s)", alias_appid.c_str(), appid);
320 std::recursive_mutex& Proxy::GetMutex() const {
324 void Proxy::SetConnTimer() {
325 if (conn_timer_data_) {
326 _W("Already exists");
330 conn_timer_data_ = CreateWeakPtr();
331 if (conn_timer_data_ == nullptr) {
336 g_timeout_add_seconds(10, OnTimedOut, conn_timer_data_);
339 void Proxy::UnsetConnTimer() {
340 if (conn_timer_data_ == nullptr)
343 GSource* source = g_main_context_find_source_by_user_data(nullptr,
345 if (source && !g_source_is_destroyed(source))
346 g_source_destroy(source);
348 DestroyWeakPtr(conn_timer_data_);
349 conn_timer_data_ = nullptr;
352 void Proxy::SetIdler() {
354 _W("Already exists");
358 idler_data_ = CreateWeakPtr();
359 if (idler_data_ == nullptr) {
364 g_idle_add(OnIdle, idler_data_);
367 void Proxy::UnsetIdler() {
368 if (idler_data_ == nullptr)
371 GSource* source = g_main_context_find_source_by_user_data(nullptr,
373 if (source && !g_source_is_destroyed(source))
374 g_source_destroy(source);
376 DestroyWeakPtr(idler_data_);
377 idler_data_ = nullptr;
380 void Proxy::OnPortAppeared(const char* app_id, const char* port_name, int pid,
382 _W("app_id(%s), port_name(%s), pid(%d)", app_id, port_name, pid);
383 auto* proxy = static_cast<Proxy*>(user_data);
384 std::lock_guard<std::recursive_mutex> lock(proxy->GetMutex());
387 if (proxy->watch_handle_ == nullptr) {
388 _E("Invalid context");
392 auto* listener = proxy->listener_;
393 if (listener == nullptr) {
394 _E("Invalid context");
398 proxy->UnsetConnTimer();
401 int ret = proxy->Connect(false);
402 if (ret != RPC_PORT_ERROR_NONE) {
403 proxy->listener_ = nullptr;
404 if (ret == RPC_PORT_ERROR_PERMISSION_DENIED)
405 listener->OnRejected(proxy->target_appid_, ret);
407 listener->OnDisconnected(proxy->target_appid_);
411 void Proxy::OnPortVanished(const char* app_id, const char* port_name, int pid,
413 _W("app_id(%s), port_name(%s), pid(%d)", app_id, port_name, pid);
414 auto* proxy = static_cast<Proxy*>(user_data);
415 std::lock_guard<std::recursive_mutex> lock(proxy->GetMutex());
419 gboolean Proxy::OnTimedOut(gpointer user_data) {
421 auto* ptr = static_cast<std::weak_ptr<Proxy>*>(user_data);
422 auto proxy = ptr->lock();
423 if (proxy == nullptr) {
424 _E("Proxy is nullptr");
425 return G_SOURCE_REMOVE;
428 std::lock_guard<std::recursive_mutex> lock(proxy->GetMutex());
429 if (proxy->conn_timer_data_ == nullptr) {
430 _E("Invalid context. proxy(%p)", proxy.get());
431 return G_SOURCE_REMOVE;
435 DestroyWeakPtr(proxy->conn_timer_data_);
436 proxy->conn_timer_data_ = nullptr;
438 auto* listener = proxy->listener_;
439 if (listener == nullptr) {
440 _E("Invalid context");
441 return G_SOURCE_REMOVE;
444 proxy->listener_ = nullptr;
445 listener->OnRejected(proxy->target_appid_, RPC_PORT_ERROR_IO_ERROR);
446 return G_SOURCE_REMOVE;
449 gboolean Proxy::OnIdle(gpointer user_data) {
450 auto* ptr = static_cast<std::weak_ptr<Proxy>*>(user_data);
451 auto proxy = ptr->lock();
452 if (proxy == nullptr) {
453 _E("Proxy is nullptr");
454 return G_SOURCE_REMOVE;
457 std::lock_guard<std::recursive_mutex> lock(proxy->GetMutex());
458 if (proxy->idler_data_ == nullptr) {
459 _E("Invalid context. proxy(%p)", proxy.get());
460 return G_SOURCE_REMOVE;
463 DestroyWeakPtr(proxy->idler_data_);
464 proxy->idler_data_ = nullptr;
466 bool exist = Aul::ExistPort(proxy->real_appid_, proxy->port_name_,
467 rpc_port_get_target_uid());
469 proxy->OnPortAppeared(proxy->real_appid_.c_str(),
470 proxy->port_name_.c_str(), -1, proxy.get());
472 proxy->OnPortVanished(proxy->real_appid_.c_str(),
473 proxy->port_name_.c_str(), -1, proxy.get());
476 return G_SOURCE_REMOVE;
479 Proxy::ProxyPort::ProxyPort(Proxy* parent, int fd, const std::string& id,
481 : Port(fd, id), parent_(parent) {
485 Proxy::ProxyPort::~ProxyPort() {
486 if (disconn_source_ > 0)
487 g_source_remove(disconn_source_);
490 g_source_remove(source_);
492 if (channel_ != nullptr)
493 g_io_channel_unref(channel_);
496 int Proxy::ProxyPort::Watch(bool receive) {
497 channel_ = g_io_channel_unix_new(GetFd());
498 if (channel_ == nullptr) {
499 _E("g_io_channel_unix_new() is failed");
503 disconn_source_ = g_io_add_watch(channel_,
504 static_cast<GIOCondition>(G_IO_ERR | G_IO_HUP | G_IO_NVAL),
505 Proxy::ProxyPort::OnSocketDisconnected, parent_);
506 if (disconn_source_ == 0) {
507 _E("g_io_add_watch() is failed");
514 source_ = g_io_add_watch(channel_, static_cast<GIOCondition>(G_IO_IN),
515 Proxy::ProxyPort::OnDataReceived, parent_);
517 _E("g_io_add_watch() is failed");
524 void Proxy::ProxyPort::SetDisconnectedSource(guint source_id) {
525 disconn_source_ = source_id;
528 void Proxy::ProxyPort::SetSource(guint source_id) {
532 gboolean Proxy::ProxyPort::OnSocketDisconnected(GIOChannel* channel,
533 GIOCondition cond, gpointer user_data) {
534 auto* proxy = static_cast<Proxy*>(user_data);
535 std::lock_guard<std::recursive_mutex> lock(proxy->GetMutex());
536 auto* listener = proxy->listener_;
537 if (listener == nullptr) {
538 _E("Invalid context");
539 return G_SOURCE_REMOVE;
542 int fd = g_io_channel_unix_get_fd(channel);
543 _W("Socket was disconnected. fd(%d)", fd);
544 if (proxy->main_port_.get() != nullptr &&
545 proxy->main_port_->GetFd() == fd) {
546 proxy->main_port_->SetDisconnectedSource(0);
547 } else if (proxy->delegate_port_.get() != nullptr &&
548 proxy->delegate_port_->GetFd() == fd) {
549 proxy->delegate_port_->SetDisconnectedSource(0);
552 proxy->main_port_.reset();
553 proxy->delegate_port_.reset();
554 proxy->listener_ = nullptr;
555 listener->OnDisconnected(proxy->target_appid_);
556 DebugPort::GetInst()->RemoveSession(fd);
557 return G_SOURCE_REMOVE;;
560 gboolean Proxy::ProxyPort::OnDataReceived(GIOChannel* channel,
561 GIOCondition cond, gpointer user_data) {
562 auto* proxy = static_cast<Proxy*>(user_data);
563 std::lock_guard<std::recursive_mutex> lock(proxy->GetMutex());
564 auto* listener = proxy->listener_;
565 if (listener == nullptr) {
566 _E("Invalid context");
567 return G_SOURCE_REMOVE;
570 int fd = g_io_channel_unix_get_fd(channel);
571 if (proxy->delegate_port_->GetFd() == fd) {
573 if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) {
574 _W("Socket was disconnected by stub. fd(%d)", fd);
575 proxy->listener_ = nullptr;
576 proxy->delegate_port_->SetSource(0);
577 if (proxy->main_port_.get() != nullptr) {
578 DebugPort::GetInst()->RemoveSession(proxy->main_port_->GetFd());
579 proxy->main_port_.reset();
581 proxy->delegate_port_.reset();
582 listener->OnDisconnected(proxy->target_appid_);
583 return G_SOURCE_REMOVE;
586 listener->OnReceived(proxy->target_appid_);
589 return G_SOURCE_CONTINUE;
592 Proxy::Client::Client(Proxy* parent) : parent_(parent) {
595 Proxy::Client::~Client() {
597 g_io_channel_unref(channel_);
599 if (disconn_source_ > 0)
600 g_source_remove(disconn_source_);
603 g_source_remove(source_);
606 Proxy::Client* Proxy::Client::Create(Proxy* parent,
607 const std::string& endpoint) {
608 std::unique_ptr<Proxy::Client> client;
610 client.reset(new (std::nothrow) Proxy::Client(parent));
611 } catch (Exception& e) {
612 _E("Exception(%s) occurs", e.what());
619 ret = client->Connect(endpoint);
622 } else if (ret < 0) {
623 _D("Connect() is failed");
627 } while (retry_count > 0);
630 _E("Connect() is failed");
634 client->SetReceiveTimeout(5000);
635 _W("endpoint(%s), fd(%d)", endpoint.c_str(), client->GetFd());
636 return client.release();
639 int Proxy::Client::Watch() {
640 channel_ = g_io_channel_unix_new(GetFd());
641 if (channel_ == nullptr) {
642 _E("g_io_channel_unix_new() is failed");
646 source_ = g_io_add_watch(channel_, static_cast<GIOCondition>(G_IO_IN),
647 Proxy::Client::OnResponseReceived, parent_);
649 _E("g_io_add_watch() is failed");
653 disconn_source_ = g_io_add_watch(channel_,
654 static_cast<GIOCondition>(G_IO_ERR | G_IO_HUP | G_IO_NVAL),
655 Proxy::Client::OnSocketDisconnected, parent_);
656 if (disconn_source_ == 0) {
657 _E("g_io_add_watch() is failed");
664 void Proxy::Client::SetDisconnectedSource(guint source) {
665 disconn_source_ = source;
668 void Proxy::Client::SetSource(guint source) {
672 gboolean Proxy::Client::OnSocketDisconnected(GIOChannel* channel,
673 GIOCondition cond, gpointer user_data) {
674 auto* proxy = static_cast<Proxy*>(user_data);
675 std::lock_guard<std::recursive_mutex> lock(proxy->GetMutex());
676 auto* listener = proxy->listener_;
677 if (listener == nullptr) {
678 _E("Invalid context");
679 return G_SOURCE_REMOVE;
682 int fd = g_io_channel_unix_get_fd(channel);
683 _W("Socket was disconnected. fd(%d)", fd);
684 if (proxy->main_client_.get() != nullptr &&
685 proxy->main_client_->GetFd() == fd) {
686 proxy->main_client_->SetDisconnectedSource(0);
687 } else if (proxy->delegate_client_.get() != nullptr &&
688 proxy->delegate_client_->GetFd() == fd) {
689 proxy->delegate_client_->SetDisconnectedSource(0);
692 proxy->main_client_.reset();
693 proxy->delegate_client_.reset();
694 proxy->listener_ = nullptr;
695 listener->OnDisconnected(proxy->target_appid_);
696 return G_SOURCE_REMOVE;
699 gboolean Proxy::Client::OnResponseReceived(GIOChannel* channel,
700 GIOCondition cond, gpointer user_data) {
701 auto* proxy = static_cast<Proxy*>(user_data);
702 std::lock_guard<std::recursive_mutex> lock(proxy->GetMutex());
703 auto* listener = proxy->listener_;
704 if (listener == nullptr) {
705 _E("Invalid context");
706 return G_SOURCE_REMOVE;
709 bool is_delegate = false;
710 std::unique_ptr<Client> client;
711 int fd = g_io_channel_unix_get_fd(channel);
712 if (proxy->main_client_.get() != nullptr &&
713 proxy->main_client_->GetFd() == fd) {
714 client.reset(proxy->main_client_.release());
715 } else if (proxy->delegate_client_.get() != nullptr &&
716 proxy->delegate_client_->GetFd() == fd) {
717 client.reset(proxy->delegate_client_.release());
721 if (client.get() == nullptr) {
722 _E("Unknown fd(%d)", fd);
723 return G_SOURCE_REMOVE;
726 client->SetSource(0);
728 Response* response = nullptr;
729 int ret = ReceiveResponse(client.get(), &response);
731 proxy->listener_ = nullptr;
732 proxy->main_client_.reset();
733 proxy->delegate_client_.reset();
734 listener->OnRejected(proxy->target_appid_, RPC_PORT_ERROR_IO_ERROR);
735 return G_SOURCE_REMOVE;
738 std::unique_ptr<Response> response_auto(response);
739 if (response->GetResult() != 0) {
740 _E("Permission denied");
741 proxy->listener_ = nullptr;
742 proxy->main_client_.reset();
743 proxy->delegate_client_.reset();
744 listener->OnRejected(proxy->target_appid_,
745 RPC_PORT_ERROR_PERMISSION_DENIED);
746 return G_SOURCE_REMOVE;
749 client->SetNonblock();
750 int client_fd = client->RemoveFd();
752 proxy->fds_[1] = client_fd;
753 proxy->delegate_port_.reset(
754 new ProxyPort(proxy, proxy->fds_[1], proxy->target_appid_));
755 DebugPort::GetInst()->AddSession(proxy->port_name_, proxy->target_appid_,
756 proxy->fds_[0], proxy->fds_[1]);
757 listener->OnConnected(proxy->target_appid_, proxy->main_port_.get());
758 _W("target_appid(%s), port_name(%s), main_fd(%d), delegate_fd(%d)",
759 proxy->target_appid_.c_str(), proxy->port_name_.c_str(),
760 proxy->fds_[0], proxy->fds_[1]);
762 proxy->fds_[0] = client_fd;
763 proxy->main_port_.reset(
764 new ProxyPort(proxy, proxy->fds_[0], proxy->target_appid_, false));
767 return G_SOURCE_REMOVE;
770 std::shared_ptr<Proxy> Proxy::GetSharedPtr() {
771 return shared_from_this();
774 gpointer Proxy::CreateWeakPtr() {
775 auto* ptr = new (std::nothrow) std::weak_ptr<Proxy>(GetSharedPtr());
776 return static_cast<gpointer>(ptr);
779 void Proxy::DestroyWeakPtr(gpointer data) {
780 auto* ptr = static_cast<std::weak_ptr<Proxy>*>(data);
784 } // namespace internal
785 } // namespace rpc_port