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