daemon: fixed issue in registring more than one ports by a client.
[profile/ivi/message-port.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) 2012 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 #include <errno.h>
24 #include <string.h>
25 #include <gio/gio.h>
26 #include <glib/gstdio.h>
27
28 #include "config.h"
29 #include "common/log.h"
30 #include "dbus-server.h"
31 #include "dbus-manager.h"
32
33
34 G_DEFINE_TYPE (MsgPortDbusServer, msgport_dbus_server, G_TYPE_OBJECT)
35
36
37 #define MSGPORT_DBUS_SERVER_GET_PRIV(obj) \
38     G_TYPE_INSTANCE_GET_PRIVATE ((obj), MSGPORT_TYPE_DBUS_SERVER, MsgPortDbusServerPrivate)
39
40 enum
41 {
42     PROP_0,
43
44     PROP_ADDRESS,
45     N_PROPERTIES
46 };
47
48 static GParamSpec *properties[N_PROPERTIES];
49
50 struct _MsgPortDbusServerPrivate
51 {
52     GDBusServer    *bus_server;
53     gchar          *address;
54     GHashTable     *dbus_managers; /* {GDBusConnection,MsgPortDbusManager} */
55 };
56
57 static void _on_connection_closed (GDBusConnection *connection,
58                        gboolean         remote_peer_vanished,
59                        GError          *error,
60                        gpointer         user_data);
61
62 static void
63 _set_property (GObject *object,
64         guint property_id,
65         const GValue *value, GParamSpec *pspec)
66 {
67     MsgPortDbusServer *self = MSGPORT_DBUS_SERVER (object);
68
69     switch (property_id) {
70         case PROP_ADDRESS: {
71             self->priv->address = g_value_dup_string (value);
72             break;
73         }
74         default:
75             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
76     }
77 }
78
79 static void
80 _get_property (GObject *object,
81         guint property_id,
82         GValue *value, 
83         GParamSpec *pspec)
84 {
85     MsgPortDbusServer *self = MSGPORT_DBUS_SERVER (object);
86
87     switch (property_id) {
88         case PROP_ADDRESS: {
89             g_value_set_string (value, g_dbus_server_get_client_address (
90                     self->priv->bus_server));
91             break;
92         }
93         default:
94             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
95     }
96 }
97
98 static void
99 _clear_watchers(gpointer connection, gpointer auth_service, gpointer userdata)
100 {
101     g_signal_handlers_disconnect_by_func (connection, _on_connection_closed, userdata);
102 }
103
104 static void
105 _dispose (GObject *object)
106 {
107     MsgPortDbusServer *self = MSGPORT_DBUS_SERVER (object);
108
109     if (self->priv->bus_server) {
110         if (g_dbus_server_is_active (self->priv->bus_server))
111             g_dbus_server_stop (self->priv->bus_server);
112         g_object_unref (self->priv->bus_server);
113         self->priv->bus_server = NULL;
114     }
115
116     if (self->priv->dbus_managers) {
117         g_hash_table_foreach (self->priv->dbus_managers, _clear_watchers, self);
118         g_hash_table_unref (self->priv->dbus_managers);
119         self->priv->dbus_managers = NULL;
120     }
121
122     G_OBJECT_CLASS (msgport_dbus_server_parent_class)->dispose (object);
123 }
124
125 static void
126 _finalize (GObject *object)
127 {
128     MsgPortDbusServer *self = MSGPORT_DBUS_SERVER (object);
129     if (self->priv->address && g_str_has_prefix (self->priv->address, "unix:path=")) {
130         const gchar *path = g_strstr_len(self->priv->address, -1, "unix:path=") + 10;
131         if (path) { 
132             g_unlink (path);
133         }
134         g_free (self->priv->address);
135         self->priv->address = NULL;
136     }
137
138     G_OBJECT_CLASS (msgport_dbus_server_parent_class)->finalize (object);
139 }
140
141 static void
142 msgport_dbus_server_class_init (MsgPortDbusServerClass *klass)
143 {
144     GObjectClass* object_class = G_OBJECT_CLASS (klass);
145
146     g_type_class_add_private (object_class, sizeof (MsgPortDbusServerPrivate));
147
148     object_class->get_property = _get_property;
149     object_class->set_property = _set_property;
150     object_class->dispose = _dispose;
151     object_class->finalize = _finalize;
152
153     properties[PROP_ADDRESS] = g_param_spec_string ("address",
154                                                     "server address",
155                                                     "Server socket address",
156                                                     NULL,
157                                                     G_PARAM_READWRITE | 
158                                                     G_PARAM_CONSTRUCT_ONLY | 
159                                                     G_PARAM_STATIC_STRINGS);
160
161     g_object_class_install_properties (object_class, N_PROPERTIES, properties);
162 }
163
164 static void
165 msgport_dbus_server_init (MsgPortDbusServer *self)
166 {
167     self->priv = MSGPORT_DBUS_SERVER_GET_PRIV(self);
168     self->priv->bus_server = NULL;
169     self->priv->address = NULL;
170
171     self->priv->dbus_managers = g_hash_table_new_full (
172         g_direct_hash, g_direct_equal, NULL, g_object_unref);
173 }
174
175 const gchar *
176 msgport_dbus_server_get_address (MsgPortDbusServer *server)
177 {
178     g_return_val_if_fail (server || MSGPORT_IS_DBUS_SERVER (server), NULL);
179
180     return g_dbus_server_get_client_address (server->priv->bus_server);
181 }
182
183 static void
184 _on_connection_closed (GDBusConnection *connection,
185                        gboolean         remote_peer_vanished,
186                        GError          *error,
187                        gpointer         user_data)
188 {
189     MsgPortDbusServer *server = MSGPORT_DBUS_SERVER (user_data);
190
191     g_signal_handlers_disconnect_by_func (connection, _on_connection_closed, user_data);
192     DBG("dbus connection(%p) closed (peer vanished : %d) : %s",
193             connection, remote_peer_vanished, error ? error->message : "unknwon reason");
194
195     g_hash_table_remove (server->priv->dbus_managers, connection);
196 }
197
198 void
199 msgport_dbus_server_start_dbus_manager_for_connection (
200     MsgPortDbusServer *server,
201     GDBusConnection *connection)
202 {
203     MsgPortDbusManager *dbus_manager = NULL;
204     GError *error = NULL;
205
206     DBG("Starting dbus manager on connection %p", connection);
207
208     dbus_manager = msgport_dbus_manager_new (
209         connection, server, &error);
210     if (!dbus_manager) {
211         WARN ("Could not create dbus manager on conneciton %p: %s", connection, error->message);
212         g_error_free (error);
213         return;
214     }
215
216     g_hash_table_insert (server->priv->dbus_managers, connection, dbus_manager);
217
218     g_signal_connect (connection, "closed", G_CALLBACK(_on_connection_closed), server);
219 }
220
221 static gboolean
222 _on_client_request (GDBusServer *dbus_server, GDBusConnection *connection, gpointer userdata)
223 {
224     MsgPortDbusServer *server = MSGPORT_DBUS_SERVER(userdata);
225     
226     g_return_val_if_fail (server && MSGPORT_IS_DBUS_SERVER (server), FALSE);
227
228     msgport_dbus_server_start_dbus_manager_for_connection (server, connection);
229
230     return TRUE;
231 }
232
233 MsgPortDbusServer * msgport_dbus_server_new_with_address (const gchar *address)
234 {
235     GError *err = NULL;
236     gchar *guid = 0;
237     const gchar *file_path = NULL;
238     MsgPortDbusServer *server = MSGPORT_DBUS_SERVER (
239         g_object_new (MSGPORT_TYPE_DBUS_SERVER, "address", address, NULL));
240
241     if (!server) return NULL;
242
243     if (g_str_has_prefix(address, "unix:path=")) {
244         file_path = g_strstr_len (address, -1, "unix:path=") + 10;
245
246         if (g_file_test(file_path, G_FILE_TEST_EXISTS)) {
247             g_unlink (file_path);
248         }
249         else {
250             gchar *base_path = g_path_get_dirname (file_path);
251             if (g_mkdir_with_parents (base_path, S_IRUSR | S_IWUSR | S_IXUSR) == -1) {
252                 WARN ("Could not create '%s', error: %s", base_path, strerror(errno));
253             }
254             g_free (base_path);
255         }
256     }
257
258     guid = g_dbus_generate_guid ();
259
260     server->priv->bus_server = g_dbus_server_new_sync (server->priv->address,
261             G_DBUS_SERVER_FLAGS_NONE, guid, NULL, NULL, &err);
262
263     g_free (guid);
264
265     if (!server->priv->bus_server) {
266         ERR ("failed to start server at address '%s':%s", server->priv->address,
267                  err->message);
268         g_error_free (err);
269         
270         g_object_unref (server);
271      
272         return NULL;
273     }
274
275     g_signal_connect (server->priv->bus_server, "new-connection", G_CALLBACK(_on_client_request), server);
276
277     g_dbus_server_start (server->priv->bus_server);
278
279     if (file_path)
280         g_chmod (file_path, S_IRUSR | S_IWUSR);
281
282     return server;
283 }
284
285 MsgPortDbusServer *
286 msgport_dbus_server_new () {
287         MsgPortDbusServer *server = NULL;
288         gchar *address = NULL;
289
290     if (g_getenv("MESSAGEPORT_BUS_ADDRESS")) {
291         address = g_strdup (g_getenv ("MESSAGEPORT_BUS_ADDRESS"));
292     }
293     else {
294 #       ifdef MESSAGEPORT_BUS_ADDRESS
295            address = g_strdup_printf (MESSAGEPORT_BUS_ADDRESS);
296 #       endif
297     }
298     if (!address)
299         address = g_strdup_printf ("unix:path=%s/.message-port", g_get_user_runtime_dir());
300
301     server = msgport_dbus_server_new_with_address (address);
302     g_free (address);
303
304     return server ;
305 }
306
307 static gboolean
308 _find_dbus_manager_by_app_id (
309     GDBusConnection *key,
310     MsgPortDbusManager *value,
311     const gchar *app_id_to_find)
312 {
313     return !g_strcmp0 (msgport_dbus_manager_get_app_id (value), app_id_to_find);
314 }
315
316 MsgPortDbusManager *
317 msgport_dbus_server_get_dbus_manager_by_app_id (MsgPortDbusServer *server, const gchar *app_id)
318 {
319     g_return_val_if_fail (server && MSGPORT_IS_DBUS_SERVER (server), NULL);
320
321     return (MsgPortDbusManager *)g_hash_table_find (server->priv->dbus_managers,
322             (GHRFunc)_find_dbus_manager_by_app_id, (gpointer)app_id);
323 }
324