1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2009 Tanu Kaskinen
5 Copyright 2006 Lennart Poettering
6 Copyright 2006 Shams E. King
7
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.
12
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.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <dbus/dbus.h>
27
28 #include <pulse/mainloop-api.h>
29 #include <pulse/timeval.h>
30 #include <pulse/xmalloc.h>
31
32 #include <pulsecore/client.h>
33 #include <pulsecore/core-util.h>
34 #include <pulsecore/dbus-util.h>
35 #include <pulsecore/idxset.h>
36 #include <pulsecore/macro.h>
37 #include <pulsecore/modargs.h>
38 #include <pulsecore/module.h>
39 #include <pulsecore/protocol-dbus.h>
40
41 #include "iface-client.h"
42 #include "iface-core.h"
43
44 PA_MODULE_DESCRIPTION("D-Bus interface");
45 PA_MODULE_USAGE(
46 "access=local|remote|local,remote "
47 "tcp_port=<port number> "
48 "tcp_listen=<hostname>");
49 PA_MODULE_LOAD_ONCE(true);
50 PA_MODULE_AUTHOR("Tanu Kaskinen");
51 PA_MODULE_VERSION(PACKAGE_VERSION);
52
53 enum server_type {
54 SERVER_TYPE_LOCAL,
55 SERVER_TYPE_TCP
56 };
57
58 struct server;
59 struct connection;
60
61 struct userdata {
62 pa_module *module;
63 bool local_access;
64 bool remote_access;
65 uint32_t tcp_port;
66 char *tcp_listen;
67
68 struct server *local_server;
69 struct server *tcp_server;
70
71 pa_idxset *connections;
72
73 pa_defer_event *cleanup_event;
74
75 pa_dbus_protocol *dbus_protocol;
76 pa_dbusiface_core *core_iface;
77 };
78
79 struct server {
80 struct userdata *userdata;
81 enum server_type type;
82 DBusServer *dbus_server;
83 };
84
85 struct connection {
86 struct server *server;
87 pa_dbus_wrap_connection *wrap_conn;
88 pa_client *client;
89 };
90
91 static const char* const valid_modargs[] = {
92 "access",
93 "tcp_port",
94 "tcp_listen",
95 NULL
96 };
97
connection_free(struct connection * c)98 static void connection_free(struct connection *c) {
99 pa_assert(c);
100
101 pa_assert_se(pa_dbus_protocol_unregister_connection(c->server->userdata->dbus_protocol, pa_dbus_wrap_connection_get(c->wrap_conn)) >= 0);
102
103 pa_client_free(c->client);
104 pa_dbus_wrap_connection_free(c->wrap_conn);
105 pa_xfree(c);
106 }
107
108 /* Called from pa_client_kill(). */
client_kill_cb(pa_client * c)109 static void client_kill_cb(pa_client *c) {
110 struct connection *conn;
111
112 pa_assert(c);
113 pa_assert(c->userdata);
114
115 conn = c->userdata;
116 pa_idxset_remove_by_data(conn->server->userdata->connections, conn, NULL);
117 connection_free(conn);
118 c->userdata = NULL;
119
120 pa_log_info("Connection killed.");
121 }
122
123 /* Called from pa_client_send_event(). */
client_send_event_cb(pa_client * c,const char * name,pa_proplist * data)124 static void client_send_event_cb(pa_client *c, const char *name, pa_proplist *data) {
125 struct connection *conn = NULL;
126 DBusMessage *signal_msg = NULL;
127 DBusMessageIter msg_iter;
128
129 pa_assert(c);
130 pa_assert(name);
131 pa_assert(data);
132 pa_assert(c->userdata);
133
134 conn = c->userdata;
135
136 pa_assert_se(signal_msg = dbus_message_new_signal(pa_dbusiface_core_get_client_path(conn->server->userdata->core_iface, c),
137 PA_DBUSIFACE_CLIENT_INTERFACE,
138 "ClientEvent"));
139 dbus_message_iter_init_append(signal_msg, &msg_iter);
140 pa_assert_se(dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name));
141 pa_dbus_append_proplist(&msg_iter, data);
142
143 pa_assert_se(dbus_connection_send(pa_dbus_wrap_connection_get(conn->wrap_conn), signal_msg, NULL));
144 dbus_message_unref(signal_msg);
145 }
146
147 /* Called by D-Bus at the authentication phase. */
user_check_cb(DBusConnection * connection,unsigned long uid,void * data)148 static dbus_bool_t user_check_cb(DBusConnection *connection, unsigned long uid, void *data) {
149 pa_log_debug("Allowing connection by user %lu.", uid);
150
151 return TRUE;
152 }
153
disconnection_filter_cb(DBusConnection * connection,DBusMessage * message,void * user_data)154 static DBusHandlerResult disconnection_filter_cb(DBusConnection *connection, DBusMessage *message, void *user_data) {
155 struct connection *c = user_data;
156
157 pa_assert(connection);
158 pa_assert(message);
159 pa_assert(c);
160
161 if (dbus_message_is_signal(message, "org.freedesktop.DBus.Local", "Disconnected")) {
162 /* The connection died. Now we want to free the connection object, but
163 * let's wait until this message is fully processed, in case someone
164 * else is interested in this signal too. */
165 c->server->userdata->module->core->mainloop->defer_enable(c->server->userdata->cleanup_event, 1);
166 }
167
168 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
169 }
170
171 /* Called by D-Bus when a new client connection is received. */
connection_new_cb(DBusServer * dbus_server,DBusConnection * new_connection,void * data)172 static void connection_new_cb(DBusServer *dbus_server, DBusConnection *new_connection, void *data) {
173 struct server *s = data;
174 struct connection *c;
175 pa_client_new_data new_data;
176 pa_client *client;
177
178 pa_assert(new_connection);
179 pa_assert(s);
180
181 pa_client_new_data_init(&new_data);
182 new_data.module = s->userdata->module;
183 new_data.driver = __FILE__;
184 pa_proplist_sets(new_data.proplist, PA_PROP_APPLICATION_NAME, "D-Bus client");
185 client = pa_client_new(s->userdata->module->core, &new_data);
186 pa_client_new_data_done(&new_data);
187
188 if (!client) {
189 dbus_connection_close(new_connection);
190 return;
191 }
192
193 if (s->type == SERVER_TYPE_TCP || s->userdata->module->core->server_type == PA_SERVER_TYPE_SYSTEM) {
194 /* FIXME: Here we allow anyone from anywhere to access the server,
195 * anonymously. Access control should be configurable. */
196 dbus_connection_set_unix_user_function(new_connection, user_check_cb, NULL, NULL);
197 dbus_connection_set_allow_anonymous(new_connection, TRUE);
198 }
199
200 c = pa_xnew(struct connection, 1);
201 c->server = s;
202 c->wrap_conn = pa_dbus_wrap_connection_new_from_existing(s->userdata->module->core->mainloop, true, new_connection);
203 c->client = client;
204
205 c->client->kill = client_kill_cb;
206 c->client->send_event = client_send_event_cb;
207 c->client->userdata = c;
208
209 pa_assert_se(dbus_connection_add_filter(new_connection, disconnection_filter_cb, c, NULL));
210
211 pa_idxset_put(s->userdata->connections, c, NULL);
212
213 pa_assert_se(pa_dbus_protocol_register_connection(s->userdata->dbus_protocol, new_connection, c->client) >= 0);
214 }
215
216 /* Called by PA mainloop when a D-Bus fd watch event needs handling. */
io_event_cb(pa_mainloop_api * mainloop,pa_io_event * e,int fd,pa_io_event_flags_t events,void * userdata)217 static void io_event_cb(pa_mainloop_api *mainloop, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
218 unsigned int flags = 0;
219 DBusWatch *watch = userdata;
220
221 pa_assert(fd == dbus_watch_get_unix_fd(watch));
222
223 if (!dbus_watch_get_enabled(watch)) {
224 pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch, fd);
225 return;
226 }
227
228 if (events & PA_IO_EVENT_INPUT)
229 flags |= DBUS_WATCH_READABLE;
230 if (events & PA_IO_EVENT_OUTPUT)
231 flags |= DBUS_WATCH_WRITABLE;
232 if (events & PA_IO_EVENT_HANGUP)
233 flags |= DBUS_WATCH_HANGUP;
234 if (events & PA_IO_EVENT_ERROR)
235 flags |= DBUS_WATCH_ERROR;
236
237 dbus_watch_handle(watch, flags);
238 }
239
240 /* Called by PA mainloop when a D-Bus timer event needs handling. */
time_event_cb(pa_mainloop_api * mainloop,pa_time_event * e,const struct timeval * tv,void * userdata)241 static void time_event_cb(pa_mainloop_api *mainloop, pa_time_event* e, const struct timeval *tv, void *userdata) {
242 DBusTimeout *timeout = userdata;
243
244 if (dbus_timeout_get_enabled(timeout)) {
245 struct timeval next = *tv;
246 dbus_timeout_handle(timeout);
247
248 /* restart it for the next scheduled time */
249 pa_timeval_add(&next, (pa_usec_t) dbus_timeout_get_interval(timeout) * 1000);
250 mainloop->time_restart(e, &next);
251 }
252 }
253
254 /* Translates D-Bus fd watch event flags to PA IO event flags. */
get_watch_flags(DBusWatch * watch)255 static pa_io_event_flags_t get_watch_flags(DBusWatch *watch) {
256 unsigned int flags;
257 pa_io_event_flags_t events = 0;
258
259 pa_assert(watch);
260
261 flags = dbus_watch_get_flags(watch);
262
263 /* no watch flags for disabled watches */
264 if (!dbus_watch_get_enabled(watch))
265 return PA_IO_EVENT_NULL;
266
267 if (flags & DBUS_WATCH_READABLE)
268 events |= PA_IO_EVENT_INPUT;
269 if (flags & DBUS_WATCH_WRITABLE)
270 events |= PA_IO_EVENT_OUTPUT;
271
272 return events | PA_IO_EVENT_HANGUP | PA_IO_EVENT_ERROR;
273 }
274
275 /* Called by D-Bus when a D-Bus fd watch event is added. */
watch_add_cb(DBusWatch * watch,void * data)276 static dbus_bool_t watch_add_cb(DBusWatch *watch, void *data) {
277 struct server *s = data;
278 pa_mainloop_api *mainloop;
279 pa_io_event *ev;
280
281 pa_assert(watch);
282 pa_assert(s);
283
284 mainloop = s->userdata->module->core->mainloop;
285
286 ev = mainloop->io_new(
287 mainloop,
288 dbus_watch_get_unix_fd(watch),
289 get_watch_flags(watch), io_event_cb, watch);
290
291 dbus_watch_set_data(watch, ev, NULL);
292
293 return TRUE;
294 }
295
296 /* Called by D-Bus when a D-Bus fd watch event is removed. */
watch_remove_cb(DBusWatch * watch,void * data)297 static void watch_remove_cb(DBusWatch *watch, void *data) {
298 struct server *s = data;
299 pa_io_event *ev;
300
301 pa_assert(watch);
302 pa_assert(s);
303
304 if ((ev = dbus_watch_get_data(watch)))
305 s->userdata->module->core->mainloop->io_free(ev);
306 }
307
308 /* Called by D-Bus when a D-Bus fd watch event is toggled. */
watch_toggled_cb(DBusWatch * watch,void * data)309 static void watch_toggled_cb(DBusWatch *watch, void *data) {
310 struct server *s = data;
311 pa_io_event *ev;
312
313 pa_assert(watch);
314 pa_assert(s);
315
316 pa_assert_se(ev = dbus_watch_get_data(watch));
317
318 /* get_watch_flags() checks if the watch is enabled */
319 s->userdata->module->core->mainloop->io_enable(ev, get_watch_flags(watch));
320 }
321
322 /* Called by D-Bus when a D-Bus timer event is added. */
timeout_add_cb(DBusTimeout * timeout,void * data)323 static dbus_bool_t timeout_add_cb(DBusTimeout *timeout, void *data) {
324 struct server *s = data;
325 pa_mainloop_api *mainloop;
326 pa_time_event *ev;
327 struct timeval tv;
328
329 pa_assert(timeout);
330 pa_assert(s);
331
332 if (!dbus_timeout_get_enabled(timeout))
333 return FALSE;
334
335 mainloop = s->userdata->module->core->mainloop;
336
337 pa_gettimeofday(&tv);
338 pa_timeval_add(&tv, (pa_usec_t) dbus_timeout_get_interval(timeout) * 1000);
339
340 ev = mainloop->time_new(mainloop, &tv, time_event_cb, timeout);
341
342 dbus_timeout_set_data(timeout, ev, NULL);
343
344 return TRUE;
345 }
346
347 /* Called by D-Bus when a D-Bus timer event is removed. */
timeout_remove_cb(DBusTimeout * timeout,void * data)348 static void timeout_remove_cb(DBusTimeout *timeout, void *data) {
349 struct server *s = data;
350 pa_time_event *ev;
351
352 pa_assert(timeout);
353 pa_assert(s);
354
355 if ((ev = dbus_timeout_get_data(timeout)))
356 s->userdata->module->core->mainloop->time_free(ev);
357 }
358
359 /* Called by D-Bus when a D-Bus timer event is toggled. */
timeout_toggled_cb(DBusTimeout * timeout,void * data)360 static void timeout_toggled_cb(DBusTimeout *timeout, void *data) {
361 struct server *s = data;
362 pa_mainloop_api *mainloop;
363 pa_time_event *ev;
364
365 pa_assert(timeout);
366 pa_assert(s);
367
368 mainloop = s->userdata->module->core->mainloop;
369
370 pa_assert_se(ev = dbus_timeout_get_data(timeout));
371
372 if (dbus_timeout_get_enabled(timeout)) {
373 struct timeval tv;
374
375 pa_gettimeofday(&tv);
376 pa_timeval_add(&tv, (pa_usec_t) dbus_timeout_get_interval(timeout) * 1000);
377
378 mainloop->time_restart(ev, &tv);
379 } else
380 mainloop->time_restart(ev, NULL);
381 }
382
server_free(struct server * s)383 static void server_free(struct server *s) {
384 pa_assert(s);
385
386 if (s->dbus_server) {
387 dbus_server_disconnect(s->dbus_server);
388 dbus_server_unref(s->dbus_server);
389 }
390
391 pa_xfree(s);
392 }
393
start_server(struct userdata * u,const char * address,enum server_type type)394 static struct server *start_server(struct userdata *u, const char *address, enum server_type type) {
395 /* XXX: We assume that when we unref the DBusServer instance at module
396 * shutdown, nobody else holds any references to it. If we stop assuming
397 * that someday, dbus_server_set_new_connection_function,
398 * dbus_server_set_watch_functions and dbus_server_set_timeout_functions
399 * calls should probably register free callbacks, instead of providing NULL
400 * as they do now. */
401
402 struct server *s = NULL;
403 DBusError error;
404
405 pa_assert(u);
406 pa_assert(address);
407
408 dbus_error_init(&error);
409
410 s = pa_xnew0(struct server, 1);
411 s->userdata = u;
412 s->type = type;
413 s->dbus_server = dbus_server_listen(address, &error);
414
415 if (dbus_error_is_set(&error)) {
416 pa_log("dbus_server_listen() failed: %s: %s", error.name, error.message);
417 goto fail;
418 }
419
420 dbus_server_set_new_connection_function(s->dbus_server, connection_new_cb, s, NULL);
421
422 if (!dbus_server_set_watch_functions(s->dbus_server, watch_add_cb, watch_remove_cb, watch_toggled_cb, s, NULL)) {
423 pa_log("dbus_server_set_watch_functions() ran out of memory.");
424 goto fail;
425 }
426
427 if (!dbus_server_set_timeout_functions(s->dbus_server, timeout_add_cb, timeout_remove_cb, timeout_toggled_cb, s, NULL)) {
428 pa_log("dbus_server_set_timeout_functions() ran out of memory.");
429 goto fail;
430 }
431
432 return s;
433
434 fail:
435 if (s)
436 server_free(s);
437
438 dbus_error_free(&error);
439
440 return NULL;
441 }
442
start_local_server(struct userdata * u)443 static struct server *start_local_server(struct userdata *u) {
444 struct server *s = NULL;
445 char *address = NULL;
446
447 pa_assert(u);
448
449 address = pa_get_dbus_address_from_server_type(u->module->core->server_type);
450
451 s = start_server(u, address, SERVER_TYPE_LOCAL); /* May return NULL */
452
453 pa_xfree(address);
454
455 return s;
456 }
457
start_tcp_server(struct userdata * u)458 static struct server *start_tcp_server(struct userdata *u) {
459 struct server *s = NULL;
460 char *address = NULL;
461
462 pa_assert(u);
463
464 address = pa_sprintf_malloc("tcp:host=%s,port=%u", u->tcp_listen, u->tcp_port);
465
466 s = start_server(u, address, SERVER_TYPE_TCP); /* May return NULL */
467
468 pa_xfree(address);
469
470 return s;
471 }
472
get_access_arg(pa_modargs * ma,bool * local_access,bool * remote_access)473 static int get_access_arg(pa_modargs *ma, bool *local_access, bool *remote_access) {
474 const char *value = NULL;
475
476 pa_assert(ma);
477 pa_assert(local_access);
478 pa_assert(remote_access);
479
480 if (!(value = pa_modargs_get_value(ma, "access", NULL)))
481 return 0;
482
483 if (pa_streq(value, "local")) {
484 *local_access = true;
485 *remote_access = false;
486 } else if (pa_streq(value, "remote")) {
487 *local_access = false;
488 *remote_access = true;
489 } else if (pa_streq(value, "local,remote")) {
490 *local_access = true;
491 *remote_access = true;
492 } else
493 return -1;
494
495 return 0;
496 }
497
498 /* Frees dead client connections. */
cleanup_cb(pa_mainloop_api * a,pa_defer_event * e,void * userdata)499 static void cleanup_cb(pa_mainloop_api *a, pa_defer_event *e, void *userdata) {
500 struct userdata *u = userdata;
501 struct connection *conn = NULL;
502 uint32_t idx;
503
504 PA_IDXSET_FOREACH(conn, u->connections, idx) {
505 if (!dbus_connection_get_is_connected(pa_dbus_wrap_connection_get(conn->wrap_conn))) {
506 pa_idxset_remove_by_data(u->connections, conn, NULL);
507 connection_free(conn);
508 }
509 }
510
511 u->module->core->mainloop->defer_enable(e, 0);
512 }
513
pa__init(pa_module * m)514 int pa__init(pa_module *m) {
515 struct userdata *u = NULL;
516 pa_modargs *ma = NULL;
517
518 pa_assert(m);
519
520 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
521 pa_log("Failed to parse module arguments.");
522 goto fail;
523 }
524
525 m->userdata = u = pa_xnew0(struct userdata, 1);
526 u->module = m;
527 u->local_access = true;
528 u->remote_access = false;
529 u->tcp_port = PA_DBUS_DEFAULT_PORT;
530
531 if (get_access_arg(ma, &u->local_access, &u->remote_access) < 0) {
532 pa_log("Invalid access argument: '%s'", pa_modargs_get_value(ma, "access", NULL));
533 goto fail;
534 }
535
536 if (pa_modargs_get_value_u32(ma, "tcp_port", &u->tcp_port) < 0 || u->tcp_port < 1 || u->tcp_port > 49150) {
537 pa_log("Invalid tcp_port argument: '%s'", pa_modargs_get_value(ma, "tcp_port", NULL));
538 goto fail;
539 }
540
541 u->tcp_listen = pa_xstrdup(pa_modargs_get_value(ma, "tcp_listen", "0.0.0.0"));
542
543 if (u->local_access && !(u->local_server = start_local_server(u))) {
544 pa_log("Starting the local D-Bus server failed.");
545 goto fail;
546 }
547
548 if (u->remote_access && !(u->tcp_server = start_tcp_server(u))) {
549 pa_log("Starting the D-Bus server for remote connections failed.");
550 goto fail;
551 }
552
553 u->connections = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
554
555 u->cleanup_event = m->core->mainloop->defer_new(m->core->mainloop, cleanup_cb, u);
556 m->core->mainloop->defer_enable(u->cleanup_event, 0);
557
558 u->dbus_protocol = pa_dbus_protocol_get(m->core);
559 u->core_iface = pa_dbusiface_core_new(m->core);
560
561 pa_modargs_free(ma);
562
563 return 0;
564
565 fail:
566 if (ma)
567 pa_modargs_free(ma);
568
569 pa__done(m);
570
571 return -1;
572 }
573
pa__done(pa_module * m)574 void pa__done(pa_module *m) {
575 struct userdata *u;
576
577 pa_assert(m);
578
579 if (!(u = m->userdata))
580 return;
581
582 if (u->core_iface)
583 pa_dbusiface_core_free(u->core_iface);
584
585 if (u->connections)
586 pa_idxset_free(u->connections, (pa_free_cb_t) connection_free);
587
588 /* This must not be called before the connections are freed, because if
589 * there are any connections left, they will emit the
590 * org.freedesktop.DBus.Local.Disconnected signal, and
591 * disconnection_filter_cb() will be called. disconnection_filter_cb() then
592 * tries to enable the defer event, and if it's already freed, an assertion
593 * will be hit in mainloop.c. */
594 if (u->cleanup_event)
595 m->core->mainloop->defer_free(u->cleanup_event);
596
597 if (u->tcp_server)
598 server_free(u->tcp_server);
599
600 if (u->local_server)
601 server_free(u->local_server);
602
603 if (u->dbus_protocol)
604 pa_dbus_protocol_unref(u->dbus_protocol);
605
606 pa_xfree(u->tcp_listen);
607 pa_xfree(u);
608 m->userdata = NULL;
609 }
610