[WRTjs] Refactor popup
[platform/framework/web/chromium-efl.git] / wrt / src / browser / wrt_ipc.cc
1 // Copyright 2020 Samsung Electronics. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "wrt/src/browser/wrt_ipc.h"
6
7 #include "wrt/src/base/dlog_util.h"
8
9 namespace wrt {
10
11 #define WRT_DBUS_NAME "org.tizen.wrt"
12 #define WRT_DBUS_PATH "/org/tizen/wrt"
13
14 InterProcessCommunication::Message::Message(DBusConnection* connection,
15                                             DBusMessage* message,
16                                             InterProcessCommunication* ipc)
17     : connection_(connection), message_(message), ipc_(ipc) {}
18
19 const char* InterProcessCommunication::Message::Sender() const {
20   return dbus_message_get_sender(message_);
21 }
22
23 void InterProcessCommunication::Message::CloseDBusConnection() const {
24   LOG(INFO) << "Listen() will be ended and close dbus connection.";
25   if (ipc_) {
26     ipc_->will_close_ = true;
27   }
28 }
29
30 void InterProcessCommunication::Message::Reply(const char* argument) const {
31   if (!connection_) {
32     LOG(ERROR) << "connection_ is not valid";
33     return;
34   }
35   DBusMessage* reply = dbus_message_new_method_return(message_);
36   dbus_message_append_args(reply, DBUS_TYPE_STRING, &argument, DBUS_TYPE_INVALID);
37   dbus_connection_send(connection_, reply, nullptr);
38   dbus_message_unref(reply);
39 }
40
41 InterProcessCommunication::InterProcessCommunication(bool is_daemon) {
42   DBusError error;
43   dbus_error_init(&error);
44
45   connection_ = dbus_bus_get_private(DBUS_BUS_SESSION, &error);
46   if (!connection_) {
47     LOG(ERROR) << "DBus connection error : " << error.message;
48     dbus_error_free(&error);
49   }
50
51   if (is_daemon) {
52     int result = dbus_bus_request_name(connection_, WRT_DBUS_NAME, DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
53     if (dbus_error_is_set(&error)) {
54       LOG(ERROR) << "Fail to request name : " << error.message;
55       dbus_error_free(&error);
56       return;
57     }
58     if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
59       LOG(ERROR) << "Fail to become owner";
60       return;
61     }
62   }
63 }
64
65 void InterProcessCommunication::CloseDbus() {
66   if (connection_) {
67     if (!message_handlers_.empty())
68       dbus_connection_remove_filter(connection_, OnMessage, this);
69     dbus_connection_close(connection_);
70     dbus_connection_unref(connection_);
71     connection_ = nullptr;
72   }
73 }
74
75 InterProcessCommunication::~InterProcessCommunication() {
76   CloseDbus();
77 }
78
79 // static
80 DBusHandlerResult InterProcessCommunication::OnMessage(DBusConnection* connection, DBusMessage* message, void* user_data) {
81   int type = dbus_message_get_type(message);
82   if (type != DBUS_MESSAGE_TYPE_METHOD_CALL) {
83      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
84   }
85
86   std::string interface = dbus_message_get_interface(message);
87   if (interface != WRT_DBUS_NAME) {
88      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
89   }
90
91   std::string member = dbus_message_get_member(message);
92   auto* ipc = reinterpret_cast<InterProcessCommunication*>(user_data);
93   if (!ipc || !ipc->connection_) {
94     LOG(ERROR) << "ipc or connection_ is not valid";
95     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
96   }
97   auto iterator = ipc->message_handlers_.find(member);
98   if (iterator != ipc->message_handlers_.end()) {
99     DBusError error;
100     dbus_error_init(&error);
101     char* argument = nullptr;
102     if (!dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &argument, DBUS_TYPE_INVALID)) {
103       LOG(ERROR) << "dbus message reply is not valid";
104       dbus_error_free(&error);
105     }
106
107     auto& handler = iterator->second;
108     handler(member.c_str(), argument, Message(ipc->connection_, message, ipc));
109   }
110
111   return DBUS_HANDLER_RESULT_HANDLED;
112 }
113
114 void InterProcessCommunication::AddMessageHandler(const char* type, MessageHandler handler) {
115   if (message_handlers_.empty()) {
116     if (!dbus_connection_add_filter(connection_, OnMessage, this, nullptr)) {
117       LOG(ERROR) << "Fail to add message handler";
118       return;
119     }
120   }
121   message_handlers_[type] = handler;
122 }
123
124 void InterProcessCommunication::SetExitOnDisconnect(bool exit_on_disconnect) {
125   dbus_connection_set_exit_on_disconnect(connection_, exit_on_disconnect);
126 }
127
128 void InterProcessCommunication::Listen() {
129   while (dbus_connection_read_write_dispatch(connection_, 500)) {
130     if (will_close_)
131       break;
132   }
133   CloseDbus();
134 }
135
136 DBusMessage* InterProcessCommunication::InternalSendMessage(const char* receiver, const char* type, const char* argument, bool need_reply) {
137   if (!connection_) {
138     LOG(ERROR) << "connection_ is not valid";
139     return nullptr;
140   }
141   DBusMessage* message = dbus_message_new_method_call(receiver, WRT_DBUS_PATH, WRT_DBUS_NAME, type);
142   if (!message) {
143     LOG(ERROR) << "Fail to create dbus message";
144     return nullptr;
145   }
146
147   if (!dbus_message_append_args(message, DBUS_TYPE_STRING, &argument, DBUS_TYPE_INVALID)) {
148     LOG(ERROR) << "Fail to append dbus message argument";
149     return nullptr;
150   }
151
152   DBusError error;
153   dbus_error_init(&error);
154   if (need_reply) {
155     DBusMessage* reply = dbus_connection_send_with_reply_and_block(connection_, message, -1, &error);
156     dbus_message_unref(message);
157     if (!reply) {
158       LOG(ERROR) << "Fail to receive dbus message reply";
159       dbus_error_free(&error);
160       return nullptr;
161     }
162     message = reply;
163   } else {
164     dbus_connection_send(connection_, message, nullptr);
165     dbus_connection_flush(connection_);
166   }
167   if (dbus_error_is_set(&error)) {
168     LOG(ERROR) << "Fail to send message : " << error.message;
169     dbus_error_free(&error);
170     return nullptr;
171   }
172
173   return message;
174 }
175
176 bool InterProcessCommunication::SendMessage(const char* type, const char* argument) {
177   return SendMessage(WRT_DBUS_NAME, type, argument);
178 }
179
180 bool InterProcessCommunication::SendMessage(const char* receiver, const char* type, const char* argument) {
181   DBusMessage* message = InternalSendMessage(receiver, type, argument, false);
182   if (!message) {
183     return false;
184   }
185   dbus_message_unref(message);
186   return true;
187 }
188
189 bool InterProcessCommunication::SendMessageAndWaitReply(const char* type, const char* argument, std::string& reply_argument) {
190   return SendMessageAndWaitReply(WRT_DBUS_NAME, type, argument, reply_argument);
191 }
192
193 bool InterProcessCommunication::SendMessageAndWaitReply(const char* receiver, const char* type, const char* argument, std::string& reply_argument) {
194   DBusMessage* reply = InternalSendMessage(receiver, type, argument, true);
195   if (!reply) {
196     return false;
197   }
198
199   if (dbus_message_get_type(reply) != DBUS_MESSAGE_TYPE_ERROR) {
200     DBusError error;
201     dbus_error_init(&error);
202     char* buffer = nullptr;
203     if (!dbus_message_get_args(reply, &error, DBUS_TYPE_STRING, &buffer, DBUS_TYPE_INVALID)) {
204       LOG(ERROR) << "dbus message reply is not valid";
205       dbus_error_free(&error);
206       return false;
207     }
208     reply_argument = buffer;
209   }
210   dbus_message_unref(reply);
211   return true;
212 }
213
214 bool InterProcessCommunication::HasDbusOwner(const char* dbus_name) {
215   if (!connection_) {
216     LOG(ERROR) << "connection_ is not valid";
217     return false;
218   }
219
220   DBusError err;
221   dbus_error_init(&err);
222
223   bool exist = dbus_bus_name_has_owner(connection_, dbus_name, &err);
224   if (dbus_error_is_set(&err)) {
225     LOG(ERROR) << "dbus error : " << err.message;
226     dbus_error_free(&err);
227     return false;
228   }
229   return exist;
230 }
231
232 }  // namespace wrt