1 /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 */ 5 6 #include <dbus/dbus.h> 7 #include <errno.h> 8 #include <poll.h> 9 #include <stdint.h> 10 #include <stdlib.h> 11 #include <syslog.h> 12 #include <sys/select.h> 13 #include <unistd.h> 14 15 #include "cras_system_state.h" 16 #include "cras_tm.h" 17 18 static void dbus_watch_callback(void *arg) 19 { 20 DBusWatch *watch = (DBusWatch *)arg; 21 int r, flags; 22 struct pollfd pollfd; 23 24 pollfd.fd = dbus_watch_get_unix_fd(watch); 25 pollfd.events = POLLIN | POLLOUT; 26 27 r = poll(&pollfd, 1, 0); 28 if (r <= 0) 29 return; 30 31 flags = 0; 32 if (pollfd.revents & POLLIN) 33 flags |= DBUS_WATCH_READABLE; 34 if (pollfd.revents & POLLOUT) 35 flags |= DBUS_WATCH_WRITABLE; 36 37 if (!dbus_watch_handle(watch, flags)) 38 syslog(LOG_WARNING, "Failed to handle D-Bus watch."); 39 } 40 41 static dbus_bool_t dbus_watch_add(DBusWatch *watch, void *data) 42 { 43 int r; 44 unsigned int flags = dbus_watch_get_flags(watch); 45 46 /* Only select the read watch. 47 * TODO(hychao): select on write watch when we have a use case. 48 */ 49 if ((flags & DBUS_WATCH_READABLE) && dbus_watch_get_enabled(watch)) { 50 r = cras_system_add_select_fd(dbus_watch_get_unix_fd(watch), 51 dbus_watch_callback, 52 watch); 53 if (r != 0) 54 return FALSE; 55 } 56 57 return TRUE; 58 } 59 60 static void dbus_watch_remove(DBusWatch *watch, void *data) 61 { 62 unsigned int flags = dbus_watch_get_flags(watch); 63 64 /* Only select the read watch. */ 65 if (flags & DBUS_WATCH_READABLE) 66 cras_system_rm_select_fd(dbus_watch_get_unix_fd(watch)); 67 } 68 69 static void dbus_watch_toggled(DBusWatch *watch, void *data) 70 { 71 if (dbus_watch_get_enabled(watch)) { 72 dbus_watch_add(watch, NULL); 73 } else { 74 dbus_watch_remove(watch, NULL); 75 } 76 } 77 78 79 static void dbus_timeout_callback(struct cras_timer *t, void *data) 80 { 81 struct cras_tm *tm = cras_system_state_get_tm(); 82 struct DBusTimeout *timeout = data; 83 84 85 /* Timer is automatically removed after it fires. Add a new one so this 86 * fires until it is removed by dbus. */ 87 t = cras_tm_create_timer(tm, 88 dbus_timeout_get_interval(timeout), 89 dbus_timeout_callback, timeout); 90 dbus_timeout_set_data(timeout, t, NULL); 91 92 if (!dbus_timeout_handle(timeout)) 93 syslog(LOG_WARNING, "Failed to handle D-Bus timeout."); 94 } 95 96 static dbus_bool_t dbus_timeout_add(DBusTimeout *timeout, void *arg) 97 { 98 struct cras_tm *tm = cras_system_state_get_tm(); 99 struct cras_timer *t = dbus_timeout_get_data(timeout); 100 101 if (t) { 102 dbus_timeout_set_data(timeout, NULL, NULL); 103 cras_tm_cancel_timer(tm, t); 104 } 105 106 if (dbus_timeout_get_enabled(timeout)) { 107 t = cras_tm_create_timer(tm, 108 dbus_timeout_get_interval(timeout), 109 dbus_timeout_callback, timeout); 110 dbus_timeout_set_data(timeout, t, NULL); 111 if (t == NULL) 112 return FALSE; 113 114 } 115 116 return TRUE; 117 } 118 119 static void dbus_timeout_remove(DBusTimeout *timeout, void *arg) 120 { 121 struct cras_tm *tm = cras_system_state_get_tm(); 122 struct cras_timer *t = dbus_timeout_get_data(timeout); 123 124 if (t) { 125 dbus_timeout_set_data(timeout, NULL, NULL); 126 cras_tm_cancel_timer(tm, t); 127 } 128 } 129 130 static void dbus_timeout_toggled(DBusTimeout *timeout, void *arg) 131 { 132 if (dbus_timeout_get_enabled(timeout)) 133 dbus_timeout_add(timeout, NULL); 134 else 135 dbus_timeout_remove(timeout, NULL); 136 } 137 138 DBusConnection *cras_dbus_connect_system_bus() 139 { 140 DBusError dbus_error; 141 DBusConnection *conn; 142 int rc; 143 144 dbus_error_init(&dbus_error); 145 146 conn = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_error); 147 if (!conn) { 148 syslog(LOG_WARNING, "Failed to connect to D-Bus: %s", 149 dbus_error.message); 150 dbus_error_free(&dbus_error); 151 return NULL; 152 } 153 154 /* Request a name on the bus. */ 155 rc = dbus_bus_request_name(conn, "org.chromium.cras", 0, &dbus_error); 156 if (dbus_error_is_set(&dbus_error)) { 157 syslog(LOG_ERR, "Requesting dbus name %s", dbus_error.message); 158 dbus_error_free(&dbus_error); 159 } 160 if (rc != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) 161 syslog(LOG_ERR, "Not primary owner of dbus name."); 162 163 if (!dbus_connection_set_watch_functions(conn, 164 dbus_watch_add, 165 dbus_watch_remove, 166 dbus_watch_toggled, 167 NULL, 168 NULL)) 169 goto error; 170 if (!dbus_connection_set_timeout_functions(conn, 171 dbus_timeout_add, 172 dbus_timeout_remove, 173 dbus_timeout_toggled, 174 NULL, 175 NULL)) 176 goto error; 177 178 return conn; 179 180 error: 181 syslog(LOG_WARNING, "Failed to setup D-Bus connection."); 182 dbus_connection_unref(conn); 183 return NULL; 184 } 185 186 void cras_dbus_dispatch(DBusConnection *conn) 187 { 188 while (dbus_connection_dispatch(conn) 189 == DBUS_DISPATCH_DATA_REMAINS) 190 ; 191 } 192 193 void cras_dbus_disconnect_system_bus(DBusConnection *conn) 194 { 195 dbus_connection_unref(conn); 196 } 197