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 44PA_MODULE_DESCRIPTION("D-Bus interface"); 45PA_MODULE_USAGE( 46 "access=local|remote|local,remote " 47 "tcp_port=<port number> " 48 "tcp_listen=<hostname>"); 49PA_MODULE_LOAD_ONCE(true); 50PA_MODULE_AUTHOR("Tanu Kaskinen"); 51PA_MODULE_VERSION(PACKAGE_VERSION); 52 53enum server_type { 54 SERVER_TYPE_LOCAL, 55 SERVER_TYPE_TCP 56}; 57 58struct server; 59struct connection; 60 61struct 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 79struct server { 80 struct userdata *userdata; 81 enum server_type type; 82 DBusServer *dbus_server; 83}; 84 85struct connection { 86 struct server *server; 87 pa_dbus_wrap_connection *wrap_conn; 88 pa_client *client; 89}; 90 91static const char* const valid_modargs[] = { 92 "access", 93 "tcp_port", 94 "tcp_listen", 95 NULL 96}; 97 98static 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(). */ 109static 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(). */ 124static 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. */ 148static 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 154static 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, DBUS_INTERFACE_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. */ 172static 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. */ 217static 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. */ 241static 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. */ 255static 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. */ 276static 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. */ 297static 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. */ 309static 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. */ 323static 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. */ 348static 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. */ 360static 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 383static 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 394static 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 434fail: 435 if (s) 436 server_free(s); 437 438 dbus_error_free(&error); 439 440 return NULL; 441} 442 443static 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 458static 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 473static 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. */ 499static 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 514int 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 565fail: 566 if (ma) 567 pa_modargs_free(ma); 568 569 pa__done(m); 570 571 return -1; 572} 573 574void 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