missing copyright section added, and few typo fixes
[platform/core/appfw/message-port-dbus.git] / daemon / dbus-server.c
1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4  * Copyright (C) 2013 Intel Corporation.
5  *
6  * Contact: Amarnath Valluri <amarnath.valluri@linux.intel.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  */
23
24 #include <errno.h>
25 #include <string.h>
26 #include <gio/gio.h>
27 #include <glib/gstdio.h>
28
29 #include "config.h"
30 #include "common/log.h"
31 #include "dbus-server.h"
32 #include "dbus-manager.h"
33
34
35 G_DEFINE_TYPE (MsgPortDbusServer, msgport_dbus_server, G_TYPE_OBJECT)
36
37
38 #define MSGPORT_DBUS_SERVER_GET_PRIV(obj) \
39     G_TYPE_INSTANCE_GET_PRIVATE ((obj), MSGPORT_TYPE_DBUS_SERVER, MsgPortDbusServerPrivate)
40
41 enum
42 {
43     PROP_0,
44
45     PROP_ADDRESS,
46     N_PROPERTIES
47 };
48
49 static GParamSpec *properties[N_PROPERTIES];
50
51 struct _MsgPortDbusServerPrivate
52 {
53     GDBusServer    *bus_server;
54     gchar          *address;
55     GHashTable     *dbus_managers; /* {GDBusConnection,MsgPortDbusManager} */
56 };
57
58 static void _on_connection_closed (GDBusConnection *connection,
59                        gboolean         remote_peer_vanished,
60                        GError          *error,
61                        gpointer         user_data);
62
63 static void
64 _set_property (GObject *object,
65         guint property_id,
66         const GValue *value, GParamSpec *pspec)
67 {
68     MsgPortDbusServer *self = MSGPORT_DBUS_SERVER (object);
69
70     switch (property_id) {
71         case PROP_ADDRESS: {
72             self->priv->address = g_value_dup_string (value);
73             break;
74         }
75         default:
76             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
77     }
78 }
79
80 static void
81 _get_property (GObject *object,
82         guint property_id,
83         GValue *value, 
84         GParamSpec *pspec)
85 {
86     MsgPortDbusServer *self = MSGPORT_DBUS_SERVER (object);
87
88     switch (property_id) {
89         case PROP_ADDRESS: {
90             g_value_set_string (value, g_dbus_server_get_client_address (
91                     self->priv->bus_server));
92             break;
93         }
94         default:
95             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
96     }
97 }
98
99 static void
100 _clear_watchers(gpointer connection, gpointer auth_service, gpointer userdata)
101 {
102     g_signal_handlers_disconnect_by_func (connection, _on_connection_closed, userdata);
103 }
104
105 static void
106 _dispose (GObject *object)
107 {
108     MsgPortDbusServer *self = MSGPORT_DBUS_SERVER (object);
109
110     if (self->priv->bus_server) {
111         if (g_dbus_server_is_active (self->priv->bus_server))
112             g_dbus_server_stop (self->priv->bus_server);
113         g_object_unref (self->priv->bus_server);
114         self->priv->bus_server = NULL;
115     }
116
117     if (self->priv->dbus_managers) {
118         g_hash_table_foreach (self->priv->dbus_managers, _clear_watchers, self);
119         g_hash_table_unref (self->priv->dbus_managers);
120         self->priv->dbus_managers = NULL;
121     }
122
123     G_OBJECT_CLASS (msgport_dbus_server_parent_class)->dispose (object);
124 }
125
126 static void
127 _finalize (GObject *object)
128 {
129     MsgPortDbusServer *self = MSGPORT_DBUS_SERVER (object);
130     if (self->priv->address && g_str_has_prefix (self->priv->address, "unix:path=")) {
131         const gchar *path = g_strstr_len(self->priv->address, -1, "unix:path=") + 10;
132         if (path) { 
133             g_unlink (path);
134         }
135         g_free (self->priv->address);
136         self->priv->address = NULL;
137     }
138
139     G_OBJECT_CLASS (msgport_dbus_server_parent_class)->finalize (object);
140 }
141
142 static void
143 msgport_dbus_server_class_init (MsgPortDbusServerClass *klass)
144 {
145     GObjectClass* object_class = G_OBJECT_CLASS (klass);
146
147     g_type_class_add_private (object_class, sizeof (MsgPortDbusServerPrivate));
148
149     object_class->get_property = _get_property;
150     object_class->set_property = _set_property;
151     object_class->dispose = _dispose;
152     object_class->finalize = _finalize;
153
154     properties[PROP_ADDRESS] = g_param_spec_string ("address",
155                                                     "server address",
156                                                     "Server socket address",
157                                                     NULL,
158                                                     G_PARAM_READWRITE | 
159                                                     G_PARAM_CONSTRUCT_ONLY | 
160                                                     G_PARAM_STATIC_STRINGS);
161
162     g_object_class_install_properties (object_class, N_PROPERTIES, properties);
163 }
164
165 static void
166 msgport_dbus_server_init (MsgPortDbusServer *self)
167 {
168     self->priv = MSGPORT_DBUS_SERVER_GET_PRIV(self);
169     self->priv->bus_server = NULL;
170     self->priv->address = NULL;
171
172     self->priv->dbus_managers = g_hash_table_new_full (
173         g_direct_hash, g_direct_equal, NULL, g_object_unref);
174 }
175
176 const gchar *
177 msgport_dbus_server_get_address (MsgPortDbusServer *server)
178 {
179     g_return_val_if_fail (server || MSGPORT_IS_DBUS_SERVER (server), NULL);
180
181     return g_dbus_server_get_client_address (server->priv->bus_server);
182 }
183
184 static void
185 _on_connection_closed (GDBusConnection *connection,
186                        gboolean         remote_peer_vanished,
187                        GError          *error,
188                        gpointer         user_data)
189 {
190     MsgPortDbusServer *server = MSGPORT_DBUS_SERVER (user_data);
191
192     g_signal_handlers_disconnect_by_func (connection, _on_connection_closed, user_data);
193     DBG("dbus connection(%p) closed (peer vanished : %d) : %s",
194             connection, remote_peer_vanished, error ? error->message : "unknwon reason");
195
196     g_hash_table_remove (server->priv->dbus_managers, connection);
197 }
198
199 void
200 msgport_dbus_server_start_dbus_manager_for_connection (
201     MsgPortDbusServer *server,
202     GDBusConnection *connection)
203 {
204     MsgPortDbusManager *dbus_manager = NULL;
205     GError *error = NULL;
206
207     DBG("Starting dbus manager on connection %p", connection);
208
209     dbus_manager = msgport_dbus_manager_new (
210         connection, server, &error);
211     if (!dbus_manager) {
212         WARN ("Could not create dbus manager on conneciton %p: %s", connection, error->message);
213         g_error_free (error);
214         return;
215     }
216
217     g_hash_table_insert (server->priv->dbus_managers, connection, dbus_manager);
218
219     g_signal_connect (connection, "closed", G_CALLBACK(_on_connection_closed), server);
220 }
221
222 static gboolean
223 _on_client_request (GDBusServer *dbus_server, GDBusConnection *connection, gpointer userdata)
224 {
225     MsgPortDbusServer *server = MSGPORT_DBUS_SERVER(userdata);
226     
227     g_return_val_if_fail (server && MSGPORT_IS_DBUS_SERVER (server), FALSE);
228
229     msgport_dbus_server_start_dbus_manager_for_connection (server, connection);
230
231     return TRUE;
232 }
233
234 MsgPortDbusServer * msgport_dbus_server_new_with_address (const gchar *address)
235 {
236     GError *err = NULL;
237     gchar *guid = 0;
238     const gchar *file_path = NULL;
239     MsgPortDbusServer *server = MSGPORT_DBUS_SERVER (
240         g_object_new (MSGPORT_TYPE_DBUS_SERVER, "address", address, NULL));
241
242     if (!server) return NULL;
243
244     if (g_str_has_prefix(address, "unix:path=")) {
245         file_path = g_strstr_len (address, -1, "unix:path=") + 10;
246
247         if (g_file_test(file_path, G_FILE_TEST_EXISTS)) {
248             g_unlink (file_path);
249         }
250         else {
251             gchar *base_path = g_path_get_dirname (file_path);
252             if (g_mkdir_with_parents (base_path, S_IRUSR | S_IWUSR | S_IXUSR) == -1) {
253                 WARN ("Could not create '%s', error: %s", base_path, strerror(errno));
254             }
255             g_free (base_path);
256         }
257     }
258
259     guid = g_dbus_generate_guid ();
260
261     server->priv->bus_server = g_dbus_server_new_sync (server->priv->address,
262             G_DBUS_SERVER_FLAGS_NONE, guid, NULL, NULL, &err);
263
264     g_free (guid);
265
266     if (!server->priv->bus_server) {
267         ERR ("failed to start server at address '%s':%s", server->priv->address,
268                  err->message);
269         g_error_free (err);
270         
271         g_object_unref (server);
272      
273         return NULL;
274     }
275
276     g_signal_connect (server->priv->bus_server, "new-connection", G_CALLBACK(_on_client_request), server);
277
278     g_dbus_server_start (server->priv->bus_server);
279
280     if (file_path)
281         g_chmod (file_path, S_IRUSR | S_IWUSR);
282
283     return server;
284 }
285
286 MsgPortDbusServer *
287 msgport_dbus_server_new () {
288         MsgPortDbusServer *server = NULL;
289         gchar *address = NULL;
290
291     if (g_getenv("MESSAGEPORT_BUS_ADDRESS")) {
292         address = g_strdup (g_getenv ("MESSAGEPORT_BUS_ADDRESS"));
293     }
294     else {
295 #       ifdef MESSAGEPORT_BUS_ADDRESS
296            address = g_strdup_printf (MESSAGEPORT_BUS_ADDRESS);
297 #       endif
298     }
299     if (!address)
300         address = g_strdup_printf ("unix:path=%s/.message-port", g_get_user_runtime_dir());
301
302     server = msgport_dbus_server_new_with_address (address);
303     g_free (address);
304
305     return server ;
306 }
307
308 static gboolean
309 _find_dbus_manager_by_app_id (
310     GDBusConnection *key,
311     MsgPortDbusManager *value,
312     const gchar *app_id_to_find)
313 {
314     return !g_strcmp0 (msgport_dbus_manager_get_app_id (value), app_id_to_find);
315 }
316
317 MsgPortDbusManager *
318 msgport_dbus_server_get_dbus_manager_by_app_id (MsgPortDbusServer *server, const gchar *app_id)
319 {
320     g_return_val_if_fail (server && MSGPORT_IS_DBUS_SERVER (server), NULL);
321
322     return (MsgPortDbusManager *)g_hash_table_find (server->priv->dbus_managers,
323             (GHRFunc)_find_dbus_manager_by_app_id, (gpointer)app_id);
324 }
325