f09f7a67992ce0b2f4f15f010391fbe2cff495f2
[platform/core/appfw/rpc-port.git] / src / fdbroker-internal.cc
1 /*
2  * Copyright (c) 2017 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 #ifndef _GNU_SOURCE
18 #define _GNU_SOURCE
19 #endif
20
21 #include <string.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <aul.h>
25 #include <aul_rpc_port.h>
26 #include <dlog.h>
27
28 #include <algorithm>
29
30 #include "fdbroker-internal.h"
31
32 #ifdef LOG_TAG
33 #undef LOG_TAG
34 #endif
35
36 #define LOG_TAG "RPC_PORT"
37
38 #define EILLEGALACCESS 127
39
40 #define DBUS_SERVICE_DBUS "org.freedesktop.DBus"
41 #define DBUS_PATH_DBUS "/org/freedesktop/DBus"
42 #define DBUS_INTERFACE_DBUS "org.freedesktop.DBus"
43 #define RPC_PORT_OBJECT_PATH "/org/tizen/rpcport"
44 #define RPC_PORT_INTERFACE_PREFIX "org.tizen.rpcport._"
45
46 namespace rpc_port {
47 namespace internal {
48
49 FdBroker::DBusConnectionManager& FdBroker::DBusConnectionManager::GetInst() {
50   static DBusConnectionManager dm;
51
52   if (dm.disposed_) {
53     dm.Init();
54   }
55
56   return dm;
57 }
58
59 // LCOV_EXCL_START
60 void FdBroker::DBusConnectionManager::Dispose() {
61   if (!disposed_)
62     Fini();
63 }
64 // LCOV_EXCL_STOP
65
66 GDBusConnection* FdBroker::DBusConnectionManager::GetConnection() {
67   return gdbus_conn_;
68 }
69
70 FdBroker::DBusConnectionManager::~DBusConnectionManager() {
71   if (!disposed_)
72     Fini();
73 }
74
75 void FdBroker::DBusConnectionManager::Init() {
76   GError* error = nullptr;
77
78   gdbus_conn_ = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
79   if (gdbus_conn_ == nullptr) {
80     // LCOV_EXCL_START
81     if (error != nullptr) {
82       LOGE("Failed to get dbus [%s]", error->message);
83       g_error_free(error);
84     }
85
86     return;
87     // LCOV_EXCL_STOP
88   }
89
90   disposed_ = false;
91 }
92
93 void FdBroker::DBusConnectionManager::Fini() {
94   if (gdbus_conn_ != nullptr) {
95     g_object_unref(gdbus_conn_);
96     gdbus_conn_ = nullptr;
97   }
98
99   disposed_ = true;
100 }
101
102 // LCOV_EXCL_START
103 FdBroker::DBusMock& FdBroker::DBusMock::GetInst() {
104   static DBusMock mock;
105
106   return mock;
107 }
108 // LCOV_EXCL_STOP
109
110 // LCOV_EXCL_START
111 int FdBroker::DBusMock::Send(const std::string& sender,
112                              const std::string& port, int fds[2]) {
113   if (port == "wrong_port")
114     return -EILLEGALACCESS;
115   if (ports_.find(port) == ports_.end())
116     return -1;
117
118   ports_[port]->OnFdReceived(sender, fds);
119   return 0;
120 }
121 // LCOV_EXCL_STOP
122
123 // LCOV_EXCL_START
124 int FdBroker::DBusMock::AddListener(const std::string& port,
125                                     FdBroker::IEventListener* listener) {
126   if (ports_.find(port) != ports_.end())
127     return -1;
128
129   ports_[port] = listener;
130   return 0;
131 }
132 // LCOV_EXCL_STOP
133
134 // LCOV_EXCL_START
135 int FdBroker::DBusMock::Watch(FdBroker::IEventWatcher* watcher,
136                               const std::string& target_appid,
137                               const std::string& port_name) {
138   watcher->OnPortAppeared(target_appid, port_name);
139   return 0;
140 }
141 // LCOV_EXCL_STOP
142
143 // LCOV_EXCL_START
144 void FdBroker::DBusMock::Dispose() {
145   ports_.clear();
146 }
147 // LCOV_EXCL_STOP
148
149 FdBroker::SocketPair::SocketPair(bool mock)
150     : mock_(mock) {
151   socks_[SENDER] = 0;
152   socks_[RECEIVER] = 0;
153 }
154
155 FdBroker::SocketPair::~SocketPair() {
156   if (socks_[SENDER] > 0)
157     close(socks_[SENDER]);
158   if (socks_[RECEIVER] > 0)
159     close(socks_[RECEIVER]);
160 }
161
162 int FdBroker::SocketPair::Request(const std::string& target_appid,
163                                   const std::string& port_name) {
164   if (mock_) {
165     return socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, socks_);  // LCOV_EXCL_LINE
166   }
167
168   if (aul_rpc_port_create_socket_pair(target_appid.c_str(),
169       port_name.c_str(), &socks_) != AUL_R_OK) {
170     LOGE("error create socket pair");  // LCOV_EXCL_LINE
171     return -1;  // LCOV_EXCL_LINE
172   }
173
174   return 0;
175 }
176
177 int FdBroker::SocketPair::Get(Type t) const {
178   return socks_[t];
179 }
180
181 int FdBroker::SocketPair::Detach(Type t) {
182   int fd = socks_[t];
183
184   socks_[t] = 0;
185   return fd;
186 }
187
188 FdBroker::FdList::FdList() {
189   fd_list_ = g_unix_fd_list_new();
190 }
191
192 FdBroker::FdList::~FdList() {
193   g_object_unref(fd_list_);
194 }
195
196 int FdBroker::FdList::Add(int fd) {
197   GError *err = nullptr;
198
199   g_unix_fd_list_append(fd_list_, fd, &err);
200   close(fd);
201
202   if (err != NULL) {
203     LOGE("g_unix_fd_list_append [%s]", err->message);  // LCOV_EXCL_LINE
204     g_error_free(err);  // LCOV_EXCL_LINE
205     return -1;  // LCOV_EXCL_LINE
206   }
207
208   return 0;
209 }
210
211 GUnixFDList* FdBroker::FdList::GetRaw() {
212   return fd_list_;
213 }
214
215 FdBroker::FdBroker(bool mock) : mock_(mock) {
216 }
217
218 FdBroker::~FdBroker() {
219   Cancel();
220 }
221
222 void FdBroker::Cancel() {
223   std::lock_guard<std::recursive_mutex> lock(GetMutex());
224   LOGI("FdBroker::Cancel!");
225
226   if (cancellable_) {
227     LOGW("Cancel the send request");
228     g_cancellable_cancel(cancellable_);
229     g_object_unref(cancellable_);
230     cancellable_ = nullptr;
231   }
232
233   if (res_data_) {
234     DestroyWeakPtr(res_data_);
235     res_data_ = nullptr;
236   }
237
238   UnsetConnTimer();
239
240   if (watcher_id_ > 0) {
241     g_bus_unwatch_name(watcher_id_);
242     watcher_id_ = 0;
243   }
244
245   if (registration_id_ > 0) {
246     g_dbus_connection_unregister_object(
247         DBusConnectionManager::GetInst().GetConnection(),
248         registration_id_);
249     registration_id_ = 0;
250   }
251
252   if (mock_) {
253     DBusMock::GetInst().Dispose();  // LCOV_EXCL_LINE
254   }
255 }
256
257 std::string FdBroker::GetInterfaceName(const std::string& target_appid,
258                              const std::string& port_name) {
259   std::string interface_name = target_appid + "_" + port_name;
260   char c_buf[interface_name.length() * 2 + 1];
261   char* temp = &c_buf[0];
262   memset(c_buf, 0, sizeof(c_buf));
263   for (unsigned int index = 0; index < interface_name.length(); index++) {
264     snprintf(temp, 3, "%02x", interface_name[index]);
265     temp += 2;
266   }
267
268   return RPC_PORT_INTERFACE_PREFIX + std::string(c_buf);
269 }
270
271 int FdBroker::Send(const std::string& target_appid,
272                    const std::string& port_name,
273                    int (*fds)[2]) {
274   std::string interface_name = GetInterfaceName(target_appid, port_name);
275   GDBusMessage *msg;
276   SocketPair main_sock_pair(mock_);
277   SocketPair delegate_sock_pair(mock_);
278   FdList fd_list;
279   char sender_appid[255];
280
281   if (!mock_ && aul_app_get_appid_bypid(getpid(),
282        sender_appid, sizeof(sender_appid)) < 0) {
283     LOGE("Can't get appid");  // LCOV_EXCL_LINE
284     return -1;  // LCOV_EXCL_LINE
285   }
286
287   if (main_sock_pair.Request(target_appid, port_name) != 0)
288     return -1;
289   if (delegate_sock_pair.Request(target_appid, port_name) != 0)
290     return -1;
291
292   if (mock_) {
293     // LCOV_EXCL_START
294     int send_fds[2];
295     send_fds[0] = main_sock_pair.Detach(SocketPair::RECEIVER);
296     send_fds[1] = delegate_sock_pair.Detach(SocketPair::RECEIVER);
297     int ret = DBusMock::GetInst().Send("TestApp", port_name, send_fds);
298     if (ret < 0)
299       return ret;
300
301     (*fds)[0] = main_sock_pair.Detach(SocketPair::SENDER);
302     (*fds)[1] = delegate_sock_pair.Detach(SocketPair::SENDER);
303     watcher_->OnPortConnected(watch_appid_, watch_port_name_);
304     return (*fds)[0];
305     // LCOV_EXCL_STOP
306   }
307
308   if (fd_list.Add(main_sock_pair.Detach(SocketPair::RECEIVER)) != 0)
309     return -1;
310   if (fd_list.Add(delegate_sock_pair.Detach(SocketPair::RECEIVER)) != 0)
311     return -1;
312
313   msg = g_dbus_message_new_method_call(interface_name.c_str(),
314                                        RPC_PORT_OBJECT_PATH,
315                                        interface_name.c_str(), "send_message");
316   if (!msg) {
317     LOGE("Can't allocate new method call");  // LCOV_EXCL_LINE
318     return -1;  // LCOV_EXCL_LINE
319   }
320
321   std::lock_guard<std::recursive_mutex> lock(GetMutex());
322   if (cancellable_) {
323     g_cancellable_cancel(cancellable_);  // LCOV_EXCL_LINE
324     g_object_unref(cancellable_);  // LCOV_EXCL_LINE
325   }
326
327   cancellable_ = g_cancellable_new();
328   if (!cancellable_) {
329     LOGE("Failed to create GCancellable");  // LCOV_EXCL_LINE
330     g_object_unref(msg);  // LCOV_EXCL_LINE
331     return -1;  // LCOV_EXCL_LINE
332   }
333
334   if (res_data_)
335     DestroyWeakPtr(res_data_);
336
337   res_data_ = CreateWeakPtr();
338   if (res_data_ == nullptr) {
339     LOGE("Failed to create weak ptr");
340     g_object_unref(msg);
341     return -1;
342   }
343
344   g_dbus_message_set_unix_fd_list(msg, fd_list.GetRaw());
345   g_dbus_connection_send_message_with_reply(
346       DBusConnectionManager::GetInst().GetConnection(),
347       msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE,
348       5000, NULL, cancellable_, OnResultReceived, res_data_);
349   g_object_unref(msg);
350
351   (*fds)[0] = main_sock_pair.Detach(SocketPair::SENDER);
352   (*fds)[1] = delegate_sock_pair.Detach(SocketPair::SENDER);
353
354   return (*fds)[0];
355 }
356
357 // LCOV_EXCL_START
358 int FdBroker::SendSync(const std::string& target_appid,
359                        const std::string& port_name,
360                        int (*fds)[2]) {
361   char sender_appid[255] = { 0, };
362   int ret;
363   if (!mock_) {
364     ret = aul_app_get_appid_bypid(getpid(), sender_appid, sizeof(sender_appid));
365     if (ret != AUL_R_OK) {
366       LOGE("Failed to get application ID. ret(%d)", ret);
367       return -1;
368     }
369   }
370
371   SocketPair main_sock_pair(mock_);
372   ret = main_sock_pair.Request(target_appid, port_name);
373   if (ret != 0)
374     return -1;
375
376   SocketPair delegate_sock_pair(mock_);
377   ret = delegate_sock_pair.Request(target_appid, port_name);
378   if (ret != 0)
379     return -1;
380
381   if (mock_) {
382     int send_fds[2];
383     send_fds[0] = main_sock_pair.Detach(SocketPair::RECEIVER);
384     send_fds[1] = delegate_sock_pair.Detach(SocketPair::RECEIVER);
385
386     ret = DBusMock::GetInst().Send("TestApp", port_name, send_fds);
387     if (ret < 0)
388       return ret;
389
390     (*fds)[0] = main_sock_pair.Detach(SocketPair::SENDER);
391     (*fds)[1] = delegate_sock_pair.Detach(SocketPair::SENDER);
392     return (*fds)[0];
393   }
394
395   FdList fd_list;
396   ret = fd_list.Add(main_sock_pair.Detach(SocketPair::RECEIVER));
397   if (ret != 0)
398     return -1;
399
400   ret = fd_list.Add(delegate_sock_pair.Detach(SocketPair::RECEIVER));
401   if (ret != 0)
402     return -1;
403
404   std::string interface_name = GetInterfaceName(target_appid, port_name);
405
406 #define MAX_CNT 100
407 #define MAX_SLEEP 100
408 #define MIN_SLEEP 50
409 #define BASE_SLEEP (1000 * 1000)
410   GDBusMessage* reply;
411   GError* err = nullptr;
412   struct timespec try_sleep_time = { 0, MIN_SLEEP * BASE_SLEEP };
413   struct timespec start_time = { 0, };
414   struct timespec end_time = { 0, };
415   int max_timeout = MAX_CNT * MAX_SLEEP;
416
417   do {
418     clock_gettime(CLOCK_MONOTONIC, &start_time);
419     GDBusMessage* msg = g_dbus_message_new_method_call(interface_name.c_str(),
420         RPC_PORT_OBJECT_PATH, interface_name.c_str(), "send_message");
421     if (msg == nullptr) {
422       LOGE("g_dbus_message_new_method_call() is failed");
423       return -1;
424     }
425
426     g_dbus_message_set_unix_fd_list(msg, fd_list.GetRaw());
427
428     reply = g_dbus_connection_send_message_with_reply_sync(
429         DBusConnectionManager::GetInst().GetConnection(),
430         msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE, 500, nullptr, nullptr, &err);
431     clock_gettime(CLOCK_MONOTONIC, &end_time);
432     g_object_unref(msg);
433
434     if (reply && !g_dbus_message_to_gerror(reply, &err))
435       break;
436
437     if (reply == nullptr) {
438       LOGE("g_dbus_connection_send_message_with_reply_sync() is failed");
439       if (err) {
440         LOGE("error(%s)", err->message);
441         g_error_free(err);
442       }
443     } else if (g_dbus_message_to_gerror(reply, &err)) {
444       LOGE("error(%s) was set", err->message);
445       g_error_free(err);
446       g_object_unref(reply);
447     }
448     err = nullptr;
449
450     max_timeout -= (((end_time.tv_sec - start_time.tv_sec) * 1000) +
451         ((end_time.tv_nsec - start_time.tv_nsec) / BASE_SLEEP));
452     if (max_timeout <= 0)
453       break;
454
455     nanosleep(&try_sleep_time, 0);
456     max_timeout -= (try_sleep_time.tv_nsec / BASE_SLEEP);
457     if (max_timeout <= 0)
458       break;
459
460     try_sleep_time.tv_nsec *= 2;
461     if (try_sleep_time.tv_nsec > (MAX_SLEEP * BASE_SLEEP))
462       try_sleep_time.tv_nsec = MAX_SLEEP * BASE_SLEEP;
463
464     LOGD("Retry");
465   } while (max_timeout > 0);
466
467   if (max_timeout <= 0) {
468     LOGE("Timed out");
469     return -1;
470   }
471
472   GVariant* reply_body = g_dbus_message_get_body(reply);
473   if (reply_body == nullptr) {
474     LOGE("g_dbus_message_get_body() is failed");
475     g_object_unref(reply);
476     return -1;
477   }
478
479   g_variant_get(reply_body, "(i)", &ret);
480   if (ret != 0) {
481     LOGE("Access Denied[sender_appid: %s, result: %d]", sender_appid, ret);
482     g_object_unref(reply);
483     return -EILLEGALACCESS;
484   }
485
486   LOGD("[Reply: %d]", ret);
487
488   (*fds)[0] = main_sock_pair.Detach(SocketPair::SENDER);
489   (*fds)[1] = delegate_sock_pair.Detach(SocketPair::SENDER);
490
491   return (*fds)[0];
492 }
493 // LCOV_EXCL_STOP
494
495 void FdBroker::ReceiveMessage(const char* sender_appid,
496                               GDBusMethodInvocation* invocation) {
497   GDBusMessage* msg;
498   GUnixFDList* fd_list;
499   int fd_len = 0;
500   int* returned_fds = nullptr;
501
502   msg = g_dbus_method_invocation_get_message(invocation);
503   fd_list = g_dbus_message_get_unix_fd_list(msg);
504
505   if (fd_list == nullptr)
506     return;  // LCOV_EXCL_LINE
507
508   returned_fds = g_unix_fd_list_steal_fds(fd_list, &fd_len);
509   if (returned_fds == nullptr || fd_len != 2) {
510     LOGE("fail to get fds. fd_len(%d)", fd_len);  // LCOV_EXCL_LINE
511     return;  // LCOV_EXCL_LINE
512   }
513
514   listener_->OnFdReceived(sender_appid, returned_fds);
515   free(returned_fds);
516 }
517
518 void FdBroker::OnReceiveDbusMethod(GDBusConnection *conn,
519     const gchar *sender, const gchar *object_path,
520     const gchar *iface_name, const gchar *method_name,
521     GVariant *parameters, GDBusMethodInvocation *invocation,
522     gpointer user_data) {
523   auto* ptr = static_cast<std::weak_ptr<FdBroker>*>(user_data);
524   auto broker = ptr->lock();
525   if (broker == nullptr) {
526     LOGE("broker is nullptr");
527     return;
528   }
529
530   std::lock_guard<std::recursive_mutex> lock(broker->GetMutex());
531   if (broker->registration_id_ == 0) {
532     LOGE("Invalid context. FdBroker(%p)", broker.get());
533     return;
534   }
535
536   int ret = -1;
537   char sender_appid[255];
538   int sender_pid;
539
540   sender_pid = broker->GetSenderPid(conn, sender);
541   if (aul_app_get_appid_bypid(sender_pid, sender_appid,
542       sizeof(sender_appid)) < 0) {
543     g_dbus_method_invocation_return_value(invocation,
544         g_variant_new("(i)", ret));
545     return;
546   }
547
548   AccessController& ac = broker->GetAccessController();
549   ret = ac.Check(conn, sender, sender_appid);
550   if (ret == 0)
551     broker->ReceiveMessage(sender_appid, invocation);
552
553   g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ret));
554 }
555
556 int FdBroker::GetOwnerId(const std::string& interface_name) {
557   int owner_id = 0;
558   GError *error = NULL;
559
560   GVariant* result = g_dbus_connection_call_sync(
561       DBusConnectionManager::GetInst().GetConnection(),
562       DBUS_SERVICE_DBUS,
563       DBUS_PATH_DBUS,
564       DBUS_INTERFACE_DBUS,
565       "RequestName",
566       g_variant_new("(su)", interface_name.c_str(),
567           G_BUS_NAME_OWNER_FLAGS_NONE),
568       G_VARIANT_TYPE("(u)"),
569       G_DBUS_CALL_FLAGS_NONE,
570       -1,
571       nullptr,
572       &error);
573
574   if (error) {
575     LOGE("RequestName fail : %s", error->message);  // LCOV_EXCL_LINE
576     g_error_free(error);  // LCOV_EXCL_LINE
577     return -1;  // LCOV_EXCL_LINE
578   }
579
580   if (result == nullptr) {
581     LOGE("fail to get name NULL");  // LCOV_EXCL_LINE
582     return -1;  // LCOV_EXCL_LINE
583   }
584
585   g_variant_get(result, "(u)", &owner_id);
586   if (owner_id == 0) {
587     LOGE("Acquiring the own name is failed");  // LCOV_EXCL_LINE
588     g_variant_unref(result);  // LCOV_EXCL_LINE
589     return -1;  // LCOV_EXCL_LINE
590   }
591
592   LOGD("Acquiring the own name : %d", owner_id);
593   g_variant_unref(result);
594
595   return owner_id;
596 }
597
598 int FdBroker::GetSenderPid(GDBusConnection *connection, const gchar *sender) {
599   GDBusMessage *msg = NULL;
600   GDBusMessage *reply = NULL;
601   GError *err = NULL;
602   GVariant *body;
603   int pid = 0;
604
605   msg = g_dbus_message_new_method_call("org.freedesktop.DBus",
606       "/org/freedesktop/DBus", "org.freedesktop.DBus",
607       "GetConnectionUnixProcessID");
608   if (!msg) {
609     LOGE("Can't allocate new method call");  // LCOV_EXCL_LINE
610     goto out;  // LCOV_EXCL_LINE
611   }
612
613   g_dbus_message_set_body(msg, g_variant_new("(s)", sender));
614   reply = g_dbus_connection_send_message_with_reply_sync(connection, msg,
615       G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL, &err);
616
617   if (!reply) {
618     // LCOV_EXCL_START
619     if (err != NULL) {
620       LOGE("Failed to get pid [%s]", err->message);
621       g_error_free(err);
622     }
623     goto out;
624     // LCOV_EXCL_STOP
625   }
626
627   body = g_dbus_message_get_body(reply);
628   g_variant_get(body, "(u)", &pid);
629
630 out:
631   if (msg)
632     g_object_unref(msg);
633   if (reply)
634     g_object_unref(reply);
635
636   return pid;
637 }
638
639 int FdBroker::RegisterDbusInterface(const std::string& port_name) {
640   static const GDBusInterfaceVTable interface_vtable = {
641     OnReceiveDbusMethod,
642     nullptr,
643     nullptr
644   };
645   static const char introspection_prefix[] =
646     "<node>"
647     "  <interface name='";
648   static const char introspection_postfix[] =
649     "'>"
650     "  <method name='send_message'>"
651     "    <arg type='i' name='response' direction='out'/>"
652     "  </method>"
653     "  </interface>"
654     "</node>";
655   char appid[255];
656
657   if (aul_app_get_appid_bypid(getpid(), appid, sizeof(appid)) < 0)
658     return -1;
659
660   std::string interface_name = GetInterfaceName(appid, port_name);
661   std::string introspection_xml = introspection_prefix +
662                                   interface_name +
663                                   introspection_postfix;
664
665   GDBusNodeInfo* introspection_data = g_dbus_node_info_new_for_xml(
666       introspection_xml.c_str(), nullptr);
667   if (!introspection_data) {
668     LOGE("g_dbus_node_info_new_for_xml() is failed.");
669     return -1;
670   }
671
672   auto broker = CreateWeakPtr();
673   if (broker == nullptr) {
674     LOGE("Failed to create weak ptr");
675     return -1;
676   }
677
678   std::lock_guard<std::recursive_mutex> lock(GetMutex());
679   registration_id_ = g_dbus_connection_register_object(
680       DBusConnectionManager::GetInst().GetConnection(),
681       RPC_PORT_OBJECT_PATH, introspection_data->interfaces[0],
682       &interface_vtable, broker, DestroyWeakPtr, nullptr);
683
684   g_dbus_node_info_unref(introspection_data);
685   if (registration_id_ == 0) {
686     LOGE("Failed to g_dbus_connection_register_object");
687     return -1;
688   }
689
690   if (GetOwnerId(interface_name) < 0) {
691     LOGE("Failed to get owner id");
692     return -1;
693   }
694
695   LOGI("%s is registered", port_name.c_str());
696
697   return 0;
698 }
699
700 int FdBroker::Listen(IEventListener* ev, const std::string& port_name) {
701   if (listener_ != nullptr) {
702     LOGE("listener_ is not NULL");  // LCOV_EXCL_LINE
703     return RPC_PORT_ERROR_INVALID_PARAMETER;  // LCOV_EXCL_LINE
704   }
705
706   if (ev == nullptr) {
707     LOGE("ev is NULL");  // LCOV_EXCL_LINE
708     return RPC_PORT_ERROR_INVALID_PARAMETER;  // LCOV_EXCL_LINE
709   }
710
711   if (mock_) {
712     // LCOV_EXCL_START
713     int ret = DBusMock::GetInst().AddListener(port_name, ev);
714
715     if (ret < 0)
716       return ret;
717
718     return RPC_PORT_ERROR_NONE;
719     // LCOV_EXCL_STOP
720   }
721
722   int ret = RegisterDbusInterface(port_name);
723
724   if (ret != 0) {
725     LOGE("Failed to register dbus interface");  // LCOV_EXCL_LINE
726     return RPC_PORT_ERROR_IO_ERROR;  // LCOV_EXCL_LINE
727   }
728
729   listener_ = ev;
730   return RPC_PORT_ERROR_NONE;
731 }
732
733 AccessController& FdBroker::GetAccessController() {
734   return ac_;
735 }
736
737 void FdBroker::OnNameAppeared(GDBusConnection *connection,
738                               const gchar *name,
739                               const gchar *name_owner,
740                               gpointer user_data) {
741   auto* ptr = static_cast<std::weak_ptr<FdBroker>*>(user_data);
742   auto broker = ptr->lock();
743   if (broker == nullptr) {
744     LOGE("broker is nullptr");
745     return;
746   }
747
748   std::lock_guard<std::recursive_mutex> lock(broker->GetMutex());
749   if (broker->watcher_id_ == 0) {
750     LOGE("Invalid context. FdBroker(%p)", broker.get());
751     return;
752   }
753
754   broker->UnsetConnTimer();
755   int pid = broker->GetSenderPid(connection, name_owner);
756   char owner_appid[255] = { 0, };
757
758   if (aul_app_get_appid_bypid(pid, owner_appid, sizeof(owner_appid)) < 0) {
759     // LCOV_EXCL_START
760     LOGE("aul_app_get_appid_bypid failed %d", pid);
761     broker->watcher_->OnPortRejected(owner_appid,
762         RPC_PORT_ERROR_IO_ERROR);
763     return;
764     // LCOV_EXCL_STOP
765   }
766
767   if (broker->watch_appid_ != owner_appid) {
768     // LCOV_EXCL_START
769     LOGE("invalid appid %s", owner_appid);
770     broker->watcher_->OnPortRejected(owner_appid,
771         RPC_PORT_ERROR_IO_ERROR);
772     return;
773     // LCOV_EXCL_STOP
774   }
775
776   broker->watcher_->OnPortAppeared(broker->watch_appid_,
777       broker->watch_port_name_);
778 }
779
780 void FdBroker::OnNameVanished(GDBusConnection *connection,
781                               const gchar *name,
782                               gpointer user_data) {
783   auto* ptr = static_cast<std::weak_ptr<FdBroker>*>(user_data);
784   auto broker = ptr->lock();
785   if (broker == nullptr) {
786     LOGE("broker is nullptr");
787     return;
788   }
789
790   std::lock_guard<std::recursive_mutex> lock(broker->GetMutex());
791   if (broker->watcher_id_ == 0) {
792     LOGE("Invalid context. FdBroker(%p)", broker.get());
793     return;
794   }
795
796   broker->watcher_->OnPortVanished(broker->watch_appid_,
797       broker->watch_port_name_);
798 }
799
800 int FdBroker::Watch(IEventWatcher* ev, const std::string& target_appid,
801                     const std::string& port_name) {
802   std::lock_guard<std::recursive_mutex> lock(GetMutex());
803   if (ev == nullptr)
804     return -1;
805
806   int ret = Prepare(target_appid, port_name);
807   if (ret < 0)
808     return ret;
809
810   watcher_ = ev;
811   watch_appid_ = target_appid;
812   watch_port_name_ = port_name;
813
814   UnsetConnTimer();
815   SetConnTimer();
816
817   if (mock_) {
818     // LCOV_EXCL_START
819     ret = DBusMock::GetInst().Watch(ev, target_appid, port_name);
820     if (ret < 0)
821       return -1;
822
823     return 0;
824     // LCOV_EXCL_STOP
825   }
826
827   std::string interface_name = GetInterfaceName(target_appid, port_name);
828
829   if (watcher_id_ > 0) {
830     // LCOV_EXCL_START
831     g_bus_unwatch_name(watcher_id_);
832     LOGD("Retry to watch name. stub %s:%s",
833         target_appid.c_str(), port_name.c_str());
834     // LCOV_EXCL_STOP
835   }
836
837   auto broker = CreateWeakPtr();
838   if (broker == nullptr) {
839     LOGE("Failed to create weak ptr");
840     return -1;
841   }
842
843   watcher_id_ = g_bus_watch_name_on_connection(
844       DBusConnectionManager::GetInst().GetConnection(),
845       interface_name.c_str(),
846       G_BUS_NAME_WATCHER_FLAGS_NONE,
847       OnNameAppeared,
848       OnNameVanished,
849       broker,
850       DestroyWeakPtr);
851   if (watcher_id_ == 0) {
852     // LCOV_EXCL_START
853     LOGE("Failed to watch connection(%s)", interface_name.c_str());
854     watcher_ = nullptr;
855     return -1;
856     // LCOV_EXCL_STOP
857   }
858
859   return 0;
860 }
861
862 int FdBroker::Prepare(const std::string& target_appid,
863                       const std::string& port_name) {
864   if (!mock_) {
865     int ret = aul_rpc_port_prepare_stub(target_appid.c_str(),
866         port_name.c_str());
867     if (ret != AUL_R_OK) {
868       // LCOV_EXCL_START
869       LOGE("Failed to prepare stub %s:%s [ret : %d]",
870           target_appid.c_str(), port_name.c_str(), ret);
871       if (ret == AUL_R_EILLACC)
872         return -EILLEGALACCESS;
873
874       return ret;
875       // LCOV_EXCL_STOP
876     }
877   }
878
879   return 0;
880 }
881
882 void FdBroker::OnResultReceived(GObject* source_object,
883                                 GAsyncResult* res,
884                                 gpointer user_data) {
885   LOGW("OnResultReceived()");
886   GDBusConnection* conn = reinterpret_cast<GDBusConnection*>(source_object);
887   GError* err = nullptr;
888   GDBusMessage* reply = g_dbus_connection_send_message_with_reply_finish(conn,
889       res, &err);
890
891   if (err && err->code == G_IO_ERROR_CANCELLED) {
892     g_error_free(err);
893     LOGE("IO error cancelled");
894     return;
895   }
896
897   auto* ptr = static_cast<std::weak_ptr<FdBroker>*>(user_data);
898   auto broker = ptr->lock();
899   if (broker == nullptr) {
900     LOGE("broker is nullptr");
901     return;
902   }
903
904   std::lock_guard<std::recursive_mutex> lock(broker->GetMutex());
905   if (broker->cancellable_ == nullptr) {
906     LOGE("Invalid context. Fdbroker(%p)", broker.get());
907     return;
908   }
909
910   IEventWatcher* watcher = broker->watcher_;
911
912   if (err) {
913     // LCOV_EXCL_START
914     watcher->OnPortDisconnected(broker->watch_appid_, broker->watch_port_name_,
915         true);
916     g_error_free(err);
917     if (broker->cancellable_) {
918       LOGW("Cancel the send request");
919       g_cancellable_cancel(broker->cancellable_);
920       g_object_unref(broker->cancellable_);
921       broker->cancellable_ = nullptr;
922     }
923     return;
924     // LCOV_EXCL_STOP
925   }
926
927   if (reply == nullptr) {
928     LOGW("Null reply");  // LCOV_EXCL_LINE
929     return;  // LCOV_EXCL_LINE
930   }
931
932   GVariant* reply_body = g_dbus_message_get_body(reply);
933   if (reply_body == nullptr) {
934     // LCOV_EXCL_START
935     LOGE("g_dbus_message_get_body() is failed");
936     watcher->OnPortDisconnected(broker->watch_appid_, broker->watch_port_name_);
937     g_object_unref(reply);
938     return;
939     // LCOV_EXCL_STOP
940   }
941
942   int ret;
943   g_variant_get(reply_body, "(i)", &ret);
944   g_object_unref(reply);
945   if (ret != 0) {
946     LOGE("Access Denied[sender_appid : %s]", broker->watch_appid_.c_str());
947     watcher->OnPortRejected(broker->watch_appid_,
948         RPC_PORT_ERROR_PERMISSION_DENIED);
949     return;
950   }
951
952   watcher->OnPortConnected(broker->watch_appid_, broker->watch_port_name_);
953   LOGD("[Reply : %d]", ret);
954 }
955
956 gboolean FdBroker::OnDbusNameTimeout(gpointer user_data) {
957   auto* ptr = static_cast<std::weak_ptr<FdBroker>*>(user_data);
958   auto broker = ptr->lock();
959   if (broker == nullptr) {
960     LOGE("broker is nullptr");
961     return G_SOURCE_REMOVE;
962   }
963
964   std::lock_guard<std::recursive_mutex> lock(broker->GetMutex());
965   if (broker->conn_data_ == nullptr) {
966     LOGE("Invalid context. FdBroker(%p)", broker.get());
967     return G_SOURCE_REMOVE;
968   }
969
970   DestroyWeakPtr(broker->conn_data_);
971   broker->conn_data_ = nullptr;
972   broker->Cancel();
973   auto* watcher = broker->watcher_;
974   watcher->OnPortRejected(broker->watch_appid_, RPC_PORT_ERROR_IO_ERROR);
975
976   return G_SOURCE_REMOVE;
977 }
978
979 std::shared_ptr<FdBroker> FdBroker::GetSharedPtr() {
980   return shared_from_this();
981 }
982
983 gpointer FdBroker::CreateWeakPtr() {
984   auto* ptr = new (std::nothrow) std::weak_ptr<FdBroker>(GetSharedPtr());
985   return static_cast<gpointer>(ptr);
986 }
987
988 void FdBroker::DestroyWeakPtr(gpointer data) {
989   auto* ptr = static_cast<std::weak_ptr<FdBroker>*>(data);
990   delete ptr;
991 }
992
993 void FdBroker::SetConnTimer() {
994   if (conn_data_) {
995     LOGW("Already exists");
996     return;
997   }
998
999   conn_data_ = CreateWeakPtr();
1000   if (conn_data_ == nullptr)
1001     LOGE("Out of memory");
1002
1003   g_timeout_add(10 * 1000, OnDbusNameTimeout, conn_data_);
1004 }
1005
1006 void FdBroker::UnsetConnTimer() {
1007   if (conn_data_ == nullptr)
1008     return;
1009
1010   GSource* source = g_main_context_find_source_by_user_data(nullptr,
1011       conn_data_);
1012   if (source && !g_source_is_destroyed(source))
1013     g_source_destroy(source);
1014
1015   DestroyWeakPtr(conn_data_);
1016   conn_data_ = nullptr;
1017 }
1018
1019 std::recursive_mutex& FdBroker::GetMutex() const {
1020   return mutex_;
1021 }
1022
1023 }  // namespace internal
1024 }  // namespace rpc_port