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
dbus_watch_callback(void * arg,int revents)18 static void dbus_watch_callback(void *arg, int revents)
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
dbus_watch_add(DBusWatch * watch,void * data)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, watch,
52 POLLIN);
53 if (r != 0)
54 return FALSE;
55 }
56
57 return TRUE;
58 }
59
dbus_watch_remove(DBusWatch * watch,void * data)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
dbus_watch_toggled(DBusWatch * watch,void * data)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
dbus_timeout_callback(struct cras_timer * t,void * data)78 static void dbus_timeout_callback(struct cras_timer *t, void *data)
79 {
80 struct cras_tm *tm = cras_system_state_get_tm();
81 struct DBusTimeout *timeout = data;
82
83 /* Timer is automatically removed after it fires. Add a new one so this
84 * fires until it is removed by dbus. */
85 t = cras_tm_create_timer(tm, dbus_timeout_get_interval(timeout),
86 dbus_timeout_callback, timeout);
87 dbus_timeout_set_data(timeout, t, NULL);
88
89 if (!dbus_timeout_handle(timeout))
90 syslog(LOG_WARNING, "Failed to handle D-Bus timeout.");
91 }
92
dbus_timeout_add(DBusTimeout * timeout,void * arg)93 static dbus_bool_t dbus_timeout_add(DBusTimeout *timeout, void *arg)
94 {
95 struct cras_tm *tm = cras_system_state_get_tm();
96 struct cras_timer *t = dbus_timeout_get_data(timeout);
97
98 if (t) {
99 dbus_timeout_set_data(timeout, NULL, NULL);
100 cras_tm_cancel_timer(tm, t);
101 }
102
103 if (dbus_timeout_get_enabled(timeout)) {
104 t = cras_tm_create_timer(tm, dbus_timeout_get_interval(timeout),
105 dbus_timeout_callback, timeout);
106 dbus_timeout_set_data(timeout, t, NULL);
107 if (t == NULL)
108 return FALSE;
109 }
110
111 return TRUE;
112 }
113
dbus_timeout_remove(DBusTimeout * timeout,void * arg)114 static void dbus_timeout_remove(DBusTimeout *timeout, void *arg)
115 {
116 struct cras_tm *tm = cras_system_state_get_tm();
117 struct cras_timer *t = dbus_timeout_get_data(timeout);
118
119 if (t) {
120 dbus_timeout_set_data(timeout, NULL, NULL);
121 cras_tm_cancel_timer(tm, t);
122 }
123 }
124
dbus_timeout_toggled(DBusTimeout * timeout,void * arg)125 static void dbus_timeout_toggled(DBusTimeout *timeout, void *arg)
126 {
127 if (dbus_timeout_get_enabled(timeout))
128 dbus_timeout_add(timeout, NULL);
129 else
130 dbus_timeout_remove(timeout, NULL);
131 }
132
cras_dbus_connect_system_bus()133 DBusConnection *cras_dbus_connect_system_bus()
134 {
135 DBusError dbus_error;
136 DBusConnection *conn;
137 int rc;
138
139 dbus_error_init(&dbus_error);
140
141 conn = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_error);
142 if (!conn) {
143 syslog(LOG_WARNING, "Failed to connect to D-Bus: %s",
144 dbus_error.message);
145 dbus_error_free(&dbus_error);
146 return NULL;
147 }
148
149 /* Request a name on the bus. */
150 rc = dbus_bus_request_name(conn, "org.chromium.cras", 0, &dbus_error);
151 if (dbus_error_is_set(&dbus_error)) {
152 syslog(LOG_ERR, "Requesting dbus name %s", dbus_error.message);
153 dbus_error_free(&dbus_error);
154 }
155 if (rc != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
156 syslog(LOG_ERR, "Not primary owner of dbus name.");
157
158 if (!dbus_connection_set_watch_functions(
159 conn, dbus_watch_add, dbus_watch_remove, dbus_watch_toggled,
160 NULL, NULL))
161 goto error;
162 if (!dbus_connection_set_timeout_functions(
163 conn, dbus_timeout_add, dbus_timeout_remove,
164 dbus_timeout_toggled, NULL, NULL))
165 goto error;
166
167 return conn;
168
169 error:
170 syslog(LOG_WARNING, "Failed to setup D-Bus connection.");
171 dbus_connection_unref(conn);
172 return NULL;
173 }
174
cras_dbus_dispatch(DBusConnection * conn)175 void cras_dbus_dispatch(DBusConnection *conn)
176 {
177 while (dbus_connection_dispatch(conn) == DBUS_DISPATCH_DATA_REMAINS)
178 ;
179 }
180
cras_dbus_disconnect_system_bus(DBusConnection * conn)181 void cras_dbus_disconnect_system_bus(DBusConnection *conn)
182 {
183 dbus_connection_unref(conn);
184 }
185