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