Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2006 Lennart Poettering
5 : : Copyright 2006 Shams E. King
6 : :
7 : : PulseAudio is free software; you can redistribute it and/or modify
8 : : it under the terms of the GNU Lesser General Public License as published
9 : : by the Free Software Foundation; either version 2.1 of the License,
10 : : or (at your option) any later version.
11 : :
12 : : PulseAudio is distributed in the hope that it will be useful, but
13 : : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : General Public License for more details.
16 : :
17 : : You should have received a copy of the GNU Lesser General Public License
18 : : along with PulseAudio; if not, write to the Free Software
19 : : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 : : USA.
21 : : ***/
22 : :
23 : : #ifdef HAVE_CONFIG_H
24 : : #include <config.h>
25 : : #endif
26 : :
27 : : #include <stdarg.h>
28 : :
29 : : #include <pulse/rtclock.h>
30 : : #include <pulse/timeval.h>
31 : : #include <pulse/utf8.h>
32 : : #include <pulse/xmalloc.h>
33 : :
34 : : #include <pulsecore/core-rtclock.h>
35 : : #include <pulsecore/core-util.h>
36 : : #include <pulsecore/log.h>
37 : :
38 : : #include "dbus-util.h"
39 : :
40 : : struct pa_dbus_wrap_connection {
41 : : pa_mainloop_api *mainloop;
42 : : DBusConnection *connection;
43 : : pa_defer_event* dispatch_event;
44 : : pa_bool_t use_rtclock:1;
45 : : };
46 : :
47 : : struct timeout_data {
48 : : pa_dbus_wrap_connection *connection;
49 : : DBusTimeout *timeout;
50 : : };
51 : :
52 : 0 : static void dispatch_cb(pa_mainloop_api *ea, pa_defer_event *ev, void *userdata) {
53 : 0 : DBusConnection *conn = userdata;
54 : :
55 [ # # ]: 0 : if (dbus_connection_dispatch(conn) == DBUS_DISPATCH_COMPLETE)
56 : : /* no more data to process, disable the deferred */
57 : 0 : ea->defer_enable(ev, 0);
58 : 0 : }
59 : :
60 : : /* DBusDispatchStatusFunction callback for the pa mainloop */
61 : 0 : static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status, void *userdata) {
62 : 0 : pa_dbus_wrap_connection *c = userdata;
63 : :
64 [ # # ]: 0 : pa_assert(c);
65 : :
66 [ # # ]: 0 : switch(status) {
67 : :
68 : : case DBUS_DISPATCH_COMPLETE:
69 : 0 : c->mainloop->defer_enable(c->dispatch_event, 0);
70 : 0 : break;
71 : :
72 : : case DBUS_DISPATCH_DATA_REMAINS:
73 : : case DBUS_DISPATCH_NEED_MEMORY:
74 : : default:
75 : 0 : c->mainloop->defer_enable(c->dispatch_event, 1);
76 : 0 : break;
77 : : }
78 : 0 : }
79 : :
80 : 0 : static pa_io_event_flags_t get_watch_flags(DBusWatch *watch) {
81 : : unsigned int flags;
82 : 0 : pa_io_event_flags_t events = 0;
83 : :
84 [ # # ]: 0 : pa_assert(watch);
85 : :
86 : 0 : flags = dbus_watch_get_flags(watch);
87 : :
88 : : /* no watch flags for disabled watches */
89 [ # # ]: 0 : if (!dbus_watch_get_enabled(watch))
90 : : return PA_IO_EVENT_NULL;
91 : :
92 [ # # ]: 0 : if (flags & DBUS_WATCH_READABLE)
93 : 0 : events |= PA_IO_EVENT_INPUT;
94 [ # # ]: 0 : if (flags & DBUS_WATCH_WRITABLE)
95 : 0 : events |= PA_IO_EVENT_OUTPUT;
96 : :
97 : 0 : return events | PA_IO_EVENT_HANGUP | PA_IO_EVENT_ERROR;
98 : : }
99 : :
100 : : /* pa_io_event_cb_t IO event handler */
101 : 0 : static void handle_io_event(pa_mainloop_api *ea, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
102 : 0 : unsigned int flags = 0;
103 : 0 : DBusWatch *watch = userdata;
104 : :
105 : : #if HAVE_DBUS_WATCH_GET_UNIX_FD
106 [ # # ]: 0 : pa_assert(fd == dbus_watch_get_unix_fd(watch));
107 : : #else
108 : : pa_assert(fd == dbus_watch_get_fd(watch));
109 : : #endif
110 : :
111 [ # # ]: 0 : if (!dbus_watch_get_enabled(watch)) {
112 : 0 : pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch, fd);
113 : 0 : return;
114 : : }
115 : :
116 [ # # ]: 0 : if (events & PA_IO_EVENT_INPUT)
117 : 0 : flags |= DBUS_WATCH_READABLE;
118 [ # # ]: 0 : if (events & PA_IO_EVENT_OUTPUT)
119 : 0 : flags |= DBUS_WATCH_WRITABLE;
120 [ # # ]: 0 : if (events & PA_IO_EVENT_HANGUP)
121 : 0 : flags |= DBUS_WATCH_HANGUP;
122 [ # # ]: 0 : if (events & PA_IO_EVENT_ERROR)
123 : 0 : flags |= DBUS_WATCH_ERROR;
124 : :
125 : 0 : dbus_watch_handle(watch, flags);
126 : : }
127 : :
128 : : /* pa_time_event_cb_t timer event handler */
129 : 0 : static void handle_time_event(pa_mainloop_api *ea, pa_time_event* e, const struct timeval *t, void *userdata) {
130 : : struct timeval tv;
131 : 0 : struct timeout_data *d = userdata;
132 : :
133 [ # # ]: 0 : pa_assert(d);
134 [ # # ]: 0 : pa_assert(d->connection);
135 : :
136 [ # # ]: 0 : if (dbus_timeout_get_enabled(d->timeout)) {
137 : : /* Restart it for the next scheduled time. We do this before
138 : : * calling dbus_timeout_handle() to make sure that the time
139 : : * event is still around. */
140 : 0 : ea->time_restart(e, pa_timeval_rtstore(&tv,
141 : 0 : pa_timeval_load(t) + dbus_timeout_get_interval(d->timeout) * PA_USEC_PER_MSEC,
142 : 0 : d->connection->use_rtclock));
143 : :
144 : 0 : dbus_timeout_handle(d->timeout);
145 : : }
146 : 0 : }
147 : :
148 : : /* DBusAddWatchFunction callback for pa mainloop */
149 : 0 : static dbus_bool_t add_watch(DBusWatch *watch, void *data) {
150 : 0 : pa_dbus_wrap_connection *c = data;
151 : : pa_io_event *ev;
152 : :
153 [ # # ]: 0 : pa_assert(watch);
154 [ # # ]: 0 : pa_assert(c);
155 : :
156 : 0 : ev = c->mainloop->io_new(
157 : : c->mainloop,
158 : : #if HAVE_DBUS_WATCH_GET_UNIX_FD
159 : : dbus_watch_get_unix_fd(watch),
160 : : #else
161 : : dbus_watch_get_fd(watch),
162 : : #endif
163 : : get_watch_flags(watch), handle_io_event, watch);
164 : :
165 : 0 : dbus_watch_set_data(watch, ev, NULL);
166 : :
167 : 0 : return TRUE;
168 : : }
169 : :
170 : : /* DBusRemoveWatchFunction callback for pa mainloop */
171 : 0 : static void remove_watch(DBusWatch *watch, void *data) {
172 : 0 : pa_dbus_wrap_connection *c = data;
173 : : pa_io_event *ev;
174 : :
175 [ # # ]: 0 : pa_assert(watch);
176 [ # # ]: 0 : pa_assert(c);
177 : :
178 [ # # ]: 0 : if ((ev = dbus_watch_get_data(watch)))
179 : 0 : c->mainloop->io_free(ev);
180 : 0 : }
181 : :
182 : : /* DBusWatchToggledFunction callback for pa mainloop */
183 : 0 : static void toggle_watch(DBusWatch *watch, void *data) {
184 : 0 : pa_dbus_wrap_connection *c = data;
185 : : pa_io_event *ev;
186 : :
187 [ # # ]: 0 : pa_assert(watch);
188 [ # # ]: 0 : pa_assert(c);
189 : :
190 [ # # ]: 0 : pa_assert_se(ev = dbus_watch_get_data(watch));
191 : :
192 : : /* get_watch_flags() checks if the watch is enabled */
193 : 0 : c->mainloop->io_enable(ev, get_watch_flags(watch));
194 : 0 : }
195 : :
196 : 0 : static void time_event_destroy_cb(pa_mainloop_api *a, pa_time_event *e, void *userdata) {
197 : 0 : pa_xfree(userdata);
198 : 0 : }
199 : :
200 : : /* DBusAddTimeoutFunction callback for pa mainloop */
201 : 0 : static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) {
202 : 0 : pa_dbus_wrap_connection *c = data;
203 : : pa_time_event *ev;
204 : : struct timeval tv;
205 : : struct timeout_data *d;
206 : :
207 [ # # ]: 0 : pa_assert(timeout);
208 [ # # ]: 0 : pa_assert(c);
209 : :
210 [ # # ]: 0 : if (!dbus_timeout_get_enabled(timeout))
211 : : return FALSE;
212 : :
213 : 0 : d = pa_xnew(struct timeout_data, 1);
214 : 0 : d->connection = c;
215 : 0 : d->timeout = timeout;
216 : 0 : ev = c->mainloop->time_new(c->mainloop, pa_timeval_rtstore(&tv, pa_rtclock_now() + dbus_timeout_get_interval(timeout) * PA_USEC_PER_MSEC, c->use_rtclock), handle_time_event, d);
217 : 0 : c->mainloop->time_set_destroy(ev, time_event_destroy_cb);
218 : :
219 : 0 : dbus_timeout_set_data(timeout, ev, NULL);
220 : :
221 : 0 : return TRUE;
222 : : }
223 : :
224 : : /* DBusRemoveTimeoutFunction callback for pa mainloop */
225 : 0 : static void remove_timeout(DBusTimeout *timeout, void *data) {
226 : 0 : pa_dbus_wrap_connection *c = data;
227 : : pa_time_event *ev;
228 : :
229 [ # # ]: 0 : pa_assert(timeout);
230 [ # # ]: 0 : pa_assert(c);
231 : :
232 [ # # ]: 0 : if ((ev = dbus_timeout_get_data(timeout)))
233 : 0 : c->mainloop->time_free(ev);
234 : 0 : }
235 : :
236 : : /* DBusTimeoutToggledFunction callback for pa mainloop */
237 : 0 : static void toggle_timeout(DBusTimeout *timeout, void *data) {
238 : 0 : struct timeout_data *d = data;
239 : : pa_time_event *ev;
240 : : struct timeval tv;
241 : :
242 [ # # ]: 0 : pa_assert(d);
243 [ # # ]: 0 : pa_assert(d->connection);
244 [ # # ]: 0 : pa_assert(timeout);
245 : :
246 [ # # ]: 0 : pa_assert_se(ev = dbus_timeout_get_data(timeout));
247 : :
248 [ # # ]: 0 : if (dbus_timeout_get_enabled(timeout))
249 : 0 : d->connection->mainloop->time_restart(ev, pa_timeval_rtstore(&tv, pa_rtclock_now() + dbus_timeout_get_interval(timeout) * PA_USEC_PER_MSEC, d->connection->use_rtclock));
250 : : else
251 : 0 : d->connection->mainloop->time_restart(ev, pa_timeval_rtstore(&tv, PA_USEC_INVALID, d->connection->use_rtclock));
252 : 0 : }
253 : :
254 : 0 : static void wakeup_main(void *userdata) {
255 : 0 : pa_dbus_wrap_connection *c = userdata;
256 : :
257 [ # # ]: 0 : pa_assert(c);
258 : :
259 : : /* this will wakeup the mainloop and dispatch events, although
260 : : * it may not be the cleanest way of accomplishing it */
261 : 0 : c->mainloop->defer_enable(c->dispatch_event, 1);
262 : 0 : }
263 : :
264 : 0 : pa_dbus_wrap_connection* pa_dbus_wrap_connection_new(pa_mainloop_api *m, pa_bool_t use_rtclock, DBusBusType type, DBusError *error) {
265 : : DBusConnection *conn;
266 : : pa_dbus_wrap_connection *pconn;
267 : : char *id;
268 : :
269 [ # # ]: 0 : pa_assert(type == DBUS_BUS_SYSTEM || type == DBUS_BUS_SESSION || type == DBUS_BUS_STARTER);
270 : :
271 [ # # ]: 0 : if (!(conn = dbus_bus_get_private(type, error)))
272 : : return NULL;
273 : :
274 : 0 : pconn = pa_xnew(pa_dbus_wrap_connection, 1);
275 : 0 : pconn->mainloop = m;
276 : 0 : pconn->connection = conn;
277 : 0 : pconn->use_rtclock = use_rtclock;
278 : :
279 : 0 : dbus_connection_set_exit_on_disconnect(conn, FALSE);
280 : 0 : dbus_connection_set_dispatch_status_function(conn, dispatch_status, pconn, NULL);
281 : 0 : dbus_connection_set_watch_functions(conn, add_watch, remove_watch, toggle_watch, pconn, NULL);
282 : 0 : dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, toggle_timeout, pconn, NULL);
283 : 0 : dbus_connection_set_wakeup_main_function(conn, wakeup_main, pconn, NULL);
284 : :
285 : 0 : pconn->dispatch_event = pconn->mainloop->defer_new(pconn->mainloop, dispatch_cb, conn);
286 : :
287 [ # # ][ # # ]: 0 : pa_log_debug("Successfully connected to D-Bus %s bus %s as %s",
288 : : type == DBUS_BUS_SYSTEM ? "system" : (type == DBUS_BUS_SESSION ? "session" : "starter"),
289 : : pa_strnull((id = dbus_connection_get_server_id(conn))),
290 : : pa_strnull(dbus_bus_get_unique_name(conn)));
291 : :
292 : 0 : dbus_free(id);
293 : :
294 : 0 : return pconn;
295 : : }
296 : :
297 : 0 : pa_dbus_wrap_connection* pa_dbus_wrap_connection_new_from_existing(
298 : : pa_mainloop_api *m,
299 : : pa_bool_t use_rtclock,
300 : : DBusConnection *conn) {
301 : : pa_dbus_wrap_connection *pconn;
302 : :
303 [ # # ]: 0 : pa_assert(m);
304 [ # # ]: 0 : pa_assert(conn);
305 : :
306 : 0 : pconn = pa_xnew(pa_dbus_wrap_connection, 1);
307 : 0 : pconn->mainloop = m;
308 : 0 : pconn->connection = dbus_connection_ref(conn);
309 : 0 : pconn->use_rtclock = use_rtclock;
310 : :
311 : 0 : dbus_connection_set_exit_on_disconnect(conn, FALSE);
312 : 0 : dbus_connection_set_dispatch_status_function(conn, dispatch_status, pconn, NULL);
313 : 0 : dbus_connection_set_watch_functions(conn, add_watch, remove_watch, toggle_watch, pconn, NULL);
314 : 0 : dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, toggle_timeout, pconn, NULL);
315 : 0 : dbus_connection_set_wakeup_main_function(conn, wakeup_main, pconn, NULL);
316 : :
317 : 0 : pconn->dispatch_event = pconn->mainloop->defer_new(pconn->mainloop, dispatch_cb, conn);
318 : :
319 : 0 : return pconn;
320 : : }
321 : :
322 : 0 : void pa_dbus_wrap_connection_free(pa_dbus_wrap_connection* c) {
323 [ # # ]: 0 : pa_assert(c);
324 : :
325 [ # # ]: 0 : if (dbus_connection_get_is_connected(c->connection)) {
326 : 0 : dbus_connection_close(c->connection);
327 : : /* must process remaining messages, bit of a kludge to handle
328 : : * both unload and shutdown */
329 [ # # ]: 0 : while (dbus_connection_read_write_dispatch(c->connection, -1))
330 : : ;
331 : : }
332 : :
333 : 0 : c->mainloop->defer_free(c->dispatch_event);
334 : 0 : dbus_connection_unref(c->connection);
335 : 0 : pa_xfree(c);
336 : 0 : }
337 : :
338 : 0 : DBusConnection* pa_dbus_wrap_connection_get(pa_dbus_wrap_connection *c) {
339 [ # # ]: 0 : pa_assert(c);
340 [ # # ]: 0 : pa_assert(c->connection);
341 : :
342 : 0 : return c->connection;
343 : : }
344 : :
345 : 0 : int pa_dbus_add_matches(DBusConnection *c, DBusError *error, ...) {
346 : : const char *t;
347 : : va_list ap;
348 : 0 : unsigned k = 0;
349 : :
350 [ # # ]: 0 : pa_assert(c);
351 [ # # ]: 0 : pa_assert(error);
352 : :
353 : 0 : va_start(ap, error);
354 [ # # ][ # # ]: 0 : while ((t = va_arg(ap, const char*))) {
355 : 0 : dbus_bus_add_match(c, t, error);
356 : :
357 [ # # ]: 0 : if (dbus_error_is_set(error))
358 : : goto fail;
359 : :
360 : 0 : k++;
361 : : }
362 : 0 : va_end(ap);
363 : 0 : return 0;
364 : :
365 : : fail:
366 : :
367 : 0 : va_end(ap);
368 : 0 : va_start(ap, error);
369 [ # # ]: 0 : for (; k > 0; k--) {
370 [ # # ][ # # ]: 0 : pa_assert_se(t = va_arg(ap, const char*));
371 : 0 : dbus_bus_remove_match(c, t, NULL);
372 : : }
373 : 0 : va_end(ap);
374 : :
375 : 0 : return -1;
376 : : }
377 : :
378 : 0 : void pa_dbus_remove_matches(DBusConnection *c, ...) {
379 : : const char *t;
380 : : va_list ap;
381 : :
382 [ # # ]: 0 : pa_assert(c);
383 : :
384 : 0 : va_start(ap, c);
385 [ # # ][ # # ]: 0 : while ((t = va_arg(ap, const char*)))
386 : 0 : dbus_bus_remove_match(c, t, NULL);
387 : 0 : va_end(ap);
388 : 0 : }
389 : :
390 : 0 : pa_dbus_pending *pa_dbus_pending_new(
391 : : DBusConnection *c,
392 : : DBusMessage *m,
393 : : DBusPendingCall *pending,
394 : : void *context_data,
395 : : void *call_data) {
396 : :
397 : : pa_dbus_pending *p;
398 : :
399 [ # # ]: 0 : pa_assert(pending);
400 : :
401 : 0 : p = pa_xnew(pa_dbus_pending, 1);
402 : 0 : p->connection = c;
403 : 0 : p->message = m;
404 : 0 : p->pending = pending;
405 : 0 : p->context_data = context_data;
406 : 0 : p->call_data = call_data;
407 : :
408 [ # # ]: 0 : PA_LLIST_INIT(pa_dbus_pending, p);
409 : :
410 : 0 : return p;
411 : : }
412 : :
413 : 0 : void pa_dbus_pending_free(pa_dbus_pending *p) {
414 [ # # ]: 0 : pa_assert(p);
415 : :
416 [ # # ]: 0 : if (p->pending) {
417 : 0 : dbus_pending_call_cancel(p->pending);
418 : 0 : dbus_pending_call_unref(p->pending);
419 : : }
420 : :
421 [ # # ]: 0 : if (p->message)
422 : 0 : dbus_message_unref(p->message);
423 : :
424 : 0 : pa_xfree(p);
425 : 0 : }
426 : :
427 : 0 : void pa_dbus_sync_pending_list(pa_dbus_pending **p) {
428 [ # # ]: 0 : pa_assert(p);
429 : :
430 [ # # ][ # # ]: 0 : while (*p && dbus_connection_read_write_dispatch((*p)->connection, -1))
431 : : ;
432 : 0 : }
433 : :
434 : 0 : void pa_dbus_free_pending_list(pa_dbus_pending **p) {
435 : : pa_dbus_pending *i;
436 : :
437 [ # # ]: 0 : pa_assert(p);
438 : :
439 [ # # ]: 0 : while ((i = *p)) {
440 [ # # ][ # # ]: 0 : PA_LLIST_REMOVE(pa_dbus_pending, *p, i);
[ # # ][ # # ]
441 : 0 : pa_dbus_pending_free(i);
442 : : }
443 : 0 : }
444 : :
445 : 0 : const char *pa_dbus_get_error_message(DBusMessage *m) {
446 : : const char *message;
447 : :
448 [ # # ]: 0 : pa_assert(m);
449 [ # # ]: 0 : pa_assert(dbus_message_get_type(m) == DBUS_MESSAGE_TYPE_ERROR);
450 : :
451 [ # # ]: 0 : if (dbus_message_get_signature(m)[0] != 's')
452 : : return "<no explanation>";
453 : :
454 [ # # ]: 0 : pa_assert_se(dbus_message_get_args(m, NULL, DBUS_TYPE_STRING, &message, DBUS_TYPE_INVALID));
455 : :
456 : 0 : return message;
457 : : }
458 : :
459 : 0 : void pa_dbus_send_error(DBusConnection *c, DBusMessage *in_reply_to, const char *name, const char *format, ...) {
460 : : va_list ap;
461 : : char *message;
462 : 0 : DBusMessage *reply = NULL;
463 : :
464 [ # # ]: 0 : pa_assert(c);
465 [ # # ]: 0 : pa_assert(in_reply_to);
466 [ # # ]: 0 : pa_assert(name);
467 [ # # ]: 0 : pa_assert(format);
468 : :
469 : 0 : va_start(ap, format);
470 : 0 : message = pa_vsprintf_malloc(format, ap);
471 : 0 : va_end(ap);
472 [ # # ]: 0 : pa_assert_se((reply = dbus_message_new_error(in_reply_to, name, message)));
473 [ # # ]: 0 : pa_assert_se(dbus_connection_send(c, reply, NULL));
474 : :
475 : 0 : dbus_message_unref(reply);
476 : :
477 : 0 : pa_xfree(message);
478 : 0 : }
479 : :
480 : 0 : void pa_dbus_send_empty_reply(DBusConnection *c, DBusMessage *in_reply_to) {
481 : 0 : DBusMessage *reply = NULL;
482 : :
483 [ # # ]: 0 : pa_assert(c);
484 [ # # ]: 0 : pa_assert(in_reply_to);
485 : :
486 [ # # ]: 0 : pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
487 [ # # ]: 0 : pa_assert_se(dbus_connection_send(c, reply, NULL));
488 : 0 : dbus_message_unref(reply);
489 : 0 : }
490 : :
491 : 0 : void pa_dbus_send_basic_value_reply(DBusConnection *c, DBusMessage *in_reply_to, int type, void *data) {
492 : 0 : DBusMessage *reply = NULL;
493 : :
494 [ # # ]: 0 : pa_assert(c);
495 [ # # ]: 0 : pa_assert(in_reply_to);
496 [ # # ]: 0 : pa_assert(dbus_type_is_basic(type));
497 [ # # ]: 0 : pa_assert(data);
498 : :
499 [ # # ]: 0 : pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
500 [ # # ]: 0 : pa_assert_se(dbus_message_append_args(reply, type, data, DBUS_TYPE_INVALID));
501 [ # # ]: 0 : pa_assert_se(dbus_connection_send(c, reply, NULL));
502 : 0 : dbus_message_unref(reply);
503 : 0 : }
504 : :
505 : 0 : static const char *signature_from_basic_type(int type) {
506 [ # # # # : 0 : switch (type) {
# # # # #
# # # # ]
507 : : case DBUS_TYPE_BOOLEAN: return DBUS_TYPE_BOOLEAN_AS_STRING;
508 : 0 : case DBUS_TYPE_BYTE: return DBUS_TYPE_BYTE_AS_STRING;
509 : 0 : case DBUS_TYPE_INT16: return DBUS_TYPE_INT16_AS_STRING;
510 : 0 : case DBUS_TYPE_UINT16: return DBUS_TYPE_UINT16_AS_STRING;
511 : 0 : case DBUS_TYPE_INT32: return DBUS_TYPE_INT32_AS_STRING;
512 : 0 : case DBUS_TYPE_UINT32: return DBUS_TYPE_UINT32_AS_STRING;
513 : 0 : case DBUS_TYPE_INT64: return DBUS_TYPE_INT64_AS_STRING;
514 : 0 : case DBUS_TYPE_UINT64: return DBUS_TYPE_UINT64_AS_STRING;
515 : 0 : case DBUS_TYPE_DOUBLE: return DBUS_TYPE_DOUBLE_AS_STRING;
516 : 0 : case DBUS_TYPE_STRING: return DBUS_TYPE_STRING_AS_STRING;
517 : 0 : case DBUS_TYPE_OBJECT_PATH: return DBUS_TYPE_OBJECT_PATH_AS_STRING;
518 : 0 : case DBUS_TYPE_SIGNATURE: return DBUS_TYPE_SIGNATURE_AS_STRING;
519 : 0 : default: pa_assert_not_reached();
520 : : }
521 : : }
522 : :
523 : 0 : void pa_dbus_send_basic_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, int type, void *data) {
524 : 0 : DBusMessage *reply = NULL;
525 : : DBusMessageIter msg_iter;
526 : : DBusMessageIter variant_iter;
527 : :
528 [ # # ]: 0 : pa_assert(c);
529 [ # # ]: 0 : pa_assert(in_reply_to);
530 [ # # ]: 0 : pa_assert(dbus_type_is_basic(type));
531 [ # # ]: 0 : pa_assert(data);
532 : :
533 [ # # ]: 0 : pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
534 : 0 : dbus_message_iter_init_append(reply, &msg_iter);
535 [ # # ]: 0 : pa_assert_se(dbus_message_iter_open_container(&msg_iter,
536 : : DBUS_TYPE_VARIANT,
537 : : signature_from_basic_type(type),
538 : : &variant_iter));
539 [ # # ]: 0 : pa_assert_se(dbus_message_iter_append_basic(&variant_iter, type, data));
540 [ # # ]: 0 : pa_assert_se(dbus_message_iter_close_container(&msg_iter, &variant_iter));
541 [ # # ]: 0 : pa_assert_se(dbus_connection_send(c, reply, NULL));
542 : 0 : dbus_message_unref(reply);
543 : 0 : }
544 : :
545 : : /* Note: returns sizeof(char*) for strings, object paths and signatures. */
546 : : static unsigned basic_type_size(int type) {
547 [ # # # # : 0 : switch (type) {
# # # #
# ]
548 : : case DBUS_TYPE_BOOLEAN: return sizeof(dbus_bool_t);
549 : : case DBUS_TYPE_BYTE: return 1;
550 : : case DBUS_TYPE_INT16: return sizeof(dbus_int16_t);
551 : : case DBUS_TYPE_UINT16: return sizeof(dbus_uint16_t);
552 : : case DBUS_TYPE_INT32: return sizeof(dbus_int32_t);
553 : : case DBUS_TYPE_UINT32: return sizeof(dbus_uint32_t);
554 : : case DBUS_TYPE_INT64: return sizeof(dbus_int64_t);
555 : : case DBUS_TYPE_UINT64: return sizeof(dbus_uint64_t);
556 : : case DBUS_TYPE_DOUBLE: return sizeof(double);
557 : : case DBUS_TYPE_STRING:
558 : : case DBUS_TYPE_OBJECT_PATH:
559 : : case DBUS_TYPE_SIGNATURE: return sizeof(char*);
560 : 0 : default: pa_assert_not_reached();
561 : : }
562 : : }
563 : :
564 : 0 : void pa_dbus_send_basic_array_variant_reply(
565 : : DBusConnection *c,
566 : : DBusMessage *in_reply_to,
567 : : int item_type,
568 : : void *array,
569 : : unsigned n) {
570 : 0 : DBusMessage *reply = NULL;
571 : : DBusMessageIter msg_iter;
572 : :
573 [ # # ]: 0 : pa_assert(c);
574 [ # # ]: 0 : pa_assert(in_reply_to);
575 [ # # ]: 0 : pa_assert(dbus_type_is_basic(item_type));
576 [ # # ]: 0 : pa_assert(array || n == 0);
577 : :
578 [ # # ]: 0 : pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
579 : 0 : dbus_message_iter_init_append(reply, &msg_iter);
580 : 0 : pa_dbus_append_basic_array_variant(&msg_iter, item_type, array, n);
581 [ # # ]: 0 : pa_assert_se(dbus_connection_send(c, reply, NULL));
582 : 0 : dbus_message_unref(reply);
583 : 0 : }
584 : :
585 : 0 : void pa_dbus_send_proplist_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, pa_proplist *proplist) {
586 : 0 : DBusMessage *reply = NULL;
587 : : DBusMessageIter msg_iter;
588 : :
589 [ # # ]: 0 : pa_assert(c);
590 [ # # ]: 0 : pa_assert(in_reply_to);
591 [ # # ]: 0 : pa_assert(proplist);
592 : :
593 [ # # ]: 0 : pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
594 : 0 : dbus_message_iter_init_append(reply, &msg_iter);
595 : 0 : pa_dbus_append_proplist_variant(&msg_iter, proplist);
596 [ # # ]: 0 : pa_assert_se(dbus_connection_send(c, reply, NULL));
597 : 0 : dbus_message_unref(reply);
598 : 0 : }
599 : :
600 : 0 : void pa_dbus_append_basic_array(DBusMessageIter *iter, int item_type, const void *array, unsigned n) {
601 : : DBusMessageIter array_iter;
602 : : unsigned i;
603 : : unsigned item_size;
604 : :
605 [ # # ]: 0 : pa_assert(iter);
606 [ # # ]: 0 : pa_assert(dbus_type_is_basic(item_type));
607 [ # # ]: 0 : pa_assert(array || n == 0);
608 : :
609 : 0 : item_size = basic_type_size(item_type);
610 : :
611 [ # # ]: 0 : pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, signature_from_basic_type(item_type), &array_iter));
612 : :
613 [ # # ]: 0 : for (i = 0; i < n; ++i)
614 [ # # ]: 0 : pa_assert_se(dbus_message_iter_append_basic(&array_iter, item_type, &((uint8_t*) array)[i * item_size]));
615 : :
616 [ # # ]: 0 : pa_assert_se(dbus_message_iter_close_container(iter, &array_iter));
617 : 0 : }
618 : :
619 : 0 : void pa_dbus_append_basic_variant(DBusMessageIter *iter, int type, void *data) {
620 : : DBusMessageIter variant_iter;
621 : :
622 [ # # ]: 0 : pa_assert(iter);
623 [ # # ]: 0 : pa_assert(dbus_type_is_basic(type));
624 [ # # ]: 0 : pa_assert(data);
625 : :
626 [ # # ]: 0 : pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, signature_from_basic_type(type), &variant_iter));
627 [ # # ]: 0 : pa_assert_se(dbus_message_iter_append_basic(&variant_iter, type, data));
628 [ # # ]: 0 : pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
629 : 0 : }
630 : :
631 : 0 : void pa_dbus_append_basic_array_variant(DBusMessageIter *iter, int item_type, const void *array, unsigned n) {
632 : : DBusMessageIter variant_iter;
633 : : char *array_signature;
634 : :
635 [ # # ]: 0 : pa_assert(iter);
636 [ # # ]: 0 : pa_assert(dbus_type_is_basic(item_type));
637 [ # # ]: 0 : pa_assert(array || n == 0);
638 : :
639 : 0 : array_signature = pa_sprintf_malloc("a%c", *signature_from_basic_type(item_type));
640 : :
641 [ # # ]: 0 : pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, array_signature, &variant_iter));
642 : 0 : pa_dbus_append_basic_array(&variant_iter, item_type, array, n);
643 [ # # ]: 0 : pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
644 : :
645 : 0 : pa_xfree(array_signature);
646 : 0 : }
647 : :
648 : 0 : void pa_dbus_append_basic_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, int type, void *data) {
649 : : DBusMessageIter dict_entry_iter;
650 : :
651 [ # # ]: 0 : pa_assert(dict_iter);
652 [ # # ]: 0 : pa_assert(key);
653 [ # # ]: 0 : pa_assert(dbus_type_is_basic(type));
654 [ # # ]: 0 : pa_assert(data);
655 : :
656 [ # # ]: 0 : pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
657 [ # # ]: 0 : pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
658 : 0 : pa_dbus_append_basic_variant(&dict_entry_iter, type, data);
659 [ # # ]: 0 : pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
660 : 0 : }
661 : :
662 : 0 : void pa_dbus_append_basic_array_variant_dict_entry(
663 : : DBusMessageIter *dict_iter,
664 : : const char *key,
665 : : int item_type,
666 : : const void *array,
667 : : unsigned n) {
668 : : DBusMessageIter dict_entry_iter;
669 : :
670 [ # # ]: 0 : pa_assert(dict_iter);
671 [ # # ]: 0 : pa_assert(key);
672 [ # # ]: 0 : pa_assert(dbus_type_is_basic(item_type));
673 [ # # ]: 0 : pa_assert(array || n == 0);
674 : :
675 [ # # ]: 0 : pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
676 [ # # ]: 0 : pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
677 : 0 : pa_dbus_append_basic_array_variant(&dict_entry_iter, item_type, array, n);
678 [ # # ]: 0 : pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
679 : 0 : }
680 : :
681 : 0 : void pa_dbus_append_proplist(DBusMessageIter *iter, pa_proplist *proplist) {
682 : : DBusMessageIter dict_iter;
683 : : DBusMessageIter dict_entry_iter;
684 : : DBusMessageIter array_iter;
685 : 0 : void *state = NULL;
686 : : const char *key;
687 : :
688 [ # # ]: 0 : pa_assert(iter);
689 [ # # ]: 0 : pa_assert(proplist);
690 : :
691 [ # # ]: 0 : pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{say}", &dict_iter));
692 : :
693 [ # # ]: 0 : while ((key = pa_proplist_iterate(proplist, &state))) {
694 : 0 : const void *value = NULL;
695 : : size_t nbytes;
696 : :
697 [ # # ]: 0 : pa_assert_se(pa_proplist_get(proplist, key, &value, &nbytes) >= 0);
698 : :
699 [ # # ]: 0 : pa_assert_se(dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
700 : :
701 [ # # ]: 0 : pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
702 : :
703 [ # # ]: 0 : pa_assert_se(dbus_message_iter_open_container(&dict_entry_iter, DBUS_TYPE_ARRAY, "y", &array_iter));
704 [ # # ]: 0 : pa_assert_se(dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, &value, nbytes));
705 [ # # ]: 0 : pa_assert_se(dbus_message_iter_close_container(&dict_entry_iter, &array_iter));
706 : :
707 [ # # ]: 0 : pa_assert_se(dbus_message_iter_close_container(&dict_iter, &dict_entry_iter));
708 : : }
709 : :
710 [ # # ]: 0 : pa_assert_se(dbus_message_iter_close_container(iter, &dict_iter));
711 : 0 : }
712 : :
713 : 0 : void pa_dbus_append_proplist_variant(DBusMessageIter *iter, pa_proplist *proplist) {
714 : : DBusMessageIter variant_iter;
715 : :
716 [ # # ]: 0 : pa_assert(iter);
717 [ # # ]: 0 : pa_assert(proplist);
718 : :
719 [ # # ]: 0 : pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{say}", &variant_iter));
720 : 0 : pa_dbus_append_proplist(&variant_iter, proplist);
721 [ # # ]: 0 : pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
722 : 0 : }
723 : :
724 : 0 : void pa_dbus_append_proplist_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, pa_proplist *proplist) {
725 : : DBusMessageIter dict_entry_iter;
726 : :
727 [ # # ]: 0 : pa_assert(dict_iter);
728 [ # # ]: 0 : pa_assert(key);
729 [ # # ]: 0 : pa_assert(proplist);
730 : :
731 [ # # ]: 0 : pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
732 [ # # ]: 0 : pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
733 : 0 : pa_dbus_append_proplist_variant(&dict_entry_iter, proplist);
734 [ # # ]: 0 : pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
735 : 0 : }
736 : :
737 : 0 : pa_proplist *pa_dbus_get_proplist_arg(DBusConnection *c, DBusMessage *msg, DBusMessageIter *iter) {
738 : : DBusMessageIter dict_iter;
739 : : DBusMessageIter dict_entry_iter;
740 : 0 : pa_proplist *proplist = NULL;
741 : 0 : const char *key = NULL;
742 : 0 : const uint8_t *value = NULL;
743 : 0 : int value_length = 0;
744 : :
745 [ # # ]: 0 : pa_assert(c);
746 [ # # ]: 0 : pa_assert(msg);
747 [ # # ]: 0 : pa_assert(iter);
748 [ # # ]: 0 : pa_assert(pa_streq(dbus_message_iter_get_signature(iter), "a{say}"));
749 : :
750 : 0 : proplist = pa_proplist_new();
751 : :
752 : 0 : dbus_message_iter_recurse(iter, &dict_iter);
753 : :
754 [ # # ]: 0 : while (dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_INVALID) {
755 : 0 : dbus_message_iter_recurse(&dict_iter, &dict_entry_iter);
756 : :
757 : 0 : dbus_message_iter_get_basic(&dict_entry_iter, &key);
758 : 0 : dbus_message_iter_next(&dict_entry_iter);
759 : :
760 [ # # ][ # # ]: 0 : if (strlen(key) <= 0 || !pa_ascii_valid(key)) {
761 : 0 : pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Invalid property list key: '%s'.", key);
762 : 0 : goto fail;
763 : : }
764 : :
765 : 0 : dbus_message_iter_get_fixed_array(&dict_entry_iter, &value, &value_length);
766 : :
767 [ # # ]: 0 : pa_assert(value_length >= 0);
768 : :
769 [ # # ]: 0 : pa_assert_se(pa_proplist_set(proplist, key, value, value_length) >= 0);
770 : :
771 : 0 : dbus_message_iter_next(&dict_iter);
772 : : }
773 : :
774 : 0 : dbus_message_iter_next(iter);
775 : :
776 : 0 : return proplist;
777 : :
778 : : fail:
779 [ # # ]: 0 : if (proplist)
780 : 0 : pa_proplist_free(proplist);
781 : :
782 : : return NULL;
783 : : }
|