2 This file is part of PulseAudio.
4 Copyright 2009 Tanu Kaskinen
5 Copyright 2006 Lennart Poettering
6 Copyright 2006 Shams E. King
8 PulseAudio is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published
10 by the Free Software Foundation; either version 2.1 of the License,
11 or (at your option) any later version.
13 PulseAudio is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with PulseAudio; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
28 #include <dbus/dbus.h>
30 #include <pulse/mainloop-api.h>
31 #include <pulse/timeval.h>
32 #include <pulse/xmalloc.h>
34 #include <pulsecore/client.h>
35 #include <pulsecore/core-util.h>
36 #include <pulsecore/dbus-util.h>
37 #include <pulsecore/idxset.h>
38 #include <pulsecore/macro.h>
39 #include <pulsecore/modargs.h>
40 #include <pulsecore/module.h>
41 #include <pulsecore/protocol-dbus.h>
43 #include "iface-client.h"
44 #include "iface-core.h"
46 #include "module-dbus-protocol-symdef.h"
48 PA_MODULE_DESCRIPTION("D-Bus interface");
50 "access=local|remote|local,remote "
51 "tcp_port=<port number>");
52 PA_MODULE_LOAD_ONCE(TRUE
);
53 PA_MODULE_AUTHOR("Tanu Kaskinen");
54 PA_MODULE_VERSION(PACKAGE_VERSION
);
56 #define CLEANUP_INTERVAL 10 /* seconds */
68 pa_bool_t local_access
;
69 pa_bool_t remote_access
;
72 struct server
*local_server
;
73 struct server
*tcp_server
;
75 pa_idxset
*connections
;
77 pa_time_event
*cleanup_event
;
79 pa_dbus_protocol
*dbus_protocol
;
80 pa_dbusiface_core
*core_iface
;
84 struct userdata
*userdata
;
85 enum server_type type
;
86 DBusServer
*dbus_server
;
90 struct server
*server
;
91 pa_dbus_wrap_connection
*wrap_conn
;
95 static const char* const valid_modargs
[] = {
101 static void connection_free(struct connection
*c
) {
104 pa_assert_se(pa_dbus_protocol_unregister_connection(c
->server
->userdata
->dbus_protocol
, pa_dbus_wrap_connection_get(c
->wrap_conn
)) >= 0);
106 pa_client_free(c
->client
);
107 pa_assert_se(pa_idxset_remove_by_data(c
->server
->userdata
->connections
, c
, NULL
));
108 pa_dbus_wrap_connection_free(c
->wrap_conn
);
112 /* Called from pa_client_kill(). */
113 static void client_kill_cb(pa_client
*c
) {
114 struct connection
*conn
;
117 pa_assert(c
->userdata
);
120 connection_free(conn
);
123 pa_log_info("Connection killed.");
126 /* Called from pa_client_send_event(). */
127 static void client_send_event_cb(pa_client
*c
, const char *name
, pa_proplist
*data
) {
128 struct connection
*conn
= NULL
;
129 DBusMessage
*signal
= NULL
;
130 DBusMessageIter msg_iter
;
135 pa_assert(c
->userdata
);
139 pa_assert_se(signal
= dbus_message_new_signal(pa_dbusiface_core_get_client_path(conn
->server
->userdata
->core_iface
, c
),
140 PA_DBUSIFACE_CLIENT_INTERFACE
,
142 dbus_message_iter_init_append(signal
, &msg_iter
);
143 pa_assert_se(dbus_message_iter_append_basic(&msg_iter
, DBUS_TYPE_STRING
, &name
));
144 pa_dbus_append_proplist(&msg_iter
, data
);
146 pa_assert_se(dbus_connection_send(pa_dbus_wrap_connection_get(conn
->wrap_conn
), signal
, NULL
));
147 dbus_message_unref(signal
);
150 /* Called by D-Bus at the authentication phase. */
151 static dbus_bool_t
user_check_cb(DBusConnection
*connection
, unsigned long uid
, void *data
) {
152 pa_log_debug("Allowing connection by user %lu.", uid
);
157 /* Called by D-Bus when a new client connection is received. */
158 static void connection_new_cb(DBusServer
*dbus_server
, DBusConnection
*new_connection
, void *data
) {
159 struct server
*s
= data
;
160 struct connection
*c
;
161 pa_client_new_data new_data
;
164 pa_assert(new_connection
);
167 pa_client_new_data_init(&new_data
);
168 new_data
.module
= s
->userdata
->module
;
169 new_data
.driver
= __FILE__
;
170 pa_proplist_sets(new_data
.proplist
, PA_PROP_APPLICATION_NAME
, "D-Bus client");
171 client
= pa_client_new(s
->userdata
->module
->core
, &new_data
);
172 pa_client_new_data_done(&new_data
);
175 dbus_connection_close(new_connection
);
179 if (s
->type
== SERVER_TYPE_TCP
|| s
->userdata
->module
->core
->server_type
== PA_SERVER_TYPE_SYSTEM
) {
180 /* FIXME: Here we allow anyone from anywhere to access the server,
181 * anonymously. Access control should be configurable. */
182 dbus_connection_set_unix_user_function(new_connection
, user_check_cb
, NULL
, NULL
);
183 dbus_connection_set_allow_anonymous(new_connection
, TRUE
);
186 c
= pa_xnew(struct connection
, 1);
188 c
->wrap_conn
= pa_dbus_wrap_connection_new_from_existing(s
->userdata
->module
->core
->mainloop
, TRUE
, new_connection
);
191 c
->client
->kill
= client_kill_cb
;
192 c
->client
->send_event
= client_send_event_cb
;
193 c
->client
->userdata
= c
;
195 pa_idxset_put(s
->userdata
->connections
, c
, NULL
);
197 pa_assert_se(pa_dbus_protocol_register_connection(s
->userdata
->dbus_protocol
, new_connection
, c
->client
) >= 0);
200 /* Called by PA mainloop when a D-Bus fd watch event needs handling. */
201 static void io_event_cb(pa_mainloop_api
*mainloop
, pa_io_event
*e
, int fd
, pa_io_event_flags_t events
, void *userdata
) {
202 unsigned int flags
= 0;
203 DBusWatch
*watch
= userdata
;
205 #if HAVE_DBUS_WATCH_GET_UNIX_FD
206 pa_assert(fd
== dbus_watch_get_unix_fd(watch
));
208 pa_assert(fd
== dbus_watch_get_fd(watch
));
211 if (!dbus_watch_get_enabled(watch
)) {
212 pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch
, fd
);
216 if (events
& PA_IO_EVENT_INPUT
)
217 flags
|= DBUS_WATCH_READABLE
;
218 if (events
& PA_IO_EVENT_OUTPUT
)
219 flags
|= DBUS_WATCH_WRITABLE
;
220 if (events
& PA_IO_EVENT_HANGUP
)
221 flags
|= DBUS_WATCH_HANGUP
;
222 if (events
& PA_IO_EVENT_ERROR
)
223 flags
|= DBUS_WATCH_ERROR
;
225 dbus_watch_handle(watch
, flags
);
228 /* Called by PA mainloop when a D-Bus timer event needs handling. */
229 static void time_event_cb(pa_mainloop_api
*mainloop
, pa_time_event
* e
, const struct timeval
*tv
, void *userdata
) {
230 DBusTimeout
*timeout
= userdata
;
232 if (dbus_timeout_get_enabled(timeout
)) {
233 struct timeval next
= *tv
;
234 dbus_timeout_handle(timeout
);
236 /* restart it for the next scheduled time */
237 pa_timeval_add(&next
, (pa_usec_t
) dbus_timeout_get_interval(timeout
) * 1000);
238 mainloop
->time_restart(e
, &next
);
242 /* Translates D-Bus fd watch event flags to PA IO event flags. */
243 static pa_io_event_flags_t
get_watch_flags(DBusWatch
*watch
) {
245 pa_io_event_flags_t events
= 0;
249 flags
= dbus_watch_get_flags(watch
);
251 /* no watch flags for disabled watches */
252 if (!dbus_watch_get_enabled(watch
))
253 return PA_IO_EVENT_NULL
;
255 if (flags
& DBUS_WATCH_READABLE
)
256 events
|= PA_IO_EVENT_INPUT
;
257 if (flags
& DBUS_WATCH_WRITABLE
)
258 events
|= PA_IO_EVENT_OUTPUT
;
260 return events
| PA_IO_EVENT_HANGUP
| PA_IO_EVENT_ERROR
;
263 /* Called by D-Bus when a D-Bus fd watch event is added. */
264 static dbus_bool_t
watch_add_cb(DBusWatch
*watch
, void *data
) {
265 struct server
*s
= data
;
266 pa_mainloop_api
*mainloop
;
272 mainloop
= s
->userdata
->module
->core
->mainloop
;
274 ev
= mainloop
->io_new(
276 #if HAVE_DBUS_WATCH_GET_UNIX_FD
277 dbus_watch_get_unix_fd(watch
),
279 dbus_watch_get_fd(watch
),
281 get_watch_flags(watch
), io_event_cb
, watch
);
283 dbus_watch_set_data(watch
, ev
, NULL
);
288 /* Called by D-Bus when a D-Bus fd watch event is removed. */
289 static void watch_remove_cb(DBusWatch
*watch
, void *data
) {
290 struct server
*s
= data
;
296 if ((ev
= dbus_watch_get_data(watch
)))
297 s
->userdata
->module
->core
->mainloop
->io_free(ev
);
300 /* Called by D-Bus when a D-Bus fd watch event is toggled. */
301 static void watch_toggled_cb(DBusWatch
*watch
, void *data
) {
302 struct server
*s
= data
;
308 pa_assert_se(ev
= dbus_watch_get_data(watch
));
310 /* get_watch_flags() checks if the watch is enabled */
311 s
->userdata
->module
->core
->mainloop
->io_enable(ev
, get_watch_flags(watch
));
314 /* Called by D-Bus when a D-Bus timer event is added. */
315 static dbus_bool_t
timeout_add_cb(DBusTimeout
*timeout
, void *data
) {
316 struct server
*s
= data
;
317 pa_mainloop_api
*mainloop
;
324 if (!dbus_timeout_get_enabled(timeout
))
327 mainloop
= s
->userdata
->module
->core
->mainloop
;
329 pa_gettimeofday(&tv
);
330 pa_timeval_add(&tv
, (pa_usec_t
) dbus_timeout_get_interval(timeout
) * 1000);
332 ev
= mainloop
->time_new(mainloop
, &tv
, time_event_cb
, timeout
);
334 dbus_timeout_set_data(timeout
, ev
, NULL
);
339 /* Called by D-Bus when a D-Bus timer event is removed. */
340 static void timeout_remove_cb(DBusTimeout
*timeout
, void *data
) {
341 struct server
*s
= data
;
347 if ((ev
= dbus_timeout_get_data(timeout
)))
348 s
->userdata
->module
->core
->mainloop
->time_free(ev
);
351 /* Called by D-Bus when a D-Bus timer event is toggled. */
352 static void timeout_toggled_cb(DBusTimeout
*timeout
, void *data
) {
353 struct server
*s
= data
;
354 pa_mainloop_api
*mainloop
;
360 mainloop
= s
->userdata
->module
->core
->mainloop
;
362 pa_assert_se(ev
= dbus_timeout_get_data(timeout
));
364 if (dbus_timeout_get_enabled(timeout
)) {
367 pa_gettimeofday(&tv
);
368 pa_timeval_add(&tv
, (pa_usec_t
) dbus_timeout_get_interval(timeout
) * 1000);
370 mainloop
->time_restart(ev
, &tv
);
372 mainloop
->time_restart(ev
, NULL
);
375 static void server_free(struct server
*s
) {
378 if (s
->dbus_server
) {
379 dbus_server_disconnect(s
->dbus_server
);
380 dbus_server_unref(s
->dbus_server
);
386 static struct server
*start_server(struct userdata
*u
, const char *address
, enum server_type type
) {
387 /* XXX: We assume that when we unref the DBusServer instance at module
388 * shutdown, nobody else holds any references to it. If we stop assuming
389 * that someday, dbus_server_set_new_connection_function,
390 * dbus_server_set_watch_functions and dbus_server_set_timeout_functions
391 * calls should probably register free callbacks, instead of providing NULL
394 struct server
*s
= NULL
;
400 dbus_error_init(&error
);
402 s
= pa_xnew0(struct server
, 1);
404 s
->dbus_server
= dbus_server_listen(address
, &error
);
406 if (dbus_error_is_set(&error
)) {
407 pa_log("dbus_server_listen() failed: %s: %s", error
.name
, error
.message
);
411 dbus_server_set_new_connection_function(s
->dbus_server
, connection_new_cb
, s
, NULL
);
413 if (!dbus_server_set_watch_functions(s
->dbus_server
, watch_add_cb
, watch_remove_cb
, watch_toggled_cb
, s
, NULL
)) {
414 pa_log("dbus_server_set_watch_functions() ran out of memory.");
418 if (!dbus_server_set_timeout_functions(s
->dbus_server
, timeout_add_cb
, timeout_remove_cb
, timeout_toggled_cb
, s
, NULL
)) {
419 pa_log("dbus_server_set_timeout_functions() ran out of memory.");
429 dbus_error_free(&error
);
434 static struct server
*start_local_server(struct userdata
*u
) {
435 struct server
*s
= NULL
;
436 char *address
= NULL
;
440 address
= pa_get_dbus_address_from_server_type(u
->module
->core
->server_type
);
442 s
= start_server(u
, address
, SERVER_TYPE_LOCAL
); /* May return NULL */
449 static struct server
*start_tcp_server(struct userdata
*u
) {
450 struct server
*s
= NULL
;
451 char *address
= NULL
;
455 address
= pa_sprintf_malloc("tcp:host=127.0.0.1,port=%u", u
->tcp_port
);
457 s
= start_server(u
, address
, SERVER_TYPE_TCP
); /* May return NULL */
464 static int get_access_arg(pa_modargs
*ma
, pa_bool_t
*local_access
, pa_bool_t
*remote_access
) {
465 const char *value
= NULL
;
468 pa_assert(local_access
);
469 pa_assert(remote_access
);
471 if (!(value
= pa_modargs_get_value(ma
, "access", NULL
)))
474 if (!strcmp(value
, "local")) {
475 *local_access
= TRUE
;
476 *remote_access
= FALSE
;
477 } else if (!strcmp(value
, "remote")) {
478 *local_access
= FALSE
;
479 *remote_access
= TRUE
;
480 } else if (!strcmp(value
, "local,remote")) {
481 *local_access
= TRUE
;
482 *remote_access
= TRUE
;
489 /* Frees dead client connections. Called every CLEANUP_INTERVAL seconds. */
490 static void cleanup_cb(pa_mainloop_api
*a
, pa_time_event
*e
, const struct timeval
*tv
, void *userdata
) {
491 struct userdata
*u
= userdata
;
492 struct connection
*conn
= NULL
;
494 struct timeval cleanup_timeval
;
495 unsigned free_count
= 0;
497 for (conn
= pa_idxset_first(u
->connections
, &idx
); conn
; conn
= pa_idxset_next(u
->connections
, &idx
)) {
498 if (!dbus_connection_get_is_connected(pa_dbus_wrap_connection_get(conn
->wrap_conn
))) {
499 connection_free(conn
);
505 pa_log_debug("Freed %u dead D-Bus client connections.", free_count
);
507 pa_gettimeofday(&cleanup_timeval
);
508 cleanup_timeval
.tv_sec
+= CLEANUP_INTERVAL
;
509 u
->module
->core
->mainloop
->time_restart(e
, &cleanup_timeval
);
512 int pa__init(pa_module
*m
) {
513 struct userdata
*u
= NULL
;
514 pa_modargs
*ma
= NULL
;
515 struct timeval cleanup_timeval
;
519 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
520 pa_log("Failed to parse module arguments.");
524 m
->userdata
= u
= pa_xnew0(struct userdata
, 1);
526 u
->local_access
= TRUE
;
527 u
->remote_access
= FALSE
;
528 u
->tcp_port
= PA_DBUS_DEFAULT_PORT
;
530 if (get_access_arg(ma
, &u
->local_access
, &u
->remote_access
) < 0) {
531 pa_log("Invalid access argument: '%s'", pa_modargs_get_value(ma
, "access", NULL
));
535 if (pa_modargs_get_value_u32(ma
, "tcp_port", &u
->tcp_port
) < 0 || u
->tcp_port
< 1 || u
->tcp_port
> 49150) {
536 pa_log("Invalid tcp_port argument: '%s'", pa_modargs_get_value(ma
, "tcp_port", NULL
));
540 if (u
->local_access
&& !(u
->local_server
= start_local_server(u
))) {
541 pa_log("Starting the local D-Bus server failed.");
545 if (u
->remote_access
&& !(u
->tcp_server
= start_tcp_server(u
))) {
546 pa_log("Starting the D-Bus server for remote connections failed.");
550 u
->connections
= pa_idxset_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
552 pa_gettimeofday(&cleanup_timeval
);
553 cleanup_timeval
.tv_sec
+= CLEANUP_INTERVAL
;
554 u
->cleanup_event
= m
->core
->mainloop
->time_new(m
->core
->mainloop
, &cleanup_timeval
, cleanup_cb
, u
);
556 u
->dbus_protocol
= pa_dbus_protocol_get(m
->core
);
557 u
->core_iface
= pa_dbusiface_core_new(m
->core
);
570 /* Called by idxset when the connection set is freed. */
571 static void connection_free_cb(void *p
, void *userdata
) {
572 struct connection
*conn
= p
;
576 connection_free(conn
);
579 void pa__done(pa_module
*m
) {
584 if (!(u
= m
->userdata
))
588 pa_dbusiface_core_free(u
->core_iface
);
590 if (u
->cleanup_event
)
591 m
->core
->mainloop
->time_free(u
->cleanup_event
);
594 pa_idxset_free(u
->connections
, connection_free_cb
, NULL
);
597 server_free(u
->tcp_server
);
600 server_free(u
->local_server
);
602 if (u
->dbus_protocol
)
603 pa_dbus_protocol_unref(u
->dbus_protocol
);