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 "tcp_listen=<hostname>");
53 PA_MODULE_LOAD_ONCE(true);
54 PA_MODULE_AUTHOR("Tanu Kaskinen");
55 PA_MODULE_VERSION(PACKAGE_VERSION
);
72 struct server
*local_server
;
73 struct server
*tcp_server
;
75 pa_idxset
*connections
;
77 pa_defer_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
[] = {
102 static void connection_free(struct connection
*c
) {
105 pa_assert_se(pa_dbus_protocol_unregister_connection(c
->server
->userdata
->dbus_protocol
, pa_dbus_wrap_connection_get(c
->wrap_conn
)) >= 0);
107 pa_client_free(c
->client
);
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 pa_idxset_remove_by_data(conn
->server
->userdata
->connections
, conn
, NULL
);
121 connection_free(conn
);
124 pa_log_info("Connection killed.");
127 /* Called from pa_client_send_event(). */
128 static void client_send_event_cb(pa_client
*c
, const char *name
, pa_proplist
*data
) {
129 struct connection
*conn
= NULL
;
130 DBusMessage
*signal_msg
= NULL
;
131 DBusMessageIter msg_iter
;
136 pa_assert(c
->userdata
);
140 pa_assert_se(signal_msg
= dbus_message_new_signal(pa_dbusiface_core_get_client_path(conn
->server
->userdata
->core_iface
, c
),
141 PA_DBUSIFACE_CLIENT_INTERFACE
,
143 dbus_message_iter_init_append(signal_msg
, &msg_iter
);
144 pa_assert_se(dbus_message_iter_append_basic(&msg_iter
, DBUS_TYPE_STRING
, &name
));
145 pa_dbus_append_proplist(&msg_iter
, data
);
147 pa_assert_se(dbus_connection_send(pa_dbus_wrap_connection_get(conn
->wrap_conn
), signal_msg
, NULL
));
148 dbus_message_unref(signal_msg
);
151 /* Called by D-Bus at the authentication phase. */
152 static dbus_bool_t
user_check_cb(DBusConnection
*connection
, unsigned long uid
, void *data
) {
153 pa_log_debug("Allowing connection by user %lu.", uid
);
158 static DBusHandlerResult
disconnection_filter_cb(DBusConnection
*connection
, DBusMessage
*message
, void *user_data
) {
159 struct connection
*c
= user_data
;
161 pa_assert(connection
);
165 if (dbus_message_is_signal(message
, "org.freedesktop.DBus.Local", "Disconnected")) {
166 /* The connection died. Now we want to free the connection object, but
167 * let's wait until this message is fully processed, in case someone
168 * else is interested in this signal too. */
169 c
->server
->userdata
->module
->core
->mainloop
->defer_enable(c
->server
->userdata
->cleanup_event
, 1);
172 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
175 /* Called by D-Bus when a new client connection is received. */
176 static void connection_new_cb(DBusServer
*dbus_server
, DBusConnection
*new_connection
, void *data
) {
177 struct server
*s
= data
;
178 struct connection
*c
;
179 pa_client_new_data new_data
;
182 pa_assert(new_connection
);
185 pa_client_new_data_init(&new_data
);
186 new_data
.module
= s
->userdata
->module
;
187 new_data
.driver
= __FILE__
;
188 pa_proplist_sets(new_data
.proplist
, PA_PROP_APPLICATION_NAME
, "D-Bus client");
189 client
= pa_client_new(s
->userdata
->module
->core
, &new_data
);
190 pa_client_new_data_done(&new_data
);
193 dbus_connection_close(new_connection
);
197 if (s
->type
== SERVER_TYPE_TCP
|| s
->userdata
->module
->core
->server_type
== PA_SERVER_TYPE_SYSTEM
) {
198 /* FIXME: Here we allow anyone from anywhere to access the server,
199 * anonymously. Access control should be configurable. */
200 dbus_connection_set_unix_user_function(new_connection
, user_check_cb
, NULL
, NULL
);
201 dbus_connection_set_allow_anonymous(new_connection
, TRUE
);
204 c
= pa_xnew(struct connection
, 1);
206 c
->wrap_conn
= pa_dbus_wrap_connection_new_from_existing(s
->userdata
->module
->core
->mainloop
, true, new_connection
);
209 c
->client
->kill
= client_kill_cb
;
210 c
->client
->send_event
= client_send_event_cb
;
211 c
->client
->userdata
= c
;
213 pa_assert_se(dbus_connection_add_filter(new_connection
, disconnection_filter_cb
, c
, NULL
));
215 pa_idxset_put(s
->userdata
->connections
, c
, NULL
);
217 pa_assert_se(pa_dbus_protocol_register_connection(s
->userdata
->dbus_protocol
, new_connection
, c
->client
) >= 0);
220 /* Called by PA mainloop when a D-Bus fd watch event needs handling. */
221 static void io_event_cb(pa_mainloop_api
*mainloop
, pa_io_event
*e
, int fd
, pa_io_event_flags_t events
, void *userdata
) {
222 unsigned int flags
= 0;
223 DBusWatch
*watch
= userdata
;
225 #if HAVE_DBUS_WATCH_GET_UNIX_FD
226 pa_assert(fd
== dbus_watch_get_unix_fd(watch
));
228 pa_assert(fd
== dbus_watch_get_fd(watch
));
231 if (!dbus_watch_get_enabled(watch
)) {
232 pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch
, fd
);
236 if (events
& PA_IO_EVENT_INPUT
)
237 flags
|= DBUS_WATCH_READABLE
;
238 if (events
& PA_IO_EVENT_OUTPUT
)
239 flags
|= DBUS_WATCH_WRITABLE
;
240 if (events
& PA_IO_EVENT_HANGUP
)
241 flags
|= DBUS_WATCH_HANGUP
;
242 if (events
& PA_IO_EVENT_ERROR
)
243 flags
|= DBUS_WATCH_ERROR
;
245 dbus_watch_handle(watch
, flags
);
248 /* Called by PA mainloop when a D-Bus timer event needs handling. */
249 static void time_event_cb(pa_mainloop_api
*mainloop
, pa_time_event
* e
, const struct timeval
*tv
, void *userdata
) {
250 DBusTimeout
*timeout
= userdata
;
252 if (dbus_timeout_get_enabled(timeout
)) {
253 struct timeval next
= *tv
;
254 dbus_timeout_handle(timeout
);
256 /* restart it for the next scheduled time */
257 pa_timeval_add(&next
, (pa_usec_t
) dbus_timeout_get_interval(timeout
) * 1000);
258 mainloop
->time_restart(e
, &next
);
262 /* Translates D-Bus fd watch event flags to PA IO event flags. */
263 static pa_io_event_flags_t
get_watch_flags(DBusWatch
*watch
) {
265 pa_io_event_flags_t events
= 0;
269 flags
= dbus_watch_get_flags(watch
);
271 /* no watch flags for disabled watches */
272 if (!dbus_watch_get_enabled(watch
))
273 return PA_IO_EVENT_NULL
;
275 if (flags
& DBUS_WATCH_READABLE
)
276 events
|= PA_IO_EVENT_INPUT
;
277 if (flags
& DBUS_WATCH_WRITABLE
)
278 events
|= PA_IO_EVENT_OUTPUT
;
280 return events
| PA_IO_EVENT_HANGUP
| PA_IO_EVENT_ERROR
;
283 /* Called by D-Bus when a D-Bus fd watch event is added. */
284 static dbus_bool_t
watch_add_cb(DBusWatch
*watch
, void *data
) {
285 struct server
*s
= data
;
286 pa_mainloop_api
*mainloop
;
292 mainloop
= s
->userdata
->module
->core
->mainloop
;
294 ev
= mainloop
->io_new(
296 #if HAVE_DBUS_WATCH_GET_UNIX_FD
297 dbus_watch_get_unix_fd(watch
),
299 dbus_watch_get_fd(watch
),
301 get_watch_flags(watch
), io_event_cb
, watch
);
303 dbus_watch_set_data(watch
, ev
, NULL
);
308 /* Called by D-Bus when a D-Bus fd watch event is removed. */
309 static void watch_remove_cb(DBusWatch
*watch
, void *data
) {
310 struct server
*s
= data
;
316 if ((ev
= dbus_watch_get_data(watch
)))
317 s
->userdata
->module
->core
->mainloop
->io_free(ev
);
320 /* Called by D-Bus when a D-Bus fd watch event is toggled. */
321 static void watch_toggled_cb(DBusWatch
*watch
, void *data
) {
322 struct server
*s
= data
;
328 pa_assert_se(ev
= dbus_watch_get_data(watch
));
330 /* get_watch_flags() checks if the watch is enabled */
331 s
->userdata
->module
->core
->mainloop
->io_enable(ev
, get_watch_flags(watch
));
334 /* Called by D-Bus when a D-Bus timer event is added. */
335 static dbus_bool_t
timeout_add_cb(DBusTimeout
*timeout
, void *data
) {
336 struct server
*s
= data
;
337 pa_mainloop_api
*mainloop
;
344 if (!dbus_timeout_get_enabled(timeout
))
347 mainloop
= s
->userdata
->module
->core
->mainloop
;
349 pa_gettimeofday(&tv
);
350 pa_timeval_add(&tv
, (pa_usec_t
) dbus_timeout_get_interval(timeout
) * 1000);
352 ev
= mainloop
->time_new(mainloop
, &tv
, time_event_cb
, timeout
);
354 dbus_timeout_set_data(timeout
, ev
, NULL
);
359 /* Called by D-Bus when a D-Bus timer event is removed. */
360 static void timeout_remove_cb(DBusTimeout
*timeout
, void *data
) {
361 struct server
*s
= data
;
367 if ((ev
= dbus_timeout_get_data(timeout
)))
368 s
->userdata
->module
->core
->mainloop
->time_free(ev
);
371 /* Called by D-Bus when a D-Bus timer event is toggled. */
372 static void timeout_toggled_cb(DBusTimeout
*timeout
, void *data
) {
373 struct server
*s
= data
;
374 pa_mainloop_api
*mainloop
;
380 mainloop
= s
->userdata
->module
->core
->mainloop
;
382 pa_assert_se(ev
= dbus_timeout_get_data(timeout
));
384 if (dbus_timeout_get_enabled(timeout
)) {
387 pa_gettimeofday(&tv
);
388 pa_timeval_add(&tv
, (pa_usec_t
) dbus_timeout_get_interval(timeout
) * 1000);
390 mainloop
->time_restart(ev
, &tv
);
392 mainloop
->time_restart(ev
, NULL
);
395 static void server_free(struct server
*s
) {
398 if (s
->dbus_server
) {
399 dbus_server_disconnect(s
->dbus_server
);
400 dbus_server_unref(s
->dbus_server
);
406 static struct server
*start_server(struct userdata
*u
, const char *address
, enum server_type type
) {
407 /* XXX: We assume that when we unref the DBusServer instance at module
408 * shutdown, nobody else holds any references to it. If we stop assuming
409 * that someday, dbus_server_set_new_connection_function,
410 * dbus_server_set_watch_functions and dbus_server_set_timeout_functions
411 * calls should probably register free callbacks, instead of providing NULL
414 struct server
*s
= NULL
;
420 dbus_error_init(&error
);
422 s
= pa_xnew0(struct server
, 1);
425 s
->dbus_server
= dbus_server_listen(address
, &error
);
427 if (dbus_error_is_set(&error
)) {
428 pa_log("dbus_server_listen() failed: %s: %s", error
.name
, error
.message
);
432 dbus_server_set_new_connection_function(s
->dbus_server
, connection_new_cb
, s
, NULL
);
434 if (!dbus_server_set_watch_functions(s
->dbus_server
, watch_add_cb
, watch_remove_cb
, watch_toggled_cb
, s
, NULL
)) {
435 pa_log("dbus_server_set_watch_functions() ran out of memory.");
439 if (!dbus_server_set_timeout_functions(s
->dbus_server
, timeout_add_cb
, timeout_remove_cb
, timeout_toggled_cb
, s
, NULL
)) {
440 pa_log("dbus_server_set_timeout_functions() ran out of memory.");
450 dbus_error_free(&error
);
455 static struct server
*start_local_server(struct userdata
*u
) {
456 struct server
*s
= NULL
;
457 char *address
= NULL
;
461 address
= pa_get_dbus_address_from_server_type(u
->module
->core
->server_type
);
463 s
= start_server(u
, address
, SERVER_TYPE_LOCAL
); /* May return NULL */
470 static struct server
*start_tcp_server(struct userdata
*u
) {
471 struct server
*s
= NULL
;
472 char *address
= NULL
;
476 address
= pa_sprintf_malloc("tcp:host=%s,port=%u", u
->tcp_listen
, u
->tcp_port
);
478 s
= start_server(u
, address
, SERVER_TYPE_TCP
); /* May return NULL */
485 static int get_access_arg(pa_modargs
*ma
, bool *local_access
, bool *remote_access
) {
486 const char *value
= NULL
;
489 pa_assert(local_access
);
490 pa_assert(remote_access
);
492 if (!(value
= pa_modargs_get_value(ma
, "access", NULL
)))
495 if (pa_streq(value
, "local")) {
496 *local_access
= true;
497 *remote_access
= false;
498 } else if (pa_streq(value
, "remote")) {
499 *local_access
= false;
500 *remote_access
= true;
501 } else if (pa_streq(value
, "local,remote")) {
502 *local_access
= true;
503 *remote_access
= true;
510 /* Frees dead client connections. */
511 static void cleanup_cb(pa_mainloop_api
*a
, pa_defer_event
*e
, void *userdata
) {
512 struct userdata
*u
= userdata
;
513 struct connection
*conn
= NULL
;
516 PA_IDXSET_FOREACH(conn
, u
->connections
, idx
) {
517 if (!dbus_connection_get_is_connected(pa_dbus_wrap_connection_get(conn
->wrap_conn
))) {
518 pa_idxset_remove_by_data(u
->connections
, conn
, NULL
);
519 connection_free(conn
);
523 u
->module
->core
->mainloop
->defer_enable(e
, 0);
526 int pa__init(pa_module
*m
) {
527 struct userdata
*u
= NULL
;
528 pa_modargs
*ma
= NULL
;
532 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
533 pa_log("Failed to parse module arguments.");
537 m
->userdata
= u
= pa_xnew0(struct userdata
, 1);
539 u
->local_access
= true;
540 u
->remote_access
= false;
541 u
->tcp_port
= PA_DBUS_DEFAULT_PORT
;
543 if (get_access_arg(ma
, &u
->local_access
, &u
->remote_access
) < 0) {
544 pa_log("Invalid access argument: '%s'", pa_modargs_get_value(ma
, "access", NULL
));
548 if (pa_modargs_get_value_u32(ma
, "tcp_port", &u
->tcp_port
) < 0 || u
->tcp_port
< 1 || u
->tcp_port
> 49150) {
549 pa_log("Invalid tcp_port argument: '%s'", pa_modargs_get_value(ma
, "tcp_port", NULL
));
553 u
->tcp_listen
= pa_xstrdup(pa_modargs_get_value(ma
, "tcp_listen", "0.0.0.0"));
555 if (u
->local_access
&& !(u
->local_server
= start_local_server(u
))) {
556 pa_log("Starting the local D-Bus server failed.");
560 if (u
->remote_access
&& !(u
->tcp_server
= start_tcp_server(u
))) {
561 pa_log("Starting the D-Bus server for remote connections failed.");
565 u
->connections
= pa_idxset_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
567 u
->cleanup_event
= m
->core
->mainloop
->defer_new(m
->core
->mainloop
, cleanup_cb
, u
);
568 m
->core
->mainloop
->defer_enable(u
->cleanup_event
, 0);
570 u
->dbus_protocol
= pa_dbus_protocol_get(m
->core
);
571 u
->core_iface
= pa_dbusiface_core_new(m
->core
);
586 void pa__done(pa_module
*m
) {
591 if (!(u
= m
->userdata
))
595 pa_dbusiface_core_free(u
->core_iface
);
598 pa_idxset_free(u
->connections
, (pa_free_cb_t
) connection_free
);
600 /* This must not be called before the connections are freed, because if
601 * there are any connections left, they will emit the
602 * org.freedesktop.DBus.Local.Disconnected signal, and
603 * disconnection_filter_cb() will be called. disconnection_filter_cb() then
604 * tries to enable the defer event, and if it's already freed, an assertion
605 * will be hit in mainloop.c. */
606 if (u
->cleanup_event
)
607 m
->core
->mainloop
->defer_free(u
->cleanup_event
);
610 server_free(u
->tcp_server
);
613 server_free(u
->local_server
);
615 if (u
->dbus_protocol
)
616 pa_dbus_protocol_unref(u
->dbus_protocol
);
618 pa_xfree(u
->tcp_listen
);