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