• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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