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