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
);
67 pa_bool_t local_access
;
68 pa_bool_t remote_access
;
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 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_msg
= NULL
;
130 DBusMessageIter msg_iter
;
135 pa_assert(c
->userdata
);
139 pa_assert_se(signal_msg
= 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
, &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_msg
, NULL
));
147 dbus_message_unref(signal_msg
);
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 static DBusHandlerResult
disconnection_filter_cb(DBusConnection
*connection
, DBusMessage
*message
, void *user_data
) {
158 struct connection
*c
= user_data
;
160 pa_assert(connection
);
164 if (dbus_message_is_signal(message
, "org.freedesktop.DBus.Local", "Disconnected")) {
165 /* The connection died. Now we want to free the connection object, but
166 * let's wait until this message is fully processed, in case someone
167 * else is interested in this signal too. */
168 c
->server
->userdata
->module
->core
->mainloop
->defer_enable(c
->server
->userdata
->cleanup_event
, 1);
171 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
174 /* Called by D-Bus when a new client connection is received. */
175 static void connection_new_cb(DBusServer
*dbus_server
, DBusConnection
*new_connection
, void *data
) {
176 struct server
*s
= data
;
177 struct connection
*c
;
178 pa_client_new_data new_data
;
181 pa_assert(new_connection
);
184 pa_client_new_data_init(&new_data
);
185 new_data
.module
= s
->userdata
->module
;
186 new_data
.driver
= __FILE__
;
187 pa_proplist_sets(new_data
.proplist
, PA_PROP_APPLICATION_NAME
, "D-Bus client");
188 client
= pa_client_new(s
->userdata
->module
->core
, &new_data
);
189 pa_client_new_data_done(&new_data
);
192 dbus_connection_close(new_connection
);
196 if (s
->type
== SERVER_TYPE_TCP
|| s
->userdata
->module
->core
->server_type
== PA_SERVER_TYPE_SYSTEM
) {
197 /* FIXME: Here we allow anyone from anywhere to access the server,
198 * anonymously. Access control should be configurable. */
199 dbus_connection_set_unix_user_function(new_connection
, user_check_cb
, NULL
, NULL
);
200 dbus_connection_set_allow_anonymous(new_connection
, TRUE
);
203 c
= pa_xnew(struct connection
, 1);
205 c
->wrap_conn
= pa_dbus_wrap_connection_new_from_existing(s
->userdata
->module
->core
->mainloop
, TRUE
, new_connection
);
208 c
->client
->kill
= client_kill_cb
;
209 c
->client
->send_event
= client_send_event_cb
;
210 c
->client
->userdata
= c
;
212 pa_assert_se(dbus_connection_add_filter(new_connection
, disconnection_filter_cb
, c
, NULL
));
214 pa_idxset_put(s
->userdata
->connections
, c
, NULL
);
216 pa_assert_se(pa_dbus_protocol_register_connection(s
->userdata
->dbus_protocol
, new_connection
, c
->client
) >= 0);
219 /* Called by PA mainloop when a D-Bus fd watch event needs handling. */
220 static void io_event_cb(pa_mainloop_api
*mainloop
, pa_io_event
*e
, int fd
, pa_io_event_flags_t events
, void *userdata
) {
221 unsigned int flags
= 0;
222 DBusWatch
*watch
= userdata
;
224 #if HAVE_DBUS_WATCH_GET_UNIX_FD
225 pa_assert(fd
== dbus_watch_get_unix_fd(watch
));
227 pa_assert(fd
== dbus_watch_get_fd(watch
));
230 if (!dbus_watch_get_enabled(watch
)) {
231 pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch
, fd
);
235 if (events
& PA_IO_EVENT_INPUT
)
236 flags
|= DBUS_WATCH_READABLE
;
237 if (events
& PA_IO_EVENT_OUTPUT
)
238 flags
|= DBUS_WATCH_WRITABLE
;
239 if (events
& PA_IO_EVENT_HANGUP
)
240 flags
|= DBUS_WATCH_HANGUP
;
241 if (events
& PA_IO_EVENT_ERROR
)
242 flags
|= DBUS_WATCH_ERROR
;
244 dbus_watch_handle(watch
, flags
);
247 /* Called by PA mainloop when a D-Bus timer event needs handling. */
248 static void time_event_cb(pa_mainloop_api
*mainloop
, pa_time_event
* e
, const struct timeval
*tv
, void *userdata
) {
249 DBusTimeout
*timeout
= userdata
;
251 if (dbus_timeout_get_enabled(timeout
)) {
252 struct timeval next
= *tv
;
253 dbus_timeout_handle(timeout
);
255 /* restart it for the next scheduled time */
256 pa_timeval_add(&next
, (pa_usec_t
) dbus_timeout_get_interval(timeout
) * 1000);
257 mainloop
->time_restart(e
, &next
);
261 /* Translates D-Bus fd watch event flags to PA IO event flags. */
262 static pa_io_event_flags_t
get_watch_flags(DBusWatch
*watch
) {
264 pa_io_event_flags_t events
= 0;
268 flags
= dbus_watch_get_flags(watch
);
270 /* no watch flags for disabled watches */
271 if (!dbus_watch_get_enabled(watch
))
272 return PA_IO_EVENT_NULL
;
274 if (flags
& DBUS_WATCH_READABLE
)
275 events
|= PA_IO_EVENT_INPUT
;
276 if (flags
& DBUS_WATCH_WRITABLE
)
277 events
|= PA_IO_EVENT_OUTPUT
;
279 return events
| PA_IO_EVENT_HANGUP
| PA_IO_EVENT_ERROR
;
282 /* Called by D-Bus when a D-Bus fd watch event is added. */
283 static dbus_bool_t
watch_add_cb(DBusWatch
*watch
, void *data
) {
284 struct server
*s
= data
;
285 pa_mainloop_api
*mainloop
;
291 mainloop
= s
->userdata
->module
->core
->mainloop
;
293 ev
= mainloop
->io_new(
295 #if HAVE_DBUS_WATCH_GET_UNIX_FD
296 dbus_watch_get_unix_fd(watch
),
298 dbus_watch_get_fd(watch
),
300 get_watch_flags(watch
), io_event_cb
, watch
);
302 dbus_watch_set_data(watch
, ev
, NULL
);
307 /* Called by D-Bus when a D-Bus fd watch event is removed. */
308 static void watch_remove_cb(DBusWatch
*watch
, void *data
) {
309 struct server
*s
= data
;
315 if ((ev
= dbus_watch_get_data(watch
)))
316 s
->userdata
->module
->core
->mainloop
->io_free(ev
);
319 /* Called by D-Bus when a D-Bus fd watch event is toggled. */
320 static void watch_toggled_cb(DBusWatch
*watch
, void *data
) {
321 struct server
*s
= data
;
327 pa_assert_se(ev
= dbus_watch_get_data(watch
));
329 /* get_watch_flags() checks if the watch is enabled */
330 s
->userdata
->module
->core
->mainloop
->io_enable(ev
, get_watch_flags(watch
));
333 /* Called by D-Bus when a D-Bus timer event is added. */
334 static dbus_bool_t
timeout_add_cb(DBusTimeout
*timeout
, void *data
) {
335 struct server
*s
= data
;
336 pa_mainloop_api
*mainloop
;
343 if (!dbus_timeout_get_enabled(timeout
))
346 mainloop
= s
->userdata
->module
->core
->mainloop
;
348 pa_gettimeofday(&tv
);
349 pa_timeval_add(&tv
, (pa_usec_t
) dbus_timeout_get_interval(timeout
) * 1000);
351 ev
= mainloop
->time_new(mainloop
, &tv
, time_event_cb
, timeout
);
353 dbus_timeout_set_data(timeout
, ev
, NULL
);
358 /* Called by D-Bus when a D-Bus timer event is removed. */
359 static void timeout_remove_cb(DBusTimeout
*timeout
, void *data
) {
360 struct server
*s
= data
;
366 if ((ev
= dbus_timeout_get_data(timeout
)))
367 s
->userdata
->module
->core
->mainloop
->time_free(ev
);
370 /* Called by D-Bus when a D-Bus timer event is toggled. */
371 static void timeout_toggled_cb(DBusTimeout
*timeout
, void *data
) {
372 struct server
*s
= data
;
373 pa_mainloop_api
*mainloop
;
379 mainloop
= s
->userdata
->module
->core
->mainloop
;
381 pa_assert_se(ev
= dbus_timeout_get_data(timeout
));
383 if (dbus_timeout_get_enabled(timeout
)) {
386 pa_gettimeofday(&tv
);
387 pa_timeval_add(&tv
, (pa_usec_t
) dbus_timeout_get_interval(timeout
) * 1000);
389 mainloop
->time_restart(ev
, &tv
);
391 mainloop
->time_restart(ev
, NULL
);
394 static void server_free(struct server
*s
) {
397 if (s
->dbus_server
) {
398 dbus_server_disconnect(s
->dbus_server
);
399 dbus_server_unref(s
->dbus_server
);
405 static struct server
*start_server(struct userdata
*u
, const char *address
, enum server_type type
) {
406 /* XXX: We assume that when we unref the DBusServer instance at module
407 * shutdown, nobody else holds any references to it. If we stop assuming
408 * that someday, dbus_server_set_new_connection_function,
409 * dbus_server_set_watch_functions and dbus_server_set_timeout_functions
410 * calls should probably register free callbacks, instead of providing NULL
413 struct server
*s
= NULL
;
419 dbus_error_init(&error
);
421 s
= pa_xnew0(struct server
, 1);
424 s
->dbus_server
= dbus_server_listen(address
, &error
);
426 if (dbus_error_is_set(&error
)) {
427 pa_log("dbus_server_listen() failed: %s: %s", error
.name
, error
.message
);
431 dbus_server_set_new_connection_function(s
->dbus_server
, connection_new_cb
, s
, NULL
);
433 if (!dbus_server_set_watch_functions(s
->dbus_server
, watch_add_cb
, watch_remove_cb
, watch_toggled_cb
, s
, NULL
)) {
434 pa_log("dbus_server_set_watch_functions() ran out of memory.");
438 if (!dbus_server_set_timeout_functions(s
->dbus_server
, timeout_add_cb
, timeout_remove_cb
, timeout_toggled_cb
, s
, NULL
)) {
439 pa_log("dbus_server_set_timeout_functions() ran out of memory.");
449 dbus_error_free(&error
);
454 static struct server
*start_local_server(struct userdata
*u
) {
455 struct server
*s
= NULL
;
456 char *address
= NULL
;
460 address
= pa_get_dbus_address_from_server_type(u
->module
->core
->server_type
);
462 s
= start_server(u
, address
, SERVER_TYPE_LOCAL
); /* May return NULL */
469 static struct server
*start_tcp_server(struct userdata
*u
) {
470 struct server
*s
= NULL
;
471 char *address
= NULL
;
475 address
= pa_sprintf_malloc("tcp:host=%s,port=%u", u
->tcp_listen
, u
->tcp_port
);
477 s
= start_server(u
, address
, SERVER_TYPE_TCP
); /* May return NULL */
484 static int get_access_arg(pa_modargs
*ma
, pa_bool_t
*local_access
, pa_bool_t
*remote_access
) {
485 const char *value
= NULL
;
488 pa_assert(local_access
);
489 pa_assert(remote_access
);
491 if (!(value
= pa_modargs_get_value(ma
, "access", NULL
)))
494 if (!strcmp(value
, "local")) {
495 *local_access
= TRUE
;
496 *remote_access
= FALSE
;
497 } else if (!strcmp(value
, "remote")) {
498 *local_access
= FALSE
;
499 *remote_access
= TRUE
;
500 } else if (!strcmp(value
, "local,remote")) {
501 *local_access
= TRUE
;
502 *remote_access
= TRUE
;
509 /* Frees dead client connections. */
510 static void cleanup_cb(pa_mainloop_api
*a
, pa_defer_event
*e
, void *userdata
) {
511 struct userdata
*u
= userdata
;
512 struct connection
*conn
= NULL
;
515 PA_IDXSET_FOREACH(conn
, u
->connections
, idx
) {
516 if (!dbus_connection_get_is_connected(pa_dbus_wrap_connection_get(conn
->wrap_conn
))) {
517 pa_idxset_remove_by_data(u
->connections
, conn
, NULL
);
518 connection_free(conn
);
522 u
->module
->core
->mainloop
->defer_enable(e
, 0);
525 int pa__init(pa_module
*m
) {
526 struct userdata
*u
= NULL
;
527 pa_modargs
*ma
= NULL
;
531 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
532 pa_log("Failed to parse module arguments.");
536 m
->userdata
= u
= pa_xnew0(struct userdata
, 1);
538 u
->local_access
= TRUE
;
539 u
->remote_access
= FALSE
;
540 u
->tcp_port
= PA_DBUS_DEFAULT_PORT
;
542 if (get_access_arg(ma
, &u
->local_access
, &u
->remote_access
) < 0) {
543 pa_log("Invalid access argument: '%s'", pa_modargs_get_value(ma
, "access", NULL
));
547 if (pa_modargs_get_value_u32(ma
, "tcp_port", &u
->tcp_port
) < 0 || u
->tcp_port
< 1 || u
->tcp_port
> 49150) {
548 pa_log("Invalid tcp_port argument: '%s'", pa_modargs_get_value(ma
, "tcp_port", NULL
));
552 u
->tcp_listen
= pa_xstrdup(pa_modargs_get_value(ma
, "tcp_listen", "0.0.0.0"));
554 if (u
->local_access
&& !(u
->local_server
= start_local_server(u
))) {
555 pa_log("Starting the local D-Bus server failed.");
559 if (u
->remote_access
&& !(u
->tcp_server
= start_tcp_server(u
))) {
560 pa_log("Starting the D-Bus server for remote connections failed.");
564 u
->connections
= pa_idxset_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
566 u
->cleanup_event
= m
->core
->mainloop
->defer_new(m
->core
->mainloop
, cleanup_cb
, u
);
567 m
->core
->mainloop
->defer_enable(u
->cleanup_event
, 0);
569 u
->dbus_protocol
= pa_dbus_protocol_get(m
->core
);
570 u
->core_iface
= pa_dbusiface_core_new(m
->core
);
585 void pa__done(pa_module
*m
) {
587 struct connection
*c
;
591 if (!(u
= m
->userdata
))
595 pa_dbusiface_core_free(u
->core_iface
);
597 while ((c
= pa_idxset_steal_first(u
->connections
, NULL
)))
600 pa_idxset_free(u
->connections
, NULL
, NULL
);
602 /* This must not be called before the connections are freed, because if
603 * there are any connections left, they will emit the
604 * org.freedesktop.DBus.Local.Disconnected signal, and
605 * disconnection_filter_cb() will be called. disconnection_filter_cb() then
606 * tries to enable the defer event, and if it's already freed, an assertion
607 * will be hit in mainloop.c. */
608 if (u
->cleanup_event
)
609 m
->core
->mainloop
->defer_free(u
->cleanup_event
);
612 server_free(u
->tcp_server
);
615 server_free(u
->local_server
);
617 if (u
->dbus_protocol
)
618 pa_dbus_protocol_unref(u
->dbus_protocol
);
620 pa_xfree(u
->tcp_listen
);