Home | History | Annotate | Download | only in gdbus
      1 /*
      2  *
      3  *  D-Bus helper library
      4  *
      5  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel (at) holtmann.org>
      6  *
      7  *
      8  *  This program is free software; you can redistribute it and/or modify
      9  *  it under the terms of the GNU General Public License as published by
     10  *  the Free Software Foundation; either version 2 of the License, or
     11  *  (at your option) any later version.
     12  *
     13  *  This program is distributed in the hope that it will be useful,
     14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  *  GNU General Public License for more details.
     17  *
     18  *  You should have received a copy of the GNU General Public License
     19  *  along with this program; if not, write to the Free Software
     20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     21  *
     22  */
     23 
     24 #ifdef HAVE_CONFIG_H
     25 #include <config.h>
     26 #endif
     27 
     28 #include <glib.h>
     29 #include <dbus/dbus.h>
     30 
     31 #ifdef NEED_DBUS_WATCH_GET_UNIX_FD
     32 #define dbus_watch_get_unix_fd dbus_watch_get_fd
     33 #endif
     34 
     35 #include "gdbus.h"
     36 
     37 #define DISPATCH_TIMEOUT  0
     38 
     39 #define info(fmt...)
     40 #define error(fmt...)
     41 #define debug(fmt...)
     42 
     43 struct timeout_handler {
     44 	guint id;
     45 	DBusTimeout *timeout;
     46 };
     47 
     48 struct watch_info {
     49 	guint id;
     50 	DBusWatch *watch;
     51 	DBusConnection *conn;
     52 };
     53 
     54 struct disconnect_data {
     55 	GDBusWatchFunction function;
     56 	void *user_data;
     57 };
     58 
     59 static gboolean disconnected_signal(DBusConnection *conn,
     60 						DBusMessage *msg, void *data)
     61 {
     62 	struct disconnect_data *dc_data = data;
     63 
     64 	error("Got disconnected from the system message bus");
     65 
     66 	dc_data->function(conn, dc_data->user_data);
     67 
     68 	dbus_connection_unref(conn);
     69 
     70 	return TRUE;
     71 }
     72 
     73 static gboolean message_dispatch(void *data)
     74 {
     75 	DBusConnection *conn = data;
     76 
     77 	dbus_connection_ref(conn);
     78 
     79 	/* Dispatch messages */
     80 	while (dbus_connection_dispatch(conn) == DBUS_DISPATCH_DATA_REMAINS);
     81 
     82 	dbus_connection_unref(conn);
     83 
     84 	return FALSE;
     85 }
     86 
     87 static inline void queue_dispatch(DBusConnection *conn,
     88 						DBusDispatchStatus status)
     89 {
     90 	if (status == DBUS_DISPATCH_DATA_REMAINS)
     91 		g_timeout_add(DISPATCH_TIMEOUT, message_dispatch, conn);
     92 }
     93 
     94 static gboolean watch_func(GIOChannel *chan, GIOCondition cond, gpointer data)
     95 {
     96 	struct watch_info *info = data;
     97 	unsigned int flags = 0;
     98 
     99 	dbus_connection_ref(info->conn);
    100 
    101 	if (cond & G_IO_IN)  flags |= DBUS_WATCH_READABLE;
    102 	if (cond & G_IO_OUT) flags |= DBUS_WATCH_WRITABLE;
    103 	if (cond & G_IO_HUP) flags |= DBUS_WATCH_HANGUP;
    104 	if (cond & G_IO_ERR) flags |= DBUS_WATCH_ERROR;
    105 
    106 	dbus_watch_handle(info->watch, flags);
    107 
    108 	dbus_connection_unref(info->conn);
    109 
    110 	return TRUE;
    111 }
    112 
    113 static void watch_info_free(void *data)
    114 {
    115 	struct watch_info *info = data;
    116 
    117 	if (info->id > 0) {
    118 		g_source_remove(info->id);
    119 		info->id = 0;
    120 	}
    121 
    122 	dbus_connection_unref(info->conn);
    123 
    124 	g_free(info);
    125 }
    126 
    127 static dbus_bool_t add_watch(DBusWatch *watch, void *data)
    128 {
    129 	DBusConnection *conn = data;
    130 	GIOCondition cond = G_IO_HUP | G_IO_ERR;
    131 	GIOChannel *chan;
    132 	struct watch_info *info;
    133 	unsigned int flags;
    134 	int fd;
    135 
    136 	if (!dbus_watch_get_enabled(watch))
    137 		return TRUE;
    138 
    139 	info = g_new0(struct watch_info, 1);
    140 
    141 	fd = dbus_watch_get_unix_fd(watch);
    142 	chan = g_io_channel_unix_new(fd);
    143 
    144 	info->watch = watch;
    145 	info->conn = dbus_connection_ref(conn);
    146 
    147 	dbus_watch_set_data(watch, info, watch_info_free);
    148 
    149 	flags = dbus_watch_get_flags(watch);
    150 
    151 	if (flags & DBUS_WATCH_READABLE) cond |= G_IO_IN;
    152 	if (flags & DBUS_WATCH_WRITABLE) cond |= G_IO_OUT;
    153 
    154 	info->id = g_io_add_watch(chan, cond, watch_func, info);
    155 
    156 	g_io_channel_unref(chan);
    157 
    158 	return TRUE;
    159 }
    160 
    161 static void remove_watch(DBusWatch *watch, void *data)
    162 {
    163 	if (dbus_watch_get_enabled(watch))
    164 		return;
    165 
    166 	/* will trigger watch_info_free() */
    167 	dbus_watch_set_data(watch, NULL, NULL);
    168 }
    169 
    170 static void watch_toggled(DBusWatch *watch, void *data)
    171 {
    172 	/* Because we just exit on OOM, enable/disable is
    173 	 * no different from add/remove */
    174 	if (dbus_watch_get_enabled(watch))
    175 		add_watch(watch, data);
    176 	else
    177 		remove_watch(watch, data);
    178 }
    179 
    180 static gboolean timeout_handler_dispatch(gpointer data)
    181 {
    182 	struct timeout_handler *handler = data;
    183 
    184 	handler->id = 0;
    185 
    186 	/* if not enabled should not be polled by the main loop */
    187 	if (!dbus_timeout_get_enabled(handler->timeout))
    188 		return FALSE;
    189 
    190 	dbus_timeout_handle(handler->timeout);
    191 
    192 	return FALSE;
    193 }
    194 
    195 static void timeout_handler_free(void *data)
    196 {
    197 	struct timeout_handler *handler = data;
    198 
    199 	if (handler->id > 0) {
    200 		g_source_remove(handler->id);
    201 		handler->id = 0;
    202 	}
    203 
    204 	g_free(handler);
    205 }
    206 
    207 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
    208 {
    209 	int interval = dbus_timeout_get_interval(timeout);
    210 	struct timeout_handler *handler;
    211 
    212 	if (!dbus_timeout_get_enabled(timeout))
    213 		return TRUE;
    214 
    215 	handler = g_new0(struct timeout_handler, 1);
    216 
    217 	handler->timeout = timeout;
    218 
    219 	dbus_timeout_set_data(timeout, handler, timeout_handler_free);
    220 
    221 	handler->id = g_timeout_add(interval, timeout_handler_dispatch,
    222 								handler);
    223 
    224 	return TRUE;
    225 }
    226 
    227 static void remove_timeout(DBusTimeout *timeout, void *data)
    228 {
    229 	if (dbus_timeout_get_enabled(timeout))
    230 		return;
    231 
    232 	/* will trigger timeout_handler_free() */
    233 	dbus_timeout_set_data(timeout, NULL, NULL);
    234 }
    235 
    236 static void timeout_toggled(DBusTimeout *timeout, void *data)
    237 {
    238 	if (dbus_timeout_get_enabled(timeout))
    239 		add_timeout(timeout, data);
    240 	else
    241 		remove_timeout(timeout, data);
    242 }
    243 
    244 static void dispatch_status(DBusConnection *conn,
    245 					DBusDispatchStatus status, void *data)
    246 {
    247 	if (!dbus_connection_get_is_connected(conn))
    248 		return;
    249 
    250 	queue_dispatch(conn, status);
    251 }
    252 
    253 static inline void setup_dbus_with_main_loop(DBusConnection *conn)
    254 {
    255 	dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
    256 						watch_toggled, conn, NULL);
    257 
    258 	dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout,
    259 						timeout_toggled, NULL, NULL);
    260 
    261 	dbus_connection_set_dispatch_status_function(conn, dispatch_status,
    262 								NULL, NULL);
    263 }
    264 
    265 static gboolean setup_bus(DBusConnection *conn, const char *name,
    266 						DBusError *error)
    267 {
    268 	gboolean result;
    269 	DBusDispatchStatus status;
    270 
    271 	if (name != NULL) {
    272 		result = g_dbus_request_name(conn, name, error);
    273 
    274 		if (error != NULL) {
    275 			if (dbus_error_is_set(error) == TRUE)
    276 				return FALSE;
    277 		}
    278 
    279 		if (result == FALSE)
    280 			return FALSE;
    281 	}
    282 
    283 	setup_dbus_with_main_loop(conn);
    284 
    285 	status = dbus_connection_get_dispatch_status(conn);
    286 	queue_dispatch(conn, status);
    287 
    288 	return TRUE;
    289 }
    290 
    291 DBusConnection *g_dbus_setup_bus(DBusBusType type, const char *name,
    292 							DBusError *error)
    293 {
    294 	DBusConnection *conn;
    295 
    296 	conn = dbus_bus_get(type, error);
    297 
    298 	if (error != NULL) {
    299 		if (dbus_error_is_set(error) == TRUE)
    300 			return NULL;
    301 	}
    302 
    303 	if (conn == NULL)
    304 		return NULL;
    305 
    306 	if (setup_bus(conn, name, error) == FALSE) {
    307 		dbus_connection_unref(conn);
    308 		return NULL;
    309 	}
    310 
    311 	return conn;
    312 }
    313 
    314 DBusConnection *g_dbus_setup_private(DBusBusType type, const char *name,
    315 							DBusError *error)
    316 {
    317 	DBusConnection *conn;
    318 
    319 	conn = dbus_bus_get_private(type, error);
    320 
    321 	if (error != NULL) {
    322 		if (dbus_error_is_set(error) == TRUE)
    323 			return NULL;
    324 	}
    325 
    326 	if (conn == NULL)
    327 		return NULL;
    328 
    329 	if (setup_bus(conn, name, error) == FALSE) {
    330 		dbus_connection_unref(conn);
    331 		return NULL;
    332 	}
    333 
    334 	return conn;
    335 }
    336 
    337 gboolean g_dbus_request_name(DBusConnection *connection, const char *name,
    338 							DBusError *error)
    339 {
    340 	int result;
    341 
    342 	result = dbus_bus_request_name(connection, name,
    343 					DBUS_NAME_FLAG_DO_NOT_QUEUE, error);
    344 
    345 	if (error != NULL) {
    346 		if (dbus_error_is_set(error) == TRUE)
    347 			return FALSE;
    348 	}
    349 
    350 	if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
    351 		if (error != NULL)
    352 			dbus_set_error(error, name, "Name already in use");
    353 
    354 		return FALSE;
    355 	}
    356 
    357 	return TRUE;
    358 }
    359 
    360 gboolean g_dbus_set_disconnect_function(DBusConnection *connection,
    361 				GDBusWatchFunction function,
    362 				void *user_data, DBusFreeFunction destroy)
    363 {
    364 	struct disconnect_data *dc_data;
    365 
    366 	dc_data = g_new0(struct disconnect_data, 1);
    367 
    368 	dc_data->function = function;
    369 	dc_data->user_data = user_data;
    370 
    371 	dbus_connection_set_exit_on_disconnect(connection, FALSE);
    372 
    373 	if (g_dbus_add_signal_watch(connection, NULL, NULL,
    374 				DBUS_INTERFACE_LOCAL, "Disconnected",
    375 				disconnected_signal, dc_data, g_free) == 0) {
    376 		error("Failed to add watch for D-Bus Disconnected signal");
    377 		g_free(dc_data);
    378 		return FALSE;
    379 	}
    380 
    381 	return TRUE;
    382 }
    383