1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4 * Copyright (C) 2012 Intel Corporation.
6 * Contact: Amarnath Valluri <amarnath.valluri@linux.intel.com>
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.
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.
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
26 #include <glib/gstdio.h>
29 #include "common/log.h"
30 #include "dbus-server.h"
31 #include "dbus-manager.h"
34 G_DEFINE_TYPE (MsgPortDbusServer, msgport_dbus_server, G_TYPE_OBJECT)
37 #define MSGPORT_DBUS_SERVER_GET_PRIV(obj) \
38 G_TYPE_INSTANCE_GET_PRIVATE ((obj), MSGPORT_TYPE_DBUS_SERVER, MsgPortDbusServerPrivate)
48 static GParamSpec *properties[N_PROPERTIES];
50 struct _MsgPortDbusServerPrivate
52 GDBusServer *bus_server;
54 GHashTable *dbus_managers; /* {GDBusConnection,MsgPortDbusManager} */
57 static void _on_connection_closed (GDBusConnection *connection,
58 gboolean remote_peer_vanished,
63 _set_property (GObject *object,
65 const GValue *value, GParamSpec *pspec)
67 MsgPortDbusServer *self = MSGPORT_DBUS_SERVER (object);
69 switch (property_id) {
71 self->priv->address = g_value_dup_string (value);
75 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
80 _get_property (GObject *object,
85 MsgPortDbusServer *self = MSGPORT_DBUS_SERVER (object);
87 switch (property_id) {
89 g_value_set_string (value, g_dbus_server_get_client_address (
90 self->priv->bus_server));
94 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
99 _clear_watchers(gpointer connection, gpointer auth_service, gpointer userdata)
101 g_signal_handlers_disconnect_by_func (connection, _on_connection_closed, userdata);
105 _dispose (GObject *object)
107 MsgPortDbusServer *self = MSGPORT_DBUS_SERVER (object);
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;
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;
122 G_OBJECT_CLASS (msgport_dbus_server_parent_class)->dispose (object);
126 _finalize (GObject *object)
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;
134 g_free (self->priv->address);
135 self->priv->address = NULL;
138 G_OBJECT_CLASS (msgport_dbus_server_parent_class)->finalize (object);
142 msgport_dbus_server_class_init (MsgPortDbusServerClass *klass)
144 GObjectClass* object_class = G_OBJECT_CLASS (klass);
146 g_type_class_add_private (object_class, sizeof (MsgPortDbusServerPrivate));
148 object_class->get_property = _get_property;
149 object_class->set_property = _set_property;
150 object_class->dispose = _dispose;
151 object_class->finalize = _finalize;
153 properties[PROP_ADDRESS] = g_param_spec_string ("address",
155 "Server socket address",
158 G_PARAM_CONSTRUCT_ONLY |
159 G_PARAM_STATIC_STRINGS);
161 g_object_class_install_properties (object_class, N_PROPERTIES, properties);
165 msgport_dbus_server_init (MsgPortDbusServer *self)
167 self->priv = MSGPORT_DBUS_SERVER_GET_PRIV(self);
168 self->priv->bus_server = NULL;
169 self->priv->address = NULL;
171 self->priv->dbus_managers = g_hash_table_new_full (
172 g_direct_hash, g_direct_equal, NULL, g_object_unref);
176 msgport_dbus_server_get_address (MsgPortDbusServer *server)
178 g_return_val_if_fail (server || MSGPORT_IS_DBUS_SERVER (server), NULL);
180 return g_dbus_server_get_client_address (server->priv->bus_server);
184 _on_connection_closed (GDBusConnection *connection,
185 gboolean remote_peer_vanished,
189 MsgPortDbusServer *server = MSGPORT_DBUS_SERVER (user_data);
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");
195 g_hash_table_remove (server->priv->dbus_managers, connection);
199 msgport_dbus_server_start_dbus_manager_for_connection (
200 MsgPortDbusServer *server,
201 GDBusConnection *connection)
203 MsgPortDbusManager *dbus_manager = NULL;
204 GError *error = NULL;
206 DBG("Starting dbus manager on connection %p", connection);
208 dbus_manager = msgport_dbus_manager_new (
209 connection, server, &error);
211 WARN ("Could not create dbus manager on conneciton %p: %s", connection, error->message);
212 g_error_free (error);
216 g_hash_table_insert (server->priv->dbus_managers, connection, dbus_manager);
218 g_signal_connect (connection, "closed", G_CALLBACK(_on_connection_closed), server);
222 _on_client_request (GDBusServer *dbus_server, GDBusConnection *connection, gpointer userdata)
224 MsgPortDbusServer *server = MSGPORT_DBUS_SERVER(userdata);
226 g_return_val_if_fail (server && MSGPORT_IS_DBUS_SERVER (server), FALSE);
228 msgport_dbus_server_start_dbus_manager_for_connection (server, connection);
233 MsgPortDbusServer * msgport_dbus_server_new_with_address (const gchar *address)
237 const gchar *file_path = NULL;
238 MsgPortDbusServer *server = MSGPORT_DBUS_SERVER (
239 g_object_new (MSGPORT_TYPE_DBUS_SERVER, "address", address, NULL));
241 if (!server) return NULL;
243 if (g_str_has_prefix(address, "unix:path=")) {
244 file_path = g_strstr_len (address, -1, "unix:path=") + 10;
246 if (g_file_test(file_path, G_FILE_TEST_EXISTS)) {
247 g_unlink (file_path);
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));
258 guid = g_dbus_generate_guid ();
260 server->priv->bus_server = g_dbus_server_new_sync (server->priv->address,
261 G_DBUS_SERVER_FLAGS_NONE, guid, NULL, NULL, &err);
265 if (!server->priv->bus_server) {
266 ERR ("failed to start server at address '%s':%s", server->priv->address,
270 g_object_unref (server);
275 g_signal_connect (server->priv->bus_server, "new-connection", G_CALLBACK(_on_client_request), server);
277 g_dbus_server_start (server->priv->bus_server);
280 g_chmod (file_path, S_IRUSR | S_IWUSR);
286 msgport_dbus_server_new () {
287 MsgPortDbusServer *server = NULL;
288 gchar *address = NULL;
290 if (g_getenv("MESSAGEPORT_BUS_ADDRESS")) {
291 address = g_strdup (g_getenv ("MESSAGEPORT_BUS_ADDRESS"));
294 # ifdef MESSAGEPORT_BUS_ADDRESS
295 address = g_strdup_printf (MESSAGEPORT_BUS_ADDRESS);
299 address = g_strdup_printf ("unix:path=%s/.message-port", g_get_user_runtime_dir());
301 server = msgport_dbus_server_new_with_address (address);
308 _find_dbus_manager_by_app_id (
309 GDBusConnection *key,
310 MsgPortDbusManager *value,
311 const gchar *app_id_to_find)
313 return !g_strcmp0 (msgport_dbus_manager_get_app_id (value), app_id_to_find);
317 msgport_dbus_server_get_dbus_manager_by_app_id (MsgPortDbusServer *server, const gchar *app_id)
319 g_return_val_if_fail (server && MSGPORT_IS_DBUS_SERVER (server), NULL);
321 return (MsgPortDbusManager *)g_hash_table_find (server->priv->dbus_managers,
322 (GHRFunc)_find_dbus_manager_by_app_id, (gpointer)app_id);