d6f770b6bba2e15cc7f8269c661d3e38277ff374
[platform/framework/web/crosswalk-tizen.git] / src / common / dbus_server.cc
1 /*
2  * Copyright (c) 2015 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 "common/dbus_server.h"
18
19 #include "common/logger.h"
20
21 namespace wrt {
22
23 namespace {
24
25 static void OnMethodCall(GDBusConnection* connection,
26                          const gchar* /*sender*/,
27                          const gchar* /*object_path*/,
28                          const gchar* interface_name,
29                          const gchar* method_name,
30                          GVariant* parameters,
31                          GDBusMethodInvocation* invocation,
32                          gpointer user_data) {
33   DBusServer* self = reinterpret_cast<DBusServer*>(user_data);
34   if (!self) {
35     LOGGER(ERROR) << "DBusServer is NULL.";
36     return;
37   }
38   auto callback = self->GetMethodCallback(interface_name);
39   if (callback) {
40     callback(connection, method_name, parameters, invocation);
41   }
42 }
43
44 static GVariant* OnGetProperty(GDBusConnection* connection,
45                                const gchar* /*sender*/,
46                                const gchar* /*object_path*/,
47                                const gchar* interface_name,
48                                const gchar* property_name,
49                                GError** /*error*/,
50                                gpointer user_data) {
51   DBusServer* self = reinterpret_cast<DBusServer*>(user_data);
52   if (!self) {
53     LOGGER(ERROR) << "DBusServer is NULL.";
54     return NULL;
55   }
56
57   auto callback =
58       self->GetPropertyGetter(interface_name);
59
60   GVariant* ret = NULL;
61   if (callback) {
62     ret = callback(connection, property_name);
63   }
64
65   return ret;
66 }
67
68 static gboolean OnSetProperty(GDBusConnection* connection,
69                               const gchar* /*sender*/,
70                               const gchar* /*object_path*/,
71                               const gchar* interface_name,
72                               const gchar* property_name,
73                               GVariant* value,
74                               GError** /*error*/,
75                               gpointer user_data) {
76   DBusServer* self = reinterpret_cast<DBusServer*>(user_data);
77   if (!self) {
78     LOGGER(ERROR) << "DBusServer is NULL.";
79     return FALSE;
80   }
81
82   auto callback =
83       self->GetPropertySetter(interface_name);
84
85   gboolean ret = FALSE;
86   if (callback) {
87     if (callback(connection, property_name, value)) {
88       ret = TRUE;
89     }
90   }
91
92   return ret;
93 }
94
95 static const GDBusInterfaceVTable kInterfaceVTable = {
96   OnMethodCall,
97   OnGetProperty,
98   OnSetProperty
99 };
100
101 static void OnClosedConnection(GDBusConnection* connection,
102                                gboolean /*remote_peer_vanished*/,
103                                GError* /*error*/,
104                                gpointer user_data) {
105   DBusServer* self = reinterpret_cast<DBusServer*>(user_data);
106   if (self) {
107     auto callback = self->GetDisconnectedCallback();
108     if (callback) {
109       callback(connection);
110     }
111   }
112
113   g_signal_handlers_disconnect_by_func(connection,
114                                        (gpointer)OnClosedConnection,
115                                        user_data);
116   g_object_unref(connection);
117 }
118
119 static gboolean OnClientRequest(GDBusServer* /*dbus_server*/,
120                                 GDBusConnection* connection,
121                                 gpointer user_data) {
122   GError* err = NULL;
123   DBusServer* self = reinterpret_cast<DBusServer*>(user_data);
124
125   g_signal_connect(connection, "closed",
126                    G_CALLBACK(OnClosedConnection), self);
127
128   if (self) {
129     // Check Peer Credentials
130     DBusServer::PeerCredentialsCallback callback =
131         self->GetPeerCredentialsCallback();
132     if (callback && !callback(
133         g_dbus_connection_get_peer_credentials(connection))) {
134       LOGGER(WARN) << "Invalid peer credentials.";
135       g_dbus_connection_close_sync(connection, NULL, NULL);
136     }
137
138     GDBusNodeInfo* node_info = self->GetIntrospectionNodeInfo();
139     if (!node_info) {
140       LOGGER(ERROR) << "Introspection is not set.";
141       return TRUE;
142     }
143
144     // TODO(wy80.choi): register multiple interfaces
145     g_object_ref(connection);
146     guint reg_id = g_dbus_connection_register_object(
147                           connection,
148                           "/",
149                           node_info->interfaces[0],
150                           &kInterfaceVTable,
151                           self,
152                           NULL,
153                           &err);
154     if (reg_id == 0) {
155       LOGGER(ERROR) << "Failed to register object : " << err->message;
156       g_error_free(err);
157     }
158   }
159   return TRUE;
160 }
161
162 }  // namespace
163
164 DBusServer::DBusServer()
165     : server_(NULL),
166       node_info_(NULL) {
167 }
168
169 DBusServer::~DBusServer() {
170   if (node_info_) {
171     g_dbus_node_info_unref(node_info_);
172   }
173
174   if (server_) {
175     g_object_unref(server_);
176   }
177
178   if (!address_path_.empty()) {
179     unlink(address_path_.c_str());
180   }
181 }
182
183 void DBusServer::Start(const std::string& name) {
184   GError* err = NULL;
185
186   address_path_.clear();
187   address_path_.append(g_get_user_runtime_dir());
188   address_path_.append("/.");
189   address_path_.append(name);
190   // unlink existing bus address
191   unlink(address_path_.c_str());
192
193   std::string address("unix:path=");
194   address.append(address_path_);
195
196   // create new bus socket
197   // TODO(wy80.choi): bus socket (Address) should be removed gracefully
198   // when application is terminated.
199   gchar* guid = g_dbus_generate_guid();
200   server_ = g_dbus_server_new_sync(
201                   address.c_str(), G_DBUS_SERVER_FLAGS_NONE,
202                   guid, NULL, NULL, &err);
203   g_free(guid);
204   if (!server_) {
205     LOGGER(ERROR) << "Failed to create dbus server : " << err->message;
206     g_error_free(err);
207     return;
208   }
209
210   // start server
211   g_signal_connect(server_, "new-connection",
212                    G_CALLBACK(OnClientRequest), this);
213
214   g_dbus_server_start(server_);
215 }
216
217 std::string DBusServer::GetClientAddress() const {
218   return std::string(g_dbus_server_get_client_address(server_));
219 }
220
221 void DBusServer::SetIntrospectionXML(const std::string& xml) {
222   GError* err = NULL;
223   node_info_ = g_dbus_node_info_new_for_xml(xml.c_str(), &err);
224   if (!node_info_) {
225     LOGGER(ERROR) << "Failed to create node info from introspection xml : "
226                   << err->message;
227     g_error_free(err);
228   }
229 }
230
231 void DBusServer::SendSignal(GDBusConnection* connection,
232                             const std::string& iface,
233                             const std::string& signal_name,
234                             GVariant* parameters) {
235   GError* err = NULL;
236   gboolean ret = g_dbus_connection_emit_signal(
237       connection, NULL, "/",
238       iface.c_str(), signal_name.c_str(),
239       parameters, &err);
240   if (!ret) {
241     LOGGER(ERROR) << "Failed to emit signal : '"
242                   << iface << '.' << signal_name << "'";
243     g_error_free(err);
244   }
245 }
246
247 void DBusServer::SetDisconnectedCallback(DisconnectedCallback func) {
248   disconnected_callback_ = func;
249 }
250
251 void DBusServer::SetPeerCredentialsCallback(PeerCredentialsCallback func) {
252   peer_credentials_callback_ = func;
253 }
254
255 void DBusServer::SetMethodCallback(
256     const std::string& iface, MethodCallback func) {
257   method_callbacks_[iface] = func;
258 }
259
260 void DBusServer::SetPropertyGetter(
261     const std::string& iface, PropertyGetter func) {
262   property_getters_[iface] = func;
263 }
264
265 void DBusServer::SetPropertySetter(
266     const std::string& iface, PropertySetter func) {
267   property_setters_[iface] = func;
268 }
269
270 DBusServer::DisconnectedCallback
271 DBusServer::GetDisconnectedCallback() const {
272   return disconnected_callback_;
273 }
274
275 DBusServer::PeerCredentialsCallback
276 DBusServer::GetPeerCredentialsCallback() const {
277   return peer_credentials_callback_;
278 }
279
280 DBusServer::MethodCallback
281 DBusServer::GetMethodCallback(const std::string& iface) {
282   return method_callbacks_[iface];
283 }
284
285 DBusServer::PropertySetter
286 DBusServer::GetPropertySetter(const std::string& iface) {
287   return property_setters_[iface];
288 }
289
290 DBusServer::PropertyGetter
291 DBusServer::GetPropertyGetter(const std::string& iface) {
292   return property_getters_[iface];
293 }
294
295 }  // namespace wrt