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