Remove duplicated code
[platform/core/appfw/rpc-port.git] / src / proxy-internal.cc
1 /*
2  * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <aul_svc.h>
18 #include <dlog.h>
19 #include <sys/socket.h>
20 #include <sys/types.h>
21 #include <uuid.h>
22
23 #include <memory>
24 #include <utility>
25 #include <vector>
26
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"
35
36 #define EILLEGALACCESS 127
37
38 namespace rpc_port {
39 namespace internal {
40 namespace {
41
42 constexpr const char kPortTypeMain[] = "main";
43 constexpr const char kPortTypeDelegate[] = "delegate";
44 constexpr const char kDPrefix[] = "d::";
45 constexpr const char kUdPrefix[] = "ud::";
46
47 std::string GenInstance() {
48   uuid_t u;
49   uuid_generate(u);
50   char uuid[37];
51   uuid_unparse(u, uuid);
52   return std::string(uuid) + "@" + Aul::GetAppId(getpid());
53 }
54
55 int SendRequest(ClientSocket* client, const Request& request) {
56   tizen_base::Parcel parcel;
57   parcel.WriteParcelable(const_cast<Request&>(request));
58   size_t size = parcel.GetDataSize();
59   int ret = client->Send(reinterpret_cast<void*>(&size), sizeof(size));
60   if (ret != 0) {
61     _E("Send() is failed. error(%d)", ret);  // LCOV_EXCL_LINE
62     return -1;  // LCOV_EXCL_LINE
63   }
64
65   ret = client->Send(parcel.GetData(), size);
66   if (ret != 0) {
67     _E("Send() is failed. error(%d)", ret);  // LCOV_EXCL_LINE
68     return -1;  // LCOV_EXCL_LINE
69   }
70
71   return 0;
72 }
73
74 int ReceiveResponse(ClientSocket* client, Response** response) {
75   int flags = fcntl(client->GetFd(), F_GETFL, 0);
76   fcntl(client->GetFd(), F_SETFL, flags & ~O_NONBLOCK);
77
78   size_t size = 0;
79   int ret = client->Receive(reinterpret_cast<void*>(&size), sizeof(size));
80   if (ret != 0) {
81     // LCOV_EXCL_START
82     _E("Receive() is failed. error(%d)", ret);
83     fcntl(client->GetFd(), F_SETFL, flags);
84     return -1;
85     // LCOV_EXCL_STOP
86   }
87
88   uint8_t* buf = static_cast<uint8_t*>(malloc(size));
89   if (buf == nullptr) {
90     // LCOV_EXCL_START
91     _E("Out of memory");
92     fcntl(client->GetFd(), F_SETFL, flags);
93     return -1;
94     // LCOV_EXCL_STOP
95   }
96
97   ret = client->Receive(buf, size);
98   if (ret != 0) {
99     // LCOV_EXCL_START
100     _E("Receive() is failed. error(%d)", ret);
101     free(buf);
102     fcntl(client->GetFd(), F_SETFL, flags);
103     return -1;
104     // LCOV_EXCL_STOP
105   }
106
107   tizen_base::Parcel parcel(buf, size, false);
108   *response = new (std::nothrow) Response();
109   if (*response == nullptr) {
110     // LCOV_EXCL_START
111     _E("Out of memory");
112     fcntl(client->GetFd(), F_SETFL, flags);
113     return -1;
114     // LCOV_EXCL_STOP
115   }
116
117   parcel.ReadParcelable(*response);
118   fcntl(client->GetFd(), F_SETFL, flags);
119   return 0;
120 }
121
122 bool IsDaemon(const std::string& name) {
123   if (name.compare(0, strlen(kDPrefix), kDPrefix) == 0) return true;
124
125   if (name.compare(0, strlen(kUdPrefix), kUdPrefix) == 0) return true;
126
127   return false;
128 }
129
130 }  // namespace
131
132 Proxy::Proxy() {
133   _D("Proxy::Proxy()");
134 }
135
136 Proxy::~Proxy() {
137   std::lock_guard<std::recursive_mutex> lock(GetMutex());
138   _D("Proxy::~Proxy()");
139   if (main_port_.get() != nullptr)
140     DebugPort::RemoveSession(main_port_->GetFd());  // LCOV_EXCL_LINE
141
142   listener_ = nullptr;
143   UnsetIdler();
144   UnsetConnTimer();
145   Cancel();
146 }
147
148 int Proxy::MainPortConnect(const std::string& instance, bool sync) {
149   std::lock_guard<std::recursive_mutex> lock(GetMutex());
150   fds_[0] = 0;
151   main_client_.reset(Client::Create(this, port_path_));
152   if (main_client_.get() == nullptr)
153     return RPC_PORT_ERROR_IO_ERROR;  // LCOV_EXCL_LINE
154
155   Request request(instance.c_str(), kPortTypeMain);
156   int ret = SendRequest(main_client_.get(), request);
157   if (ret != 0) return RPC_PORT_ERROR_IO_ERROR;  // LCOV_EXCL_LINE
158
159   main_client_->SetNonblock();
160   if (sync) {
161     Response* response = nullptr;
162     ret = ReceiveResponse(main_client_.get(), &response);
163     if (ret != 0) return RPC_PORT_ERROR_IO_ERROR;  // LCOV_EXCL_LINE
164
165     std::unique_ptr<Response> response_auto(response);
166     if (response->GetResult() != 0) {
167       _E("Permission denied");                  // LCOV_EXCL_LINE
168       return RPC_PORT_ERROR_PERMISSION_DENIED;  // LCOV_EXCL_LINE
169     }
170
171     fds_[0] = main_client_->RemoveFd();
172   } else {
173     ret = main_client_->Watch();
174     if (ret != 0) return RPC_PORT_ERROR_IO_ERROR;  // LCOV_EXCL_LINE
175   }
176
177   return RPC_PORT_ERROR_NONE;
178 }
179
180 int Proxy::DelegatePortConnect(const std::string& instance, bool sync) {
181   std::lock_guard<std::recursive_mutex> lock(GetMutex());
182   fds_[1] = 0;
183   delegate_client_.reset(Client::Create(this, port_path_));
184   if (delegate_client_.get() == nullptr)
185     return RPC_PORT_ERROR_IO_ERROR;  // LCOV_EXCL_LINE
186
187   Request request(instance.c_str(), kPortTypeDelegate);
188   int ret = SendRequest(delegate_client_.get(), request);
189   if (ret != 0) return RPC_PORT_ERROR_IO_ERROR;  // LCOV_EXCL_LINE
190
191   delegate_client_->SetNonblock();
192   if (sync) {
193     Response* response = nullptr;
194     ret = ReceiveResponse(delegate_client_.get(), &response);
195     if (ret != 0) return RPC_PORT_ERROR_IO_ERROR;  // LCOV_EXCL_LINE
196
197     std::unique_ptr<Response> response_auto(response);
198     if (response->GetResult() != 0) {
199       _E("Permission denied");                  // LCOV_EXCL_LINE
200       return RPC_PORT_ERROR_PERMISSION_DENIED;  // LCOV_EXCL_LINE
201     }
202
203     fds_[1] = delegate_client_->RemoveFd();
204   } else {
205     ret = delegate_client_->Watch();
206     if (ret != 0) return RPC_PORT_ERROR_IO_ERROR;  // LCOV_EXCL_LINE
207   }
208
209   return RPC_PORT_ERROR_NONE;
210 }
211
212 int Proxy::Connect(bool sync) {
213   std::lock_guard<std::recursive_mutex> lock(GetMutex());
214   std::string instance = GenInstance();
215   int ret = MainPortConnect(instance, sync);
216   if (ret != RPC_PORT_ERROR_NONE) return ret;
217
218   ret = DelegatePortConnect(instance, sync);
219   if (ret != RPC_PORT_ERROR_NONE) return ret;
220
221   if (sync) {
222     main_port_.reset(new ProxyPort(this, fds_[0], target_appid_, false));
223     delegate_port_.reset(new ProxyPort(this, fds_[1], target_appid_));
224     DebugPort::AddSession(port_name_, target_appid_, fds_[0], fds_[1]);
225     listener_->OnConnected(target_appid_, main_port_.get());
226   }
227
228   return ret;
229 }
230
231 int Proxy::Connect(std::string appid, std::string port_name,
232     IEventListener* listener) {
233   if (listener == nullptr)
234     return RPC_PORT_ERROR_INVALID_PARAMETER;
235
236   std::lock_guard<std::recursive_mutex> lock(GetMutex());
237   if (HasRequested()) {
238     _D("Already requested");  // LCOV_EXCL_LINE
239     return RPC_PORT_ERROR_INVALID_PARAMETER;  // LCOV_EXCL_LINE
240   }
241
242   listener_ = listener;
243   target_appid_ = std::move(appid);
244   port_name_ = std::move(port_name);
245   SetRealAppId(target_appid_);
246   main_port_.reset();
247   delegate_port_.reset();
248   port_path_ =
249       Aul::GetPortPath(real_appid_, port_name_, rpc_port_get_target_uid());
250
251   Cancel();
252   UnsetConnTimer();
253   if (!IsDaemon(real_appid_)) {
254     int ret = Aul::PrepareStub(real_appid_, port_name_,
255         rpc_port_get_target_uid());
256     if (ret != RPC_PORT_ERROR_NONE) {
257       listener_ = nullptr;
258       return ret;
259     }
260   }
261
262   if (Watch() != 0) {
263     listener_ = nullptr;  // LCOV_EXCL_LINE
264     return RPC_PORT_ERROR_IO_ERROR;  // LCOV_EXCL_LINE
265   }
266
267   return RPC_PORT_ERROR_NONE;
268 }
269
270 int Proxy::ConnectSync(std::string appid, std::string port_name,
271     IEventListener* listener) {
272   if (listener == nullptr)
273     return RPC_PORT_ERROR_INVALID_PARAMETER;
274
275   std::lock_guard<std::recursive_mutex> lock(GetMutex());
276   if (HasRequested()) {
277     _D("Already requested");
278     return RPC_PORT_ERROR_INVALID_PARAMETER;
279   }
280
281   listener_ = listener;
282   target_appid_ = std::move(appid);
283   port_name_ = std::move(port_name);
284   SetRealAppId(target_appid_);
285   port_path_ =
286       Aul::GetPortPath(real_appid_, port_name_, rpc_port_get_target_uid());
287
288   if (!IsDaemon(real_appid_)) {
289     int ret = Aul::PrepareStub(real_appid_, port_name_,
290         rpc_port_get_target_uid());
291     if (ret != RPC_PORT_ERROR_NONE) {
292       listener_ = nullptr;
293       return ret;
294     }
295   }
296
297   if (!WaitUntilPortCreation())
298     return RPC_PORT_ERROR_IO_ERROR;
299
300   int ret = Connect(true);
301   if (ret != RPC_PORT_ERROR_NONE) {
302     // LCOV_EXCL_START
303     listener_ = nullptr;
304     return ret;
305     // LCOV_EXCL_STOP
306   }
307
308   return RPC_PORT_ERROR_NONE;
309 }
310
311 bool Proxy::WaitUntilPortCreation() {
312   file_monitor_.reset(new FileMonitor(port_path_));
313   int retry_count = 100;
314   do {
315     if (file_monitor_->Exist()) return true;
316
317     usleep(100 * 1000);
318     retry_count--;
319   } while (retry_count > 0);
320
321   if (!file_monitor_->Exist()) {
322     // LCOV_EXCL_START
323     _E("port(%s) of appid(%s) is not ready",
324         port_name_.c_str(), target_appid_.c_str());
325     return false;
326     // LCOV_EXCL_STOP
327   }
328
329   return true;
330 }
331
332 void Proxy::DisconnectPort() {
333   std::lock_guard<std::recursive_mutex> lock(GetMutex());
334   if (main_port_.get() != nullptr) {
335     DebugPort::RemoveSession(main_port_->GetFd());
336     main_port_.reset();
337   }
338 }
339
340 int Proxy::Watch() {
341   std::lock_guard<std::recursive_mutex> lock(GetMutex());
342   try {
343     file_monitor_.reset(new FileMonitor(port_path_, this));
344     file_monitor_->Start();
345     SetConnTimer();
346     SetIdler();
347   } catch (const Exception& e) {
348     LOGE("Exception occurs. error(%s)", e.what());
349     return -1;
350   }
351
352   return 0;
353 }
354
355 void Proxy::Cancel() {
356   std::lock_guard<std::recursive_mutex> lock(GetMutex());
357   file_monitor_.reset();
358 }
359
360 void Proxy::SetRealAppId(const std::string& alias_appid) {
361   std::lock_guard<std::recursive_mutex> lock(GetMutex());
362   if (!real_appid_.empty())
363     return;
364
365   if (IsDaemon(alias_appid)) {
366     real_appid_ = alias_appid;
367     return;
368   }
369
370   char* appid = nullptr;
371   int ret = aul_svc_get_appid_by_alias_appid(alias_appid.c_str(), &appid);
372   if (ret != AUL_SVC_RET_OK) {
373     real_appid_ = alias_appid;
374     return;
375   }
376
377   // LCOV_EXCL_START
378   std::unique_ptr<char, decltype(std::free)*> appid_ptr(appid, std::free);
379   real_appid_ = std::string(appid);
380   _W("alias_appid(%s), real_appid(%s)", alias_appid.c_str(), appid);
381   // LCOV_EXCL_STOP
382 }
383
384 std::recursive_mutex& Proxy::GetMutex() const {
385   return mutex_;
386 }
387
388 void Proxy::SetConnTimer() {
389   if (conn_timer_data_) {
390     _W("Already exists");  // LCOV_EXCL_START
391     return;  // LCOV_EXCL_START
392   }
393
394   conn_timer_data_ = CreateWeakPtr();
395   if (conn_timer_data_ == nullptr) {
396     _E("Out of memory");  // LCOV_EXCL_START
397     return;  // LCOV_EXCL_START
398   }
399
400   g_timeout_add_seconds(10, OnTimedOut, conn_timer_data_);
401 }
402
403 void Proxy::UnsetConnTimer() {
404   if (conn_timer_data_ == nullptr)
405     return;
406
407   GSource* source = g_main_context_find_source_by_user_data(nullptr,
408       conn_timer_data_);
409   if (source && !g_source_is_destroyed(source))
410     g_source_destroy(source);
411
412   DestroyWeakPtr(conn_timer_data_);
413   conn_timer_data_ = nullptr;
414 }
415
416 void Proxy::SetIdler() {
417   if (idler_data_) {
418     _W("Already exists");  // LCOV_EXCL_START
419     return;  // LCOV_EXCL_START
420   }
421
422   idler_data_ = CreateWeakPtr();
423   if (idler_data_ == nullptr) {
424     _E("Out of memory");  // LCOV_EXCL_START
425     return;  // LCOV_EXCL_START
426   }
427
428   g_idle_add(OnIdle, idler_data_);
429 }
430
431 void Proxy::UnsetIdler() {
432   if (idler_data_ == nullptr)
433     return;
434
435   GSource* source = g_main_context_find_source_by_user_data(nullptr,
436       idler_data_);
437   if (source && !g_source_is_destroyed(source))
438     g_source_destroy(source);
439
440   DestroyWeakPtr(idler_data_);
441   idler_data_ = nullptr;
442 }
443
444 void Proxy::OnFileCreated(const std::string& path) {
445   _W("appid=%s, port_name=%s, port_path=%s",
446       target_appid_.c_str(), port_name_.c_str(), path.c_str());
447   std::lock_guard<std::recursive_mutex> lock(GetMutex());
448   UnsetIdler();
449   Cancel();
450   if (listener_ == nullptr) return;  // LCOV_EXCL_LINE
451
452   int ret = Connect(false);
453   if (ret != RPC_PORT_ERROR_NONE) {
454     // LCOV_EXCL_START
455     UnsetConnTimer();
456     auto* listener = listener_;
457     listener_ = nullptr;
458     if (ret == RPC_PORT_ERROR_PERMISSION_DENIED)
459       listener->OnRejected(target_appid_, ret);
460     else
461       listener->OnDisconnected(target_appid_);
462     // LCOV_EXCL_STOP
463   }
464 }
465
466 void Proxy::OnFileDeleted(const std::string& path) {
467   _W("appid=%s, port_name=%s, port_path=%s",
468       target_appid_.c_str(), port_name_.c_str(), path.c_str());
469   std::lock_guard<std::recursive_mutex> lock(GetMutex());
470   UnsetIdler();
471 }
472
473 gboolean Proxy::OnTimedOut(gpointer user_data) {
474   _E("Timed out");
475   auto* ptr = static_cast<std::weak_ptr<Proxy>*>(user_data);
476   auto proxy = ptr->lock();
477   if (proxy == nullptr) {
478     _E("Proxy is nullptr");  // LCOV_EXCL_LINE
479     return G_SOURCE_REMOVE;  // LCOV_EXCL_LINE
480   }
481
482   std::lock_guard<std::recursive_mutex> lock(proxy->GetMutex());
483   if (proxy->conn_timer_data_ == nullptr) {
484     _E("Invalid context. proxy(%p)", proxy.get());  // LCOV_EXCL_LINE
485     return G_SOURCE_REMOVE;  // LCOV_EXCL_LINE
486   }
487
488   proxy->Cancel();
489   proxy->main_client_.reset();
490   proxy->delegate_client_.reset();
491   DestroyWeakPtr(proxy->conn_timer_data_);
492   proxy->conn_timer_data_ = nullptr;
493
494   auto* listener = proxy->listener_;
495   if (listener == nullptr) {
496     _E("Invalid context");  // LCOV_EXCL_LINE
497     return G_SOURCE_REMOVE;  // LCOV_EXCL_LINE
498   }
499
500   proxy->listener_ = nullptr;
501   listener->OnRejected(proxy->target_appid_, RPC_PORT_ERROR_IO_ERROR);
502   return G_SOURCE_REMOVE;
503 }
504
505 gboolean Proxy::OnIdle(gpointer user_data) {
506   auto* ptr = static_cast<std::weak_ptr<Proxy>*>(user_data);
507   auto proxy = ptr->lock();
508   if (proxy == nullptr) {
509     _E("Proxy is nullptr");  // LCOV_EXCL_LINE
510     return G_SOURCE_REMOVE;  // LCOV_EXCL_LINE
511   }
512
513   std::lock_guard<std::recursive_mutex> lock(proxy->GetMutex());
514   if (proxy->idler_data_ == nullptr) {
515     _E("Invalid context. proxy(%p)", proxy.get());  // LCOV_EXCL_LINE
516     return G_SOURCE_REMOVE;  // LCOV_EXCL_LINE
517   }
518
519   DestroyWeakPtr(proxy->idler_data_);
520   proxy->idler_data_ = nullptr;
521
522   if (proxy->file_monitor_->Exist()) {
523     proxy->OnFileCreated(proxy->port_path_);
524   } else {
525     proxy->OnFileDeleted(proxy->port_path_);
526   }
527
528   return G_SOURCE_REMOVE;
529 }
530
531 Proxy::ProxyPort::ProxyPort(Proxy* parent, int fd, const std::string& id,
532     bool receive)
533     : Port(fd, id), parent_(parent) {
534   Watch(receive);
535 }
536
537 Proxy::ProxyPort::~ProxyPort() {
538   if (disconn_source_ > 0)
539     g_source_remove(disconn_source_);
540
541   if (source_ > 0)
542     g_source_remove(source_);
543
544   if (channel_ != nullptr)
545     g_io_channel_unref(channel_);
546 }
547
548 int Proxy::ProxyPort::Watch(bool receive) {
549   channel_ = g_io_channel_unix_new(GetFd());
550   if (channel_ == nullptr) {
551     _E("g_io_channel_unix_new() is failed");  // LCOV_EXCL_LINE
552     return -1;  // LCOV_EXCL_LINE
553   }
554
555   disconn_source_ = g_io_add_watch(channel_,
556       static_cast<GIOCondition>(G_IO_ERR | G_IO_HUP | G_IO_NVAL),
557       Proxy::ProxyPort::OnSocketDisconnected, parent_);
558   if (disconn_source_ == 0) {
559     _E("g_io_add_watch() is failed");  // LCOV_EXCL_LINE
560     return -1;  // LCOV_EXCL_LINE
561   }
562
563   if (!receive)
564     return 0;
565
566   source_ = g_io_add_watch(channel_, static_cast<GIOCondition>(G_IO_IN),
567       Proxy::ProxyPort::OnDataReceived, parent_);
568   if (source_ == 0) {
569     _E("g_io_add_watch() is failed");  // LCOV_EXCL_LINE
570     return -1;  // LCOV_EXCL_LINE
571   }
572
573   return 0;
574 }
575
576 void Proxy::ProxyPort::SetDisconnectedSource(guint source_id) {
577   disconn_source_ = source_id;
578 }
579
580 void Proxy::ProxyPort::SetSource(guint source_id) {
581   source_ = source_id;
582 }
583
584 gboolean Proxy::ProxyPort::OnSocketDisconnected(GIOChannel* channel,
585     GIOCondition cond, gpointer user_data) {
586   auto* proxy = static_cast<Proxy*>(user_data);
587   std::lock_guard<std::recursive_mutex> lock(proxy->GetMutex());
588   auto* listener = proxy->listener_;
589   if (listener == nullptr) {
590     _E("Invalid context");  // LCOV_EXCL_LINE
591     return G_SOURCE_REMOVE;  // LCOV_EXCL_LINE
592   }
593
594   int fd = g_io_channel_unix_get_fd(channel);
595   _W("Socket was disconnected. fd(%d)", fd);
596   if (proxy->main_port_.get() != nullptr &&
597       proxy->main_port_->GetFd() == fd) {
598     proxy->main_port_->SetDisconnectedSource(0);
599   } else if (proxy->delegate_port_.get() != nullptr &&
600              proxy->delegate_port_->GetFd() == fd) {
601     proxy->delegate_port_->SetDisconnectedSource(0);
602   }
603
604   proxy->main_port_.reset();
605   proxy->delegate_port_.reset();
606   proxy->listener_ = nullptr;
607   listener->OnDisconnected(proxy->target_appid_);
608   DebugPort::RemoveSession(fd);
609   return G_SOURCE_REMOVE;
610 }
611
612 gboolean Proxy::ProxyPort::OnDataReceived(GIOChannel* channel,
613     GIOCondition cond, gpointer user_data) {
614   auto* proxy = static_cast<Proxy*>(user_data);
615   std::lock_guard<std::recursive_mutex> lock(proxy->GetMutex());
616   auto* listener = proxy->listener_;
617   if (listener == nullptr) {
618     _E("Invalid context");  // LCOV_EXCL_LINE
619     return G_SOURCE_REMOVE;  // LCOV_EXCL_LINE
620   }
621
622   int fd = g_io_channel_unix_get_fd(channel);
623   if (proxy->delegate_port_->GetFd() == fd) {
624     char buffer[4];
625     if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) {
626       _W("Socket was disconnected by stub. fd(%d)", fd);
627       proxy->listener_ = nullptr;
628       proxy->delegate_port_->SetSource(0);
629       if (proxy->main_port_.get() != nullptr) {
630         DebugPort::RemoveSession(proxy->main_port_->GetFd());
631         proxy->main_port_.reset();
632       }
633       proxy->delegate_port_.reset();
634       listener->OnDisconnected(proxy->target_appid_);
635       return G_SOURCE_REMOVE;
636     }
637
638     listener->OnReceived(proxy->target_appid_);
639   }
640
641   return G_SOURCE_CONTINUE;
642 }
643
644 Proxy::Client::Client(Proxy* parent) : parent_(parent) {
645 }
646
647 Proxy::Client::~Client() {
648   if (channel_)
649     g_io_channel_unref(channel_);
650
651   if (disconn_source_ > 0)
652     g_source_remove(disconn_source_);
653
654   if (source_ > 0)
655     g_source_remove(source_);
656 }
657
658 Proxy::Client* Proxy::Client::Create(Proxy* parent,
659     const std::string& endpoint) {
660   std::unique_ptr<Proxy::Client> client;
661   try {
662     client.reset(new (std::nothrow) Proxy::Client(parent));
663   } catch (const Exception& e) {
664     _E("Exception(%s) occurs", e.what());  // LCOV_EXCL_LINE
665     return nullptr;  // LCOV_EXCL_LINE
666   }
667
668   int ret;
669   int retry_count = 5;
670   do {
671     ret = client->Connect(endpoint);
672     if (ret == 0) {
673       break;
674     } else if (ret < 0) {
675       // LCOV_EXCL_START
676       _D("Connect() is failed");
677       usleep(100 * 1000);
678       retry_count--;
679       // LCOV_EXCL_STOP
680     }
681   } while (retry_count > 0);
682
683   if (ret != 0) {
684     _E("Connect() is failed");  // LCOV_EXCL_LINE
685     return nullptr;  // LCOV_EXCL_LINE
686   }
687
688   try {
689     client->SetReceiveTimeout(5000);
690   } catch (const Exception& e) {
691     _E("Exception occurs. error(%s)", e.what());  // LCOV_EXCL_LINE
692     return nullptr;  // LCOV_EXCL_LINE
693   }
694
695   _W("endpoint(%s), fd(%d)", endpoint.c_str(), client->GetFd());
696   return client.release();
697 }
698
699 int Proxy::Client::Watch() {
700   channel_ = g_io_channel_unix_new(GetFd());
701   if (channel_ == nullptr) {
702     _E("g_io_channel_unix_new() is failed");  // LCOV_EXCL_LINE
703     return -1;  // LCOV_EXCL_LINE
704   }
705
706   source_ = g_io_add_watch(channel_, static_cast<GIOCondition>(G_IO_IN),
707       Proxy::Client::OnResponseReceived, parent_);
708   if (source_ == 0) {
709     _E("g_io_add_watch() is failed");  // LCOV_EXCL_LINE
710     return -1;  // LCOV_EXCL_LINE
711   }
712
713   disconn_source_ = g_io_add_watch(channel_,
714       static_cast<GIOCondition>(G_IO_ERR | G_IO_HUP | G_IO_NVAL),
715       Proxy::Client::OnSocketDisconnected, parent_);
716   if (disconn_source_ == 0) {
717     _E("g_io_add_watch() is failed");  // LCOV_EXCL_LINE
718     return -1;  // LCOV_EXCL_LINE
719   }
720
721   return 0;
722 }
723
724 // LCOV_EXCL_START
725 void Proxy::Client::SetDisconnectedSource(guint source) {
726   disconn_source_ = source;
727 }
728 // LCOV_EXCL_STOP
729
730 void Proxy::Client::SetSource(guint source) {
731   source_ = source;
732 }
733
734 // LCOV_EXCL_START
735 gboolean Proxy::Client::OnSocketDisconnected(GIOChannel* channel,
736     GIOCondition cond, gpointer user_data) {
737   auto* proxy = static_cast<Proxy*>(user_data);
738   std::lock_guard<std::recursive_mutex> lock(proxy->GetMutex());
739   proxy->UnsetConnTimer();
740   auto* listener = proxy->listener_;
741   if (listener == nullptr) {
742     _E("Invalid context");
743     return G_SOURCE_REMOVE;
744   }
745
746   int fd = g_io_channel_unix_get_fd(channel);
747   _W("Socket was disconnected. fd(%d)", fd);
748   if (proxy->main_client_.get() != nullptr &&
749       proxy->main_client_->GetFd() == fd) {
750     proxy->main_client_->SetDisconnectedSource(0);
751   } else if (proxy->delegate_client_.get() != nullptr &&
752              proxy->delegate_client_->GetFd() == fd) {
753     proxy->delegate_client_->SetDisconnectedSource(0);
754   }
755
756   proxy->main_client_.reset();
757   proxy->delegate_client_.reset();
758   proxy->listener_ = nullptr;
759   listener->OnDisconnected(proxy->target_appid_);
760   return G_SOURCE_REMOVE;
761 }
762 // LCOV_EXCL_STOP
763
764 gboolean Proxy::Client::OnResponseReceived(GIOChannel* channel,
765     GIOCondition cond, gpointer user_data) {
766   auto* proxy = static_cast<Proxy*>(user_data);
767   std::lock_guard<std::recursive_mutex> lock(proxy->GetMutex());
768   proxy->UnsetConnTimer();
769   auto* listener = proxy->listener_;
770   if (listener == nullptr) {
771     _E("Invalid context");  // LCOV_EXCL_LINE
772     return G_SOURCE_REMOVE;  // LCOV_EXCL_LINE
773   }
774
775   bool is_delegate = false;
776   std::unique_ptr<Client> client;
777   int fd = g_io_channel_unix_get_fd(channel);
778   if (proxy->main_client_.get() != nullptr &&
779       proxy->main_client_->GetFd() == fd) {
780     client.reset(proxy->main_client_.release());
781   } else if (proxy->delegate_client_.get() != nullptr &&
782              proxy->delegate_client_->GetFd() == fd) {
783     client.reset(proxy->delegate_client_.release());
784     is_delegate = true;
785   }
786
787   if (client.get() == nullptr) {
788     _E("Unknown fd(%d)", fd);  // LCOV_EXCL_LINE
789     return G_SOURCE_REMOVE;  // LCOV_EXCL_LINE
790   }
791
792   client->SetSource(0);
793
794   Response* response = nullptr;
795   int ret = ReceiveResponse(client.get(), &response);
796   if (ret != 0) {
797     // LCOV_EXCL_START
798     proxy->listener_ = nullptr;
799     proxy->main_client_.reset();
800     proxy->delegate_client_.reset();
801     listener->OnRejected(proxy->target_appid_, RPC_PORT_ERROR_IO_ERROR);
802     return G_SOURCE_REMOVE;
803     // LCOV_EXCL_STOP
804   }
805
806   std::unique_ptr<Response> response_auto(response);
807   if (response->GetResult() != 0) {
808     _E("Permission denied");
809     proxy->listener_ = nullptr;
810     proxy->main_client_.reset();
811     proxy->delegate_client_.reset();
812     listener->OnRejected(proxy->target_appid_,
813         RPC_PORT_ERROR_PERMISSION_DENIED);
814     return G_SOURCE_REMOVE;
815   }
816
817   client->SetNonblock();
818   int client_fd = client->RemoveFd();
819   if (is_delegate) {
820     _W("[DELEGATE] Result received");
821     proxy->fds_[1] = client_fd;
822     proxy->delegate_port_.reset(
823         new ProxyPort(proxy, proxy->fds_[1], proxy->target_appid_));
824   } else {
825     _W("[MAIN] Result received");
826     proxy->fds_[0] = client_fd;
827     proxy->main_port_.reset(
828         new ProxyPort(proxy, proxy->fds_[0], proxy->target_appid_, false));
829   }
830
831   if (proxy->main_port_.get() != nullptr &&
832       proxy->delegate_port_.get() != nullptr) {
833     _W("target_appid(%s), port_name(%s), main_fd(%d), delegate_fd(%d)",
834         proxy->target_appid_.c_str(), proxy->port_name_.c_str(),
835         proxy->fds_[0], proxy->fds_[1]);
836
837     DebugPort::AddSession(proxy->port_name_, proxy->target_appid_,
838         proxy->fds_[0], proxy->fds_[1]);
839     listener->OnConnected(proxy->target_appid_, proxy->main_port_.get());
840   }
841
842   return G_SOURCE_REMOVE;
843 }
844
845 std::shared_ptr<Proxy> Proxy::GetSharedPtr() {
846   return shared_from_this();
847 }
848
849 gpointer Proxy::CreateWeakPtr() {
850   auto* ptr = new (std::nothrow) std::weak_ptr<Proxy>(GetSharedPtr());
851   return static_cast<gpointer>(ptr);
852 }
853
854 void Proxy::DestroyWeakPtr(gpointer data) {
855   auto* ptr = static_cast<std::weak_ptr<Proxy>*>(data);
856   delete ptr;
857 }
858
859 bool Proxy::HasRequested() const {
860   return listener_ != nullptr &&
861       (!main_port_ || !delegate_port_ || main_port_->GetFd() > 0);
862 }
863
864 }  // namespace internal
865 }  // namespace rpc_port