Home | History | Annotate | Download | only in gdbus
      1 /*
      2  *
      3  *  D-Bus helper library
      4  *
      5  *  Copyright (C) 2004-2011  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 	DBusDispatchStatus status;
     99 
    100 	dbus_connection_ref(info->conn);
    101 
    102 	if (cond & G_IO_IN)  flags |= DBUS_WATCH_READABLE;
    103 	if (cond & G_IO_OUT) flags |= DBUS_WATCH_WRITABLE;
    104 	if (cond & G_IO_HUP) flags |= DBUS_WATCH_HANGUP;
    105 	if (cond & G_IO_ERR) flags |= DBUS_WATCH_ERROR;
    106 
    107 	dbus_watch_handle(info->watch, flags);
    108 
    109 	status = dbus_connection_get_dispatch_status(info->conn);
    110 	queue_dispatch(info->conn, status);
    111 
    112 	dbus_connection_unref(info->conn);
    113 
    114 	return TRUE;
    115 }
    116 
    117 static void watch_info_free(void *data)
    118 {
    119 	struct watch_info *info = data;
    120 
    121 	if (info->id > 0) {
    122 		g_source_remove(info->id);
    123 		info->id = 0;
    124 	}
    125 
    126 	dbus_connection_unref(info->conn);
    127 
    128 	g_free(info);
    129 }
    130 
    131 static dbus_bool_t add_watch(DBusWatch *watch, void *data)
    132 {
    133 	DBusConnection *conn = data;
    134 	GIOCondition cond = G_IO_HUP | G_IO_ERR;
    135 	GIOChannel *chan;
    136 	struct watch_info *info;
    137 	unsigned int flags;
    138 	int fd;
    139 
    140 	if (!dbus_watch_get_enabled(watch))
    141 		return TRUE;
    142 
    143 	info = g_new0(struct watch_info, 1);
    144 
    145 	fd = dbus_watch_get_unix_fd(watch);
    146 	chan = g_io_channel_unix_new(fd);
    147 
    148 	info->watch = watch;
    149 	info->conn = dbus_connection_ref(conn);
    150 
    151 	dbus_watch_set_data(watch, info, watch_info_free);
    152 
    153 	flags = dbus_watch_get_flags(watch);
    154 
    155 	if (flags & DBUS_WATCH_READABLE) cond |= G_IO_IN;
    156 	if (flags & DBUS_WATCH_WRITABLE) cond |= G_IO_OUT;
    157 
    158 	info->id = g_io_add_watch(chan, cond, watch_func, info);
    159 
    160 	g_io_channel_unref(chan);
    161 
    162 	return TRUE;
    163 }
    164 
    165 static void remove_watch(DBusWatch *watch, void *data)
    166 {
    167 	if (dbus_watch_get_enabled(watch))
    168 		return;
    169 
    170 	/* will trigger watch_info_free() */
    171 	dbus_watch_set_data(watch, NULL, NULL);
    172 }
    173 
    174 static void watch_toggled(DBusWatch *watch, void *data)
    175 {
    176 	/* Because we just exit on OOM, enable/disable is
    177 	 * no different from add/remove */
    178 	if (dbus_watch_get_enabled(watch))
    179 		add_watch(watch, data);
    180 	else
    181 		remove_watch(watch, data);
    182 }
    183 
    184 static gboolean timeout_handler_dispatch(gpointer data)
    185 {
    186 	struct timeout_handler *handler = data;
    187 
    188 	handler->id = 0;
    189 
    190 	/* if not enabled should not be polled by the main loop */
    191 	if (!dbus_timeout_get_enabled(handler->timeout))
    192 		return FALSE;
    193 
    194 	dbus_timeout_handle(handler->timeout);
    195 
    196 	return FALSE;
    197 }
    198 
    199 static void timeout_handler_free(void *data)
    200 {
    201 	struct timeout_handler *handler = data;
    202 
    203 	if (handler->id > 0) {
    204 		g_source_remove(handler->id);
    205 		handler->id = 0;
    206 	}
    207 
    208 	g_free(handler);
    209 }
    210 
    211 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
    212 {
    213 	int interval = dbus_timeout_get_interval(timeout);
    214 	struct timeout_handler *handler;
    215 
    216 	if (!dbus_timeout_get_enabled(timeout))
    217 		return TRUE;
    218 
    219 	handler = g_new0(struct timeout_handler, 1);
    220 
    221 	handler->timeout = timeout;
    222 
    223 	dbus_timeout_set_data(timeout, handler, timeout_handler_free);
    224 
    225 	handler->id = g_timeout_add(interval, timeout_handler_dispatch,
    226 								handler);
    227 
    228 	return TRUE;
    229 }
    230 
    231 static void remove_timeout(DBusTimeout *timeout, void *data)
    232 {
    233 	/* will trigger timeout_handler_free() */
    234 	dbus_timeout_set_data(timeout, NULL, NULL);
    235 }
    236 
    237 static void timeout_toggled(DBusTimeout *timeout, void *data)
    238 {
    239 	if (dbus_timeout_get_enabled(timeout))
    240 		add_timeout(timeout, data);
    241 	else
    242 		remove_timeout(timeout, data);
    243 }
    244 
    245 static void dispatch_status(DBusConnection *conn,
    246 					DBusDispatchStatus status, void *data)
    247 {
    248 	if (!dbus_connection_get_is_connected(conn))
    249 		return;
    250 
    251 	queue_dispatch(conn, status);
    252 }
    253 
    254 static inline void setup_dbus_with_main_loop(DBusConnection *conn)
    255 {
    256 	dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
    257 						watch_toggled, conn, NULL);
    258 
    259 	dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout,
    260 						timeout_toggled, NULL, NULL);
    261 
    262 	dbus_connection_set_dispatch_status_function(conn, dispatch_status,
    263 								NULL, NULL);
    264 }
    265 
    266 static gboolean setup_bus(DBusConnection *conn, const char *name,
    267 						DBusError *error)
    268 {
    269 	gboolean result;
    270 	DBusDispatchStatus status;
    271 
    272 	if (name != NULL) {
    273 		result = g_dbus_request_name(conn, name, error);
    274 
    275 		if (error != NULL) {
    276 			if (dbus_error_is_set(error) == TRUE)
    277 				return FALSE;
    278 		}
    279 
    280 		if (result == FALSE)
    281 			return FALSE;
    282 	}
    283 
    284 	setup_dbus_with_main_loop(conn);
    285 
    286 	status = dbus_connection_get_dispatch_status(conn);
    287 	queue_dispatch(conn, status);
    288 
    289 	return TRUE;
    290 }
    291 
    292 DBusConnection *g_dbus_setup_bus(DBusBusType type, const char *name,
    293 							DBusError *error)
    294 {
    295 	DBusConnection *conn;
    296 
    297 	conn = dbus_bus_get(type, error);
    298 
    299 	if (error != NULL) {
    300 		if (dbus_error_is_set(error) == TRUE)
    301 			return NULL;
    302 	}
    303 
    304 	if (conn == NULL)
    305 		return NULL;
    306 
    307 	if (setup_bus(conn, name, error) == FALSE) {
    308 		dbus_connection_unref(conn);
    309 		return NULL;
    310 	}
    311 
    312 	return conn;
    313 }
    314 
    315 DBusConnection *g_dbus_setup_private(DBusBusType type, const char *name,
    316 							DBusError *error)
    317 {
    318 	DBusConnection *conn;
    319 
    320 	conn = dbus_bus_get_private(type, error);
    321 
    322 	if (error != NULL) {
    323 		if (dbus_error_is_set(error) == TRUE)
    324 			return NULL;
    325 	}
    326 
    327 	if (conn == NULL)
    328 		return NULL;
    329 
    330 	if (setup_bus(conn, name, error) == FALSE) {
    331 		dbus_connection_unref(conn);
    332 		return NULL;
    333 	}
    334 
    335 	return conn;
    336 }
    337 
    338 gboolean g_dbus_request_name(DBusConnection *connection, const char *name,
    339 							DBusError *error)
    340 {
    341 	int result;
    342 
    343 	result = dbus_bus_request_name(connection, name,
    344 					DBUS_NAME_FLAG_DO_NOT_QUEUE, error);
    345 
    346 	if (error != NULL) {
    347 		if (dbus_error_is_set(error) == TRUE)
    348 			return FALSE;
    349 	}
    350 
    351 	if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
    352 		if (error != NULL)
    353 			dbus_set_error(error, name, "Name already in use");
    354 
    355 		return FALSE;
    356 	}
    357 
    358 	return TRUE;
    359 }
    360 
    361 gboolean g_dbus_set_disconnect_function(DBusConnection *connection,
    362 				GDBusWatchFunction function,
    363 				void *user_data, DBusFreeFunction destroy)
    364 {
    365 	struct disconnect_data *dc_data;
    366 
    367 	dc_data = g_new0(struct disconnect_data, 1);
    368 
    369 	dc_data->function = function;
    370 	dc_data->user_data = user_data;
    371 
    372 	dbus_connection_set_exit_on_disconnect(connection, FALSE);
    373 
    374 	if (g_dbus_add_signal_watch(connection, NULL, NULL,
    375 				DBUS_INTERFACE_LOCAL, "Disconnected",
    376 				disconnected_signal, dc_data, g_free) == 0) {
    377 		error("Failed to add watch for D-Bus Disconnected signal");
    378 		g_free(dc_data);
    379 		return FALSE;
    380 	}
    381 
    382 	return TRUE;
    383 }
    384