Change SmackExecLabel to SmackProcessLabel
[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  * This file is part of message-port.
5  *
6  * Copyright (C) 2013 Intel Corporation.
7  *
8  * Contact: Amarnath Valluri <amarnath.valluri@linux.intel.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23  * 02110-1301 USA
24  */
25
26 #include <errno.h>
27 #include <string.h>
28 #include <gio/gio.h>
29 #include <glib/gstdio.h>
30
31 #include "config.h"
32 #include "common/log.h"
33 #include "dbus-server.h"
34 #include "dbus-manager.h"
35 #include "utils.h"
36
37
38 G_DEFINE_TYPE (MsgPortDbusServer, msgport_dbus_server, G_TYPE_OBJECT)
39
40
41 #define MSGPORT_DBUS_SERVER_GET_PRIV(obj) \
42     G_TYPE_INSTANCE_GET_PRIVATE ((obj), MSGPORT_TYPE_DBUS_SERVER, MsgPortDbusServerPrivate)
43
44 enum
45 {
46     PROP_0,
47
48     PROP_ADDRESS,
49     N_PROPERTIES
50 };
51
52 static GParamSpec *properties[N_PROPERTIES];
53
54 struct _MsgPortDbusServerPrivate
55 {
56     GDBusServer    *bus_server;
57     gchar          *address;
58     GHashTable     *dbus_managers; /* {GDBusConnection,MsgPortDbusManager} */
59 };
60
61 static void _on_connection_closed (GDBusConnection *connection,
62                        gboolean         remote_peer_vanished,
63                        GError          *error,
64                        gpointer         user_data);
65
66 static void
67 _set_property (GObject *object,
68         guint property_id,
69         const GValue *value, GParamSpec *pspec)
70 {
71     MsgPortDbusServer *self = MSGPORT_DBUS_SERVER (object);
72
73     switch (property_id) {
74         case PROP_ADDRESS: {
75             self->priv->address = g_value_dup_string (value);
76             break;
77         }
78         default:
79             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
80     }
81 }
82
83 static void
84 _get_property (GObject *object,
85         guint property_id,
86         GValue *value, 
87         GParamSpec *pspec)
88 {
89     MsgPortDbusServer *self = MSGPORT_DBUS_SERVER (object);
90
91     switch (property_id) {
92         case PROP_ADDRESS: {
93             g_value_set_string (value, g_dbus_server_get_client_address (
94                     self->priv->bus_server));
95             break;
96         }
97         default:
98             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
99     }
100 }
101
102 static void
103 _clear_watchers(gpointer connection, gpointer auth_service, gpointer userdata)
104 {
105     g_signal_handlers_disconnect_by_func (connection, _on_connection_closed, userdata);
106 }
107
108 static void
109 _dispose (GObject *object)
110 {
111     MsgPortDbusServer *self = MSGPORT_DBUS_SERVER (object);
112
113     if (self->priv->bus_server) {
114         if (g_dbus_server_is_active (self->priv->bus_server))
115             g_dbus_server_stop (self->priv->bus_server);
116         g_clear_object (&self->priv->bus_server);
117     }
118
119     if (self->priv->dbus_managers) {
120         g_hash_table_foreach (self->priv->dbus_managers, _clear_watchers, self);
121         g_hash_table_unref (self->priv->dbus_managers);
122         self->priv->dbus_managers = NULL;
123     }
124
125     G_OBJECT_CLASS (msgport_dbus_server_parent_class)->dispose (object);
126 }
127
128 static void
129 _finalize (GObject *object)
130 {
131     MsgPortDbusServer *self = MSGPORT_DBUS_SERVER (object);
132     if (self->priv->address)  {
133         g_unlink (self->priv->address);
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 static gboolean
234 _start_bus_server (MsgPortDbusServer *server)
235 {
236     GError *err = NULL;
237     gchar *guid = 0;
238         gchar *address = NULL;
239     const gchar *file_path = NULL;
240
241     if (!server) return FALSE;
242
243     if (g_getenv("MESSAGEPORT_BUS_ADDRESS")) {
244         address = g_strdup (g_getenv ("MESSAGEPORT_BUS_ADDRESS"));
245     }
246     else {
247 #       ifdef MESSAGEPORT_BUS_ADDRESS
248            address = g_strdup_printf (MESSAGEPORT_BUS_ADDRESS);
249 #       endif
250     }
251     if (!address)
252         address = g_strdup_printf ("unix:path=%s/.message-port", g_get_user_runtime_dir());
253
254     if (g_str_has_prefix(address, "unix:path=")) {
255         file_path = g_strstr_len (address, -1, "unix:path=") + 10;
256
257         if (g_file_test(file_path, G_FILE_TEST_EXISTS)) {
258             g_unlink (file_path);
259         }
260         else {
261             gchar *base_path = g_path_get_dirname (file_path);
262             if (g_mkdir_with_parents (base_path, S_IRUSR | S_IWUSR | S_IXUSR) == -1) {
263                 WARN ("Could not create '%s', error: %s", base_path, strerror(errno));
264             }
265             g_free (base_path);
266         }
267     }
268
269     guid = g_dbus_generate_guid ();
270
271     server->priv->bus_server = g_dbus_server_new_sync (address,
272             G_DBUS_SERVER_FLAGS_NONE, guid, NULL, NULL, &err);
273
274     g_free (guid);
275
276     if (!server->priv->bus_server) {
277         ERR ("failed to start server at address '%s':%s", server->priv->address,
278                  err->message);
279         g_error_free (err);
280  
281         return FALSE;
282     }
283
284     DBG ("Dbus Server started at '%s'", address);
285
286     server->priv->address = g_strdup (file_path);
287
288     g_signal_connect (server->priv->bus_server, "new-connection", G_CALLBACK(_on_client_request), server);
289
290     g_dbus_server_start (server->priv->bus_server);
291
292     if (file_path)
293         g_chmod (file_path, S_IRUSR | S_IWUSR);
294
295     g_free (address);
296
297     return TRUE;
298 }
299
300 MsgPortDbusServer *
301 msgport_dbus_server_new () {
302     MsgPortDbusServer *server = NULL;
303     
304     server = MSGPORT_DBUS_SERVER (g_object_new (MSGPORT_TYPE_DBUS_SERVER, NULL));
305
306    _start_bus_server (server);
307
308     return server;
309 }
310
311 static gboolean
312 _find_dbus_manager_by_app_id (
313     GDBusConnection *key,
314     MsgPortDbusManager *value,
315     const gchar *app_id_to_find)
316 {
317     return !g_strcmp0 (msgport_dbus_manager_get_app_id (value), app_id_to_find);
318 }
319
320 MsgPortDbusManager *
321 msgport_dbus_server_get_dbus_manager_by_app_id (MsgPortDbusServer *server, const gchar *app_id)
322 {
323     g_return_val_if_fail (server && MSGPORT_IS_DBUS_SERVER (server), NULL);
324
325     return (MsgPortDbusManager *)g_hash_table_find (server->priv->dbus_managers,
326             (GHRFunc)_find_dbus_manager_by_app_id, (gpointer)app_id);
327 }