]> code.delx.au - pulseaudio/blob - src/pulsecore/dbus-util.c
b45e6a6c6d0e99b4a970b62502439a4f78cee2e8
[pulseaudio] / src / pulsecore / dbus-util.c
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 *c;
49 DBusTimeout *timeout;
50 };
51
52 static void dispatch_cb(pa_mainloop_api *ea, pa_defer_event *ev, void *userdata) {
53 DBusConnection *conn = userdata;
54
55 if (dbus_connection_dispatch(conn) == DBUS_DISPATCH_COMPLETE) {
56 /* no more data to process, disable the deferred */
57 ea->defer_enable(ev, 0);
58 }
59 }
60
61 /* DBusDispatchStatusFunction callback for the pa mainloop */
62 static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status, void *userdata) {
63 pa_dbus_wrap_connection *c = userdata;
64
65 pa_assert(c);
66
67 switch(status) {
68
69 case DBUS_DISPATCH_COMPLETE:
70 c->mainloop->defer_enable(c->dispatch_event, 0);
71 break;
72
73 case DBUS_DISPATCH_DATA_REMAINS:
74 case DBUS_DISPATCH_NEED_MEMORY:
75 default:
76 c->mainloop->defer_enable(c->dispatch_event, 1);
77 break;
78 }
79 }
80
81 static pa_io_event_flags_t get_watch_flags(DBusWatch *watch) {
82 unsigned int flags;
83 pa_io_event_flags_t events = 0;
84
85 pa_assert(watch);
86
87 flags = dbus_watch_get_flags(watch);
88
89 /* no watch flags for disabled watches */
90 if (!dbus_watch_get_enabled(watch))
91 return PA_IO_EVENT_NULL;
92
93 if (flags & DBUS_WATCH_READABLE)
94 events |= PA_IO_EVENT_INPUT;
95 if (flags & DBUS_WATCH_WRITABLE)
96 events |= PA_IO_EVENT_OUTPUT;
97
98 return events | PA_IO_EVENT_HANGUP | PA_IO_EVENT_ERROR;
99 }
100
101 /* pa_io_event_cb_t IO event handler */
102 static void handle_io_event(pa_mainloop_api *ea, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
103 unsigned int flags = 0;
104 DBusWatch *watch = userdata;
105
106 #if HAVE_DBUS_WATCH_GET_UNIX_FD
107 pa_assert(fd == dbus_watch_get_unix_fd(watch));
108 #else
109 pa_assert(fd == dbus_watch_get_fd(watch));
110 #endif
111
112 if (!dbus_watch_get_enabled(watch)) {
113 pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch, fd);
114 return;
115 }
116
117 if (events & PA_IO_EVENT_INPUT)
118 flags |= DBUS_WATCH_READABLE;
119 if (events & PA_IO_EVENT_OUTPUT)
120 flags |= DBUS_WATCH_WRITABLE;
121 if (events & PA_IO_EVENT_HANGUP)
122 flags |= DBUS_WATCH_HANGUP;
123 if (events & PA_IO_EVENT_ERROR)
124 flags |= DBUS_WATCH_ERROR;
125
126 dbus_watch_handle(watch, flags);
127 }
128
129 /* pa_time_event_cb_t timer event handler */
130 static void handle_time_event(pa_mainloop_api *ea, pa_time_event* e, const struct timeval *t, void *userdata) {
131 struct timeval tv;
132 struct timeout_data *d = userdata;
133
134 pa_assert(d);
135 pa_assert(d->c);
136
137 if (dbus_timeout_get_enabled(d->timeout)) {
138 dbus_timeout_handle(d->timeout);
139
140 /* restart it for the next scheduled time */
141 ea->time_restart(e, pa_timeval_rtstore(&tv, pa_timeval_load(t) + dbus_timeout_get_interval(d->timeout) * PA_USEC_PER_MSEC, d->c->use_rtclock));
142 }
143 }
144
145 /* DBusAddWatchFunction callback for pa mainloop */
146 static dbus_bool_t add_watch(DBusWatch *watch, void *data) {
147 pa_dbus_wrap_connection *c = data;
148 pa_io_event *ev;
149
150 pa_assert(watch);
151 pa_assert(c);
152
153 ev = c->mainloop->io_new(
154 c->mainloop,
155 #if HAVE_DBUS_WATCH_GET_UNIX_FD
156 dbus_watch_get_unix_fd(watch),
157 #else
158 dbus_watch_get_fd(watch),
159 #endif
160 get_watch_flags(watch), handle_io_event, watch);
161
162 dbus_watch_set_data(watch, ev, NULL);
163
164 return TRUE;
165 }
166
167 /* DBusRemoveWatchFunction callback for pa mainloop */
168 static void remove_watch(DBusWatch *watch, void *data) {
169 pa_dbus_wrap_connection *c = data;
170 pa_io_event *ev;
171
172 pa_assert(watch);
173 pa_assert(c);
174
175 if ((ev = dbus_watch_get_data(watch)))
176 c->mainloop->io_free(ev);
177 }
178
179 /* DBusWatchToggledFunction callback for pa mainloop */
180 static void toggle_watch(DBusWatch *watch, void *data) {
181 pa_dbus_wrap_connection *c = data;
182 pa_io_event *ev;
183
184 pa_assert(watch);
185 pa_assert(c);
186
187 pa_assert_se(ev = dbus_watch_get_data(watch));
188
189 /* get_watch_flags() checks if the watch is enabled */
190 c->mainloop->io_enable(ev, get_watch_flags(watch));
191 }
192
193 static void time_event_destroy_cb(pa_mainloop_api *a, pa_time_event *e, void *userdata) {
194 pa_xfree(userdata);
195 }
196
197 /* DBusAddTimeoutFunction callback for pa mainloop */
198 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) {
199 pa_dbus_wrap_connection *c = data;
200 pa_time_event *ev;
201 struct timeval tv;
202 struct timeout_data *d;
203
204 pa_assert(timeout);
205 pa_assert(c);
206
207 if (!dbus_timeout_get_enabled(timeout))
208 return FALSE;
209
210 d = pa_xnew(struct timeout_data, 1);
211 d->c = c;
212 d->timeout = timeout;
213 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);
214 c->mainloop->time_set_destroy(ev, time_event_destroy_cb);
215
216 dbus_timeout_set_data(timeout, ev, NULL);
217
218 return TRUE;
219 }
220
221 /* DBusRemoveTimeoutFunction callback for pa mainloop */
222 static void remove_timeout(DBusTimeout *timeout, void *data) {
223 pa_dbus_wrap_connection *c = data;
224 pa_time_event *ev;
225
226 pa_assert(timeout);
227 pa_assert(c);
228
229 if ((ev = dbus_timeout_get_data(timeout)))
230 c->mainloop->time_free(ev);
231 }
232
233 /* DBusTimeoutToggledFunction callback for pa mainloop */
234 static void toggle_timeout(DBusTimeout *timeout, void *data) {
235 struct timeout_data *d = data;
236 pa_time_event *ev;
237 struct timeval tv;
238
239 pa_assert(d);
240 pa_assert(d->c);
241 pa_assert(timeout);
242
243 pa_assert_se(ev = dbus_timeout_get_data(timeout));
244
245 if (dbus_timeout_get_enabled(timeout)) {
246 d->c->mainloop->time_restart(ev, pa_timeval_rtstore(&tv, pa_rtclock_now() + dbus_timeout_get_interval(timeout) * PA_USEC_PER_MSEC, d->c->use_rtclock));
247 } else
248 d->c->mainloop->time_restart(ev, pa_timeval_rtstore(&tv, PA_USEC_INVALID, d->c->use_rtclock));
249 }
250
251 static void wakeup_main(void *userdata) {
252 pa_dbus_wrap_connection *c = userdata;
253
254 pa_assert(c);
255
256 /* this will wakeup the mainloop and dispatch events, although
257 * it may not be the cleanest way of accomplishing it */
258 c->mainloop->defer_enable(c->dispatch_event, 1);
259 }
260
261 pa_dbus_wrap_connection* pa_dbus_wrap_connection_new(pa_mainloop_api *m, pa_bool_t use_rtclock, DBusBusType type, DBusError *error) {
262 DBusConnection *conn;
263 pa_dbus_wrap_connection *pconn;
264 char *id;
265
266 pa_assert(type == DBUS_BUS_SYSTEM || type == DBUS_BUS_SESSION || type == DBUS_BUS_STARTER);
267
268 if (!(conn = dbus_bus_get_private(type, error)))
269 return NULL;
270
271 pconn = pa_xnew(pa_dbus_wrap_connection, 1);
272 pconn->mainloop = m;
273 pconn->connection = conn;
274 pconn->use_rtclock = use_rtclock;
275
276 dbus_connection_set_exit_on_disconnect(conn, FALSE);
277 dbus_connection_set_dispatch_status_function(conn, dispatch_status, pconn, NULL);
278 dbus_connection_set_watch_functions(conn, add_watch, remove_watch, toggle_watch, pconn, NULL);
279 dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, toggle_timeout, pconn, NULL);
280 dbus_connection_set_wakeup_main_function(conn, wakeup_main, pconn, NULL);
281
282 pconn->dispatch_event = pconn->mainloop->defer_new(pconn->mainloop, dispatch_cb, conn);
283
284 pa_log_debug("Successfully connected to D-Bus %s bus %s as %s",
285 type == DBUS_BUS_SYSTEM ? "system" : (type == DBUS_BUS_SESSION ? "session" : "starter"),
286 pa_strnull((id = dbus_connection_get_server_id(conn))),
287 pa_strnull(dbus_bus_get_unique_name(conn)));
288
289 dbus_free(id);
290
291 return pconn;
292 }
293
294 pa_dbus_wrap_connection* pa_dbus_wrap_connection_new_from_existing(pa_mainloop_api *m, pa_bool_t use_rtclock, DBusConnection *conn) {
295 pa_dbus_wrap_connection *pconn;
296
297 pa_assert(m);
298 pa_assert(conn);
299
300 pconn = pa_xnew(pa_dbus_wrap_connection, 1);
301 pconn->mainloop = m;
302 pconn->connection = dbus_connection_ref(conn);
303 pconn->use_rtclock = use_rtclock;
304
305 dbus_connection_set_exit_on_disconnect(conn, FALSE);
306 dbus_connection_set_dispatch_status_function(conn, dispatch_status, pconn, NULL);
307 dbus_connection_set_watch_functions(conn, add_watch, remove_watch, toggle_watch, pconn, NULL);
308 dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, toggle_timeout, pconn, NULL);
309 dbus_connection_set_wakeup_main_function(conn, wakeup_main, pconn, NULL);
310
311 pconn->dispatch_event = pconn->mainloop->defer_new(pconn->mainloop, dispatch_cb, conn);
312
313 return pconn;
314 }
315
316 void pa_dbus_wrap_connection_free(pa_dbus_wrap_connection* c) {
317 pa_assert(c);
318
319 if (dbus_connection_get_is_connected(c->connection)) {
320 dbus_connection_close(c->connection);
321 /* must process remaining messages, bit of a kludge to handle
322 * both unload and shutdown */
323 while (dbus_connection_read_write_dispatch(c->connection, -1))
324 ;
325 }
326
327 c->mainloop->defer_free(c->dispatch_event);
328 dbus_connection_unref(c->connection);
329 pa_xfree(c);
330 }
331
332 DBusConnection* pa_dbus_wrap_connection_get(pa_dbus_wrap_connection *c) {
333 pa_assert(c);
334 pa_assert(c->connection);
335
336 return c->connection;
337 }
338
339 int pa_dbus_add_matches(DBusConnection *c, DBusError *error, ...) {
340 const char *t;
341 va_list ap;
342 unsigned k = 0;
343
344 pa_assert(c);
345 pa_assert(error);
346
347 va_start(ap, error);
348 while ((t = va_arg(ap, const char*))) {
349 dbus_bus_add_match(c, t, error);
350
351 if (dbus_error_is_set(error))
352 goto fail;
353
354 k++;
355 }
356 va_end(ap);
357 return 0;
358
359 fail:
360
361 va_end(ap);
362 va_start(ap, error);
363 for (; k > 0; k--) {
364 DBusError e;
365
366 pa_assert_se(t = va_arg(ap, const char*));
367
368 dbus_error_init(&e);
369 dbus_bus_remove_match(c, t, &e);
370 dbus_error_free(&e);
371 }
372 va_end(ap);
373
374 return -1;
375 }
376
377 void pa_dbus_remove_matches(DBusConnection *c, ...) {
378 const char *t;
379 va_list ap;
380 DBusError error;
381
382 pa_assert(c);
383
384 dbus_error_init(&error);
385
386 va_start(ap, c);
387 while ((t = va_arg(ap, const char*))) {
388 dbus_bus_remove_match(c, t, &error);
389 dbus_error_free(&error);
390 }
391 va_end(ap);
392 }
393
394 pa_dbus_pending *pa_dbus_pending_new(
395 DBusConnection *c,
396 DBusMessage *m,
397 DBusPendingCall *pending,
398 void *context_data,
399 void *call_data) {
400
401 pa_dbus_pending *p;
402
403 pa_assert(pending);
404
405 p = pa_xnew(pa_dbus_pending, 1);
406 p->connection = c;
407 p->message = m;
408 p->pending = pending;
409 p->context_data = context_data;
410 p->call_data = call_data;
411
412 PA_LLIST_INIT(pa_dbus_pending, p);
413
414 return p;
415 }
416
417 void pa_dbus_pending_free(pa_dbus_pending *p) {
418 pa_assert(p);
419
420 if (p->pending) {
421 dbus_pending_call_cancel(p->pending);
422 dbus_pending_call_unref(p->pending);
423 }
424
425 if (p->message)
426 dbus_message_unref(p->message);
427
428 pa_xfree(p);
429 }
430
431 void pa_dbus_sync_pending_list(pa_dbus_pending **p) {
432 pa_assert(p);
433
434 while (*p && dbus_connection_read_write_dispatch((*p)->connection, -1))
435 ;
436 }
437
438 void pa_dbus_free_pending_list(pa_dbus_pending **p) {
439 pa_dbus_pending *i;
440
441 pa_assert(p);
442
443 while ((i = *p)) {
444 PA_LLIST_REMOVE(pa_dbus_pending, *p, i);
445 pa_dbus_pending_free(i);
446 }
447 }
448
449 void pa_dbus_send_error(DBusConnection *c, DBusMessage *in_reply_to, const char *name, const char *format, ...) {
450 va_list ap;
451 char *message;
452 DBusMessage *reply = NULL;
453
454 pa_assert(c);
455 pa_assert(in_reply_to);
456 pa_assert(name);
457 pa_assert(format);
458
459 va_start(ap, format);
460 message = pa_vsprintf_malloc(format, ap);
461 va_end(ap);
462 pa_assert_se((reply = dbus_message_new_error(in_reply_to, name, message)));
463 pa_assert_se(dbus_connection_send(c, reply, NULL));
464
465 dbus_message_unref(reply);
466
467 pa_xfree(message);
468 }
469
470 void pa_dbus_send_empty_reply(DBusConnection *c, DBusMessage *in_reply_to) {
471 DBusMessage *reply = NULL;
472
473 pa_assert(c);
474 pa_assert(in_reply_to);
475
476 pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
477 pa_assert_se(dbus_connection_send(c, reply, NULL));
478 dbus_message_unref(reply);
479 }
480
481 void pa_dbus_send_basic_value_reply(DBusConnection *c, DBusMessage *in_reply_to, int type, void *data) {
482 DBusMessage *reply = NULL;
483
484 pa_assert(c);
485 pa_assert(in_reply_to);
486 pa_assert(dbus_type_is_basic(type));
487 pa_assert(data);
488
489 pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
490 pa_assert_se(dbus_message_append_args(reply, type, data, DBUS_TYPE_INVALID));
491 pa_assert_se(dbus_connection_send(c, reply, NULL));
492 dbus_message_unref(reply);
493 }
494
495 static const char *signature_from_basic_type(int type) {
496 switch (type) {
497 case DBUS_TYPE_BOOLEAN: return DBUS_TYPE_BOOLEAN_AS_STRING;
498 case DBUS_TYPE_BYTE: return DBUS_TYPE_BYTE_AS_STRING;
499 case DBUS_TYPE_INT16: return DBUS_TYPE_INT16_AS_STRING;
500 case DBUS_TYPE_UINT16: return DBUS_TYPE_UINT16_AS_STRING;
501 case DBUS_TYPE_INT32: return DBUS_TYPE_INT32_AS_STRING;
502 case DBUS_TYPE_UINT32: return DBUS_TYPE_UINT32_AS_STRING;
503 case DBUS_TYPE_INT64: return DBUS_TYPE_INT64_AS_STRING;
504 case DBUS_TYPE_UINT64: return DBUS_TYPE_UINT64_AS_STRING;
505 case DBUS_TYPE_DOUBLE: return DBUS_TYPE_DOUBLE_AS_STRING;
506 case DBUS_TYPE_STRING: return DBUS_TYPE_STRING_AS_STRING;
507 case DBUS_TYPE_OBJECT_PATH: return DBUS_TYPE_OBJECT_PATH_AS_STRING;
508 case DBUS_TYPE_SIGNATURE: return DBUS_TYPE_SIGNATURE_AS_STRING;
509 default: pa_assert_not_reached();
510 }
511 }
512
513 void pa_dbus_send_basic_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, int type, void *data) {
514 DBusMessage *reply = NULL;
515 DBusMessageIter msg_iter;
516 DBusMessageIter variant_iter;
517
518 pa_assert(c);
519 pa_assert(in_reply_to);
520 pa_assert(dbus_type_is_basic(type));
521 pa_assert(data);
522
523 pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
524 dbus_message_iter_init_append(reply, &msg_iter);
525 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_VARIANT, signature_from_basic_type(type), &variant_iter));
526 pa_assert_se(dbus_message_iter_append_basic(&variant_iter, type, data));
527 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &variant_iter));
528 pa_assert_se(dbus_connection_send(c, reply, NULL));
529 dbus_message_unref(reply);
530 }
531
532 /* Note: returns sizeof(char*) for strings, object paths and signatures. */
533 static unsigned basic_type_size(int type) {
534 switch (type) {
535 case DBUS_TYPE_BOOLEAN: return sizeof(dbus_bool_t);
536 case DBUS_TYPE_BYTE: return 1;
537 case DBUS_TYPE_INT16: return sizeof(dbus_int16_t);
538 case DBUS_TYPE_UINT16: return sizeof(dbus_uint16_t);
539 case DBUS_TYPE_INT32: return sizeof(dbus_int32_t);
540 case DBUS_TYPE_UINT32: return sizeof(dbus_uint32_t);
541 case DBUS_TYPE_INT64: return sizeof(dbus_int64_t);
542 case DBUS_TYPE_UINT64: return sizeof(dbus_uint64_t);
543 case DBUS_TYPE_DOUBLE: return sizeof(double);
544 case DBUS_TYPE_STRING:
545 case DBUS_TYPE_OBJECT_PATH:
546 case DBUS_TYPE_SIGNATURE: return sizeof(char*);
547 default: pa_assert_not_reached();
548 }
549 }
550
551 void pa_dbus_send_basic_array_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, int item_type, void *array, unsigned n) {
552 DBusMessage *reply = NULL;
553 DBusMessageIter msg_iter;
554
555 pa_assert(c);
556 pa_assert(in_reply_to);
557 pa_assert(dbus_type_is_basic(item_type));
558 pa_assert(array || n == 0);
559
560 pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
561 dbus_message_iter_init_append(reply, &msg_iter);
562 pa_dbus_append_basic_array_variant(&msg_iter, item_type, array, n);
563 pa_assert_se(dbus_connection_send(c, reply, NULL));
564 dbus_message_unref(reply);
565 }
566
567 void pa_dbus_send_proplist_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, pa_proplist *proplist) {
568 DBusMessage *reply = NULL;
569 DBusMessageIter msg_iter;
570
571 pa_assert(c);
572 pa_assert(in_reply_to);
573 pa_assert(proplist);
574
575 pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
576 dbus_message_iter_init_append(reply, &msg_iter);
577 pa_dbus_append_proplist_variant(&msg_iter, proplist);
578 pa_assert_se(dbus_connection_send(c, reply, NULL));
579 dbus_message_unref(reply);
580 }
581
582 void pa_dbus_append_basic_array(DBusMessageIter *iter, int item_type, const void *array, unsigned n) {
583 DBusMessageIter array_iter;
584 unsigned i;
585 unsigned item_size;
586
587 pa_assert(iter);
588 pa_assert(dbus_type_is_basic(item_type));
589 pa_assert(array || n == 0);
590
591 item_size = basic_type_size(item_type);
592
593 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, signature_from_basic_type(item_type), &array_iter));
594
595 for (i = 0; i < n; ++i)
596 pa_assert_se(dbus_message_iter_append_basic(&array_iter, item_type, &((uint8_t*) array)[i * item_size]));
597
598 pa_assert_se(dbus_message_iter_close_container(iter, &array_iter));
599 };
600
601 void pa_dbus_append_basic_variant(DBusMessageIter *iter, int type, void *data) {
602 DBusMessageIter variant_iter;
603
604 pa_assert(iter);
605 pa_assert(dbus_type_is_basic(type));
606 pa_assert(data);
607
608 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, signature_from_basic_type(type), &variant_iter));
609 pa_assert_se(dbus_message_iter_append_basic(&variant_iter, type, data));
610 pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
611 }
612
613 void pa_dbus_append_basic_array_variant(DBusMessageIter *iter, int item_type, const void *array, unsigned n) {
614 DBusMessageIter variant_iter;
615 char *array_signature;
616
617 pa_assert(iter);
618 pa_assert(dbus_type_is_basic(item_type));
619 pa_assert(array || n == 0);
620
621 array_signature = pa_sprintf_malloc("a%c", *signature_from_basic_type(item_type));
622
623 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, array_signature, &variant_iter));
624 pa_dbus_append_basic_array(&variant_iter, item_type, array, n);
625 pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
626
627 pa_xfree(array_signature);
628 }
629
630 void pa_dbus_append_basic_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, int type, void *data) {
631 DBusMessageIter dict_entry_iter;
632
633 pa_assert(dict_iter);
634 pa_assert(key);
635 pa_assert(dbus_type_is_basic(type));
636 pa_assert(data);
637
638 pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
639 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
640 pa_dbus_append_basic_variant(&dict_entry_iter, type, data);
641 pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
642 }
643
644 void pa_dbus_append_basic_array_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, int item_type, const void *array, unsigned n) {
645 DBusMessageIter dict_entry_iter;
646
647 pa_assert(dict_iter);
648 pa_assert(key);
649 pa_assert(dbus_type_is_basic(item_type));
650 pa_assert(array || n == 0);
651
652 pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
653 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
654 pa_dbus_append_basic_array_variant(&dict_entry_iter, item_type, array, n);
655 pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
656 }
657
658 void pa_dbus_append_proplist(DBusMessageIter *iter, pa_proplist *proplist) {
659 DBusMessageIter dict_iter;
660 DBusMessageIter dict_entry_iter;
661 DBusMessageIter array_iter;
662 void *state = NULL;
663 const char *key;
664
665 pa_assert(iter);
666 pa_assert(proplist);
667
668 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{say}", &dict_iter));
669
670 while ((key = pa_proplist_iterate(proplist, &state))) {
671 const void *value = NULL;
672 size_t nbytes;
673
674 pa_assert_se(pa_proplist_get(proplist, key, &value, &nbytes) >= 0);
675
676 pa_assert_se(dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
677
678 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
679
680 pa_assert_se(dbus_message_iter_open_container(&dict_entry_iter, DBUS_TYPE_ARRAY, "y", &array_iter));
681 pa_assert_se(dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, &value, nbytes));
682 pa_assert_se(dbus_message_iter_close_container(&dict_entry_iter, &array_iter));
683
684 pa_assert_se(dbus_message_iter_close_container(&dict_iter, &dict_entry_iter));
685 }
686
687 pa_assert_se(dbus_message_iter_close_container(iter, &dict_iter));
688 }
689
690 void pa_dbus_append_proplist_variant(DBusMessageIter *iter, pa_proplist *proplist) {
691 DBusMessageIter variant_iter;
692
693 pa_assert(iter);
694 pa_assert(proplist);
695
696 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{say}", &variant_iter));
697 pa_dbus_append_proplist(&variant_iter, proplist);
698 pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
699 }
700
701 void pa_dbus_append_proplist_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, pa_proplist *proplist) {
702 DBusMessageIter dict_entry_iter;
703
704 pa_assert(dict_iter);
705 pa_assert(key);
706 pa_assert(proplist);
707
708 pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
709 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
710 pa_dbus_append_proplist_variant(&dict_entry_iter, proplist);
711 pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
712 }
713
714 int pa_dbus_get_basic_set_property_arg(DBusConnection *c, DBusMessage *msg, int type, void *data) {
715 DBusMessageIter msg_iter;
716 DBusMessageIter variant_iter;
717
718 pa_assert(c);
719 pa_assert(msg);
720 pa_assert(dbus_type_is_basic(type));
721 pa_assert(data);
722
723 /* Skip the interface and property name arguments. */
724 if (!dbus_message_iter_init(msg, &msg_iter) || !dbus_message_iter_next(&msg_iter) || !dbus_message_iter_next(&msg_iter)) {
725 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Too few arguments.");
726 return -1;
727 }
728
729 if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_VARIANT) {
730 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Message argument isn't a variant.");
731 return -1;
732 }
733
734 dbus_message_iter_recurse(&msg_iter, &variant_iter);
735
736 if (pa_dbus_get_basic_arg(c, msg, &variant_iter, type, data) < 0)
737 return -1;
738
739 return 0;
740 }
741
742 int pa_dbus_get_fixed_array_set_property_arg(DBusConnection *c, DBusMessage *msg, int item_type, void *data, unsigned *n) {
743 DBusMessageIter msg_iter;
744 DBusMessageIter variant_iter;
745
746 pa_assert(c);
747 pa_assert(msg);
748 pa_assert(dbus_type_is_fixed(item_type));
749 pa_assert(data);
750 pa_assert(n);
751
752 /* Skip the interface and property name arguments. */
753 if (!dbus_message_iter_init(msg, &msg_iter) || !dbus_message_iter_next(&msg_iter) || !dbus_message_iter_next(&msg_iter)) {
754 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Too few arguments.");
755 return -1;
756 }
757
758 if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_VARIANT) {
759 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Message argument isn't a variant.");
760 return -1;
761 }
762
763 dbus_message_iter_recurse(&msg_iter, &variant_iter);
764
765 if (pa_dbus_get_fixed_array_arg(c, msg, &variant_iter, item_type, data, n) < 0)
766 return -1;
767
768 return 0;
769 }
770
771 int pa_dbus_get_basic_arg(DBusConnection *c, DBusMessage *msg, DBusMessageIter *iter, int type, void *data) {
772 int arg_type;
773
774 pa_assert(c);
775 pa_assert(msg);
776 pa_assert(iter);
777 pa_assert(dbus_type_is_basic(type));
778 pa_assert(data);
779
780 arg_type = dbus_message_iter_get_arg_type(iter);
781 if (arg_type != type) {
782 if (arg_type == DBUS_TYPE_INVALID)
783 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Too few arguments. D-Bus type '%c' expected.", (char) type);
784 else
785 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Wrong argument type: '%c'. Expected type '%c'.", (char) arg_type, (char) type);
786 return -1;
787 }
788
789 dbus_message_iter_get_basic(iter, data);
790
791 dbus_message_iter_next(iter);
792
793 return 0;
794 }
795
796 int pa_dbus_get_fixed_array_arg(DBusConnection *c, DBusMessage *msg, DBusMessageIter *iter, int item_type, void *array, unsigned *n) {
797 DBusMessageIter array_iter;
798 int signed_n;
799 int arg_type;
800 int element_type;
801
802 pa_assert(c);
803 pa_assert(msg);
804 pa_assert(iter);
805 pa_assert(dbus_type_is_fixed(item_type));
806 pa_assert(array);
807 pa_assert(n);
808
809 arg_type = dbus_message_iter_get_arg_type(iter);
810 if (arg_type != DBUS_TYPE_ARRAY) {
811 if (arg_type == DBUS_TYPE_INVALID)
812 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Too few arguments. An array of type '%c' was expected.", (char) item_type);
813 else
814 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Wrong argument type: '%c'. An array of type '%c' was expected.", (char) arg_type, (char) item_type);
815 return -1;
816 }
817
818 element_type = dbus_message_iter_get_element_type(iter);
819 if (element_type != item_type) {
820 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Wrong array element type: '%c'. Element type '%c' was expected.", (char) element_type, (char) item_type);
821 return -1;
822 }
823
824 dbus_message_iter_recurse(iter, &array_iter);
825
826 dbus_message_iter_get_fixed_array(&array_iter, array, &signed_n);
827
828 dbus_message_iter_next(iter);
829
830 pa_assert(signed_n >= 0);
831
832 *n = signed_n;
833
834 return 0;
835 }
836
837 pa_proplist *pa_dbus_get_proplist_arg(DBusConnection *c, DBusMessage *msg, DBusMessageIter *iter) {
838 DBusMessageIter dict_iter;
839 DBusMessageIter dict_entry_iter;
840 int arg_type;
841 pa_proplist *proplist = NULL;
842 const char *key;
843 const uint8_t *value;
844 int value_length;
845
846 pa_assert(c);
847 pa_assert(msg);
848 pa_assert(iter);
849
850 arg_type = dbus_message_iter_get_arg_type(iter);
851 if (arg_type != DBUS_TYPE_ARRAY) {
852 if (arg_type == DBUS_TYPE_INVALID)
853 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Too few arguments. An array was expected.");
854 else
855 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Wrong argument type: '%c'. An array was expected.", (char) arg_type);
856 return NULL;
857 }
858
859 arg_type = dbus_message_iter_get_element_type(iter);
860 if (arg_type != DBUS_TYPE_DICT_ENTRY) {
861 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Wrong array element type: '%c'. A dictionary entry was expected.", (char) arg_type);
862 return NULL;
863 }
864
865 proplist = pa_proplist_new();
866
867 dbus_message_iter_recurse(iter, &dict_iter);
868
869 while (dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_INVALID) {
870 dbus_message_iter_recurse(&dict_iter, &dict_entry_iter);
871
872 arg_type = dbus_message_iter_get_arg_type(&dict_entry_iter);
873 if (arg_type != DBUS_TYPE_STRING) {
874 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Wrong dict key type: '%c'. A string was expected.", (char) arg_type);
875 goto fail;
876 }
877
878 dbus_message_iter_get_basic(&dict_entry_iter, &key);
879 dbus_message_iter_next(&dict_entry_iter);
880
881 if (strlen(key) <= 0 || !pa_ascii_valid(key)) {
882 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Invalid property list key.");
883 goto fail;
884 }
885
886 arg_type = dbus_message_iter_get_arg_type(&dict_entry_iter);
887 if (arg_type != DBUS_TYPE_ARRAY) {
888 if (arg_type == DBUS_TYPE_INVALID)
889 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Dict value missing.");
890 else
891 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Wrong dict value type: '%c'. An array was expected.", (char) arg_type);
892 goto fail;
893 }
894
895 arg_type = dbus_message_iter_get_element_type(&dict_entry_iter);
896 if (arg_type != DBUS_TYPE_BYTE) {
897 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Wrong dict value item type: '%c'. A byte was expected.", (char) arg_type);
898 goto fail;
899 }
900
901 dbus_message_iter_get_fixed_array(&dict_entry_iter, &value, &value_length);
902
903 pa_assert(value_length >= 0);
904
905 pa_assert_se(pa_proplist_set(proplist, key, value, value_length) >= 0);
906
907 dbus_message_iter_next(&dict_iter);
908 }
909
910 dbus_message_iter_next(iter);
911
912 return proplist;
913
914 fail:
915 if (proplist)
916 pa_proplist_free(proplist);
917
918 return NULL;
919 }