• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)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 
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,
52 					      watch);
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 
78 
dbus_timeout_callback(struct cras_timer * t,void * data)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 
dbus_timeout_add(DBusTimeout * timeout,void * arg)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 
dbus_timeout_remove(DBusTimeout * timeout,void * arg)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 
dbus_timeout_toggled(DBusTimeout * timeout,void * arg)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 
cras_dbus_connect_system_bus()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 
cras_dbus_dispatch(DBusConnection * conn)186 void cras_dbus_dispatch(DBusConnection *conn)
187 {
188 	while (dbus_connection_dispatch(conn)
189 		== DBUS_DISPATCH_DATA_REMAINS)
190 		;
191 }
192 
cras_dbus_disconnect_system_bus(DBusConnection * conn)193 void cras_dbus_disconnect_system_bus(DBusConnection *conn)
194 {
195 	dbus_connection_unref(conn);
196 }
197