]> code.delx.au - pulseaudio/blob - src/pulsecore/dbus-util.c
core: Add name to flist struct for more informative log messages
[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 *connection;
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 /* DBusDispatchStatusFunction callback for the pa mainloop */
61 static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status, void *userdata) {
62 pa_dbus_wrap_connection *c = userdata;
63
64 pa_assert(c);
65
66 switch(status) {
67
68 case DBUS_DISPATCH_COMPLETE:
69 c->mainloop->defer_enable(c->dispatch_event, 0);
70 break;
71
72 case DBUS_DISPATCH_DATA_REMAINS:
73 case DBUS_DISPATCH_NEED_MEMORY:
74 default:
75 c->mainloop->defer_enable(c->dispatch_event, 1);
76 break;
77 }
78 }
79
80 static pa_io_event_flags_t get_watch_flags(DBusWatch *watch) {
81 unsigned int flags;
82 pa_io_event_flags_t events = 0;
83
84 pa_assert(watch);
85
86 flags = dbus_watch_get_flags(watch);
87
88 /* no watch flags for disabled watches */
89 if (!dbus_watch_get_enabled(watch))
90 return PA_IO_EVENT_NULL;
91
92 if (flags & DBUS_WATCH_READABLE)
93 events |= PA_IO_EVENT_INPUT;
94 if (flags & DBUS_WATCH_WRITABLE)
95 events |= PA_IO_EVENT_OUTPUT;
96
97 return events | PA_IO_EVENT_HANGUP | PA_IO_EVENT_ERROR;
98 }
99
100 /* pa_io_event_cb_t IO event handler */
101 static void handle_io_event(pa_mainloop_api *ea, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
102 unsigned int flags = 0;
103 DBusWatch *watch = userdata;
104
105 #if HAVE_DBUS_WATCH_GET_UNIX_FD
106 pa_assert(fd == dbus_watch_get_unix_fd(watch));
107 #else
108 pa_assert(fd == dbus_watch_get_fd(watch));
109 #endif
110
111 if (!dbus_watch_get_enabled(watch)) {
112 pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch, fd);
113 return;
114 }
115
116 if (events & PA_IO_EVENT_INPUT)
117 flags |= DBUS_WATCH_READABLE;
118 if (events & PA_IO_EVENT_OUTPUT)
119 flags |= DBUS_WATCH_WRITABLE;
120 if (events & PA_IO_EVENT_HANGUP)
121 flags |= DBUS_WATCH_HANGUP;
122 if (events & PA_IO_EVENT_ERROR)
123 flags |= DBUS_WATCH_ERROR;
124
125 dbus_watch_handle(watch, flags);
126 }
127
128 /* pa_time_event_cb_t timer event handler */
129 static void handle_time_event(pa_mainloop_api *ea, pa_time_event* e, const struct timeval *t, void *userdata) {
130 struct timeval tv;
131 struct timeout_data *d = userdata;
132
133 pa_assert(d);
134 pa_assert(d->connection);
135
136 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 ea->time_restart(e, pa_timeval_rtstore(&tv,
141 pa_timeval_load(t) + dbus_timeout_get_interval(d->timeout) * PA_USEC_PER_MSEC,
142 d->connection->use_rtclock));
143
144 dbus_timeout_handle(d->timeout);
145 }
146 }
147
148 /* DBusAddWatchFunction callback for pa mainloop */
149 static dbus_bool_t add_watch(DBusWatch *watch, void *data) {
150 pa_dbus_wrap_connection *c = data;
151 pa_io_event *ev;
152
153 pa_assert(watch);
154 pa_assert(c);
155
156 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 dbus_watch_set_data(watch, ev, NULL);
166
167 return TRUE;
168 }
169
170 /* DBusRemoveWatchFunction callback for pa mainloop */
171 static void remove_watch(DBusWatch *watch, void *data) {
172 pa_dbus_wrap_connection *c = data;
173 pa_io_event *ev;
174
175 pa_assert(watch);
176 pa_assert(c);
177
178 if ((ev = dbus_watch_get_data(watch)))
179 c->mainloop->io_free(ev);
180 }
181
182 /* DBusWatchToggledFunction callback for pa mainloop */
183 static void toggle_watch(DBusWatch *watch, void *data) {
184 pa_dbus_wrap_connection *c = data;
185 pa_io_event *ev;
186
187 pa_assert(watch);
188 pa_assert(c);
189
190 pa_assert_se(ev = dbus_watch_get_data(watch));
191
192 /* get_watch_flags() checks if the watch is enabled */
193 c->mainloop->io_enable(ev, get_watch_flags(watch));
194 }
195
196 static void time_event_destroy_cb(pa_mainloop_api *a, pa_time_event *e, void *userdata) {
197 pa_xfree(userdata);
198 }
199
200 /* DBusAddTimeoutFunction callback for pa mainloop */
201 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) {
202 pa_dbus_wrap_connection *c = data;
203 pa_time_event *ev;
204 struct timeval tv;
205 struct timeout_data *d;
206
207 pa_assert(timeout);
208 pa_assert(c);
209
210 if (!dbus_timeout_get_enabled(timeout))
211 return FALSE;
212
213 d = pa_xnew(struct timeout_data, 1);
214 d->connection = c;
215 d->timeout = timeout;
216 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 c->mainloop->time_set_destroy(ev, time_event_destroy_cb);
218
219 dbus_timeout_set_data(timeout, ev, NULL);
220
221 return TRUE;
222 }
223
224 /* DBusRemoveTimeoutFunction callback for pa mainloop */
225 static void remove_timeout(DBusTimeout *timeout, void *data) {
226 pa_dbus_wrap_connection *c = data;
227 pa_time_event *ev;
228
229 pa_assert(timeout);
230 pa_assert(c);
231
232 if ((ev = dbus_timeout_get_data(timeout)))
233 c->mainloop->time_free(ev);
234 }
235
236 /* DBusTimeoutToggledFunction callback for pa mainloop */
237 static void toggle_timeout(DBusTimeout *timeout, void *data) {
238 struct timeout_data *d = data;
239 pa_time_event *ev;
240 struct timeval tv;
241
242 pa_assert(d);
243 pa_assert(d->connection);
244 pa_assert(timeout);
245
246 pa_assert_se(ev = dbus_timeout_get_data(timeout));
247
248 if (dbus_timeout_get_enabled(timeout))
249 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 d->connection->mainloop->time_restart(ev, pa_timeval_rtstore(&tv, PA_USEC_INVALID, d->connection->use_rtclock));
252 }
253
254 static void wakeup_main(void *userdata) {
255 pa_dbus_wrap_connection *c = userdata;
256
257 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 c->mainloop->defer_enable(c->dispatch_event, 1);
262 }
263
264 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 pa_assert(type == DBUS_BUS_SYSTEM || type == DBUS_BUS_SESSION || type == DBUS_BUS_STARTER);
270
271 if (!(conn = dbus_bus_get_private(type, error)))
272 return NULL;
273
274 pconn = pa_xnew(pa_dbus_wrap_connection, 1);
275 pconn->mainloop = m;
276 pconn->connection = conn;
277 pconn->use_rtclock = use_rtclock;
278
279 dbus_connection_set_exit_on_disconnect(conn, FALSE);
280 dbus_connection_set_dispatch_status_function(conn, dispatch_status, pconn, NULL);
281 dbus_connection_set_watch_functions(conn, add_watch, remove_watch, toggle_watch, pconn, NULL);
282 dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, toggle_timeout, pconn, NULL);
283 dbus_connection_set_wakeup_main_function(conn, wakeup_main, pconn, NULL);
284
285 pconn->dispatch_event = pconn->mainloop->defer_new(pconn->mainloop, dispatch_cb, conn);
286
287 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 dbus_free(id);
293
294 return pconn;
295 }
296
297 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 pa_assert(m);
304 pa_assert(conn);
305
306 pconn = pa_xnew(pa_dbus_wrap_connection, 1);
307 pconn->mainloop = m;
308 pconn->connection = dbus_connection_ref(conn);
309 pconn->use_rtclock = use_rtclock;
310
311 dbus_connection_set_exit_on_disconnect(conn, FALSE);
312 dbus_connection_set_dispatch_status_function(conn, dispatch_status, pconn, NULL);
313 dbus_connection_set_watch_functions(conn, add_watch, remove_watch, toggle_watch, pconn, NULL);
314 dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, toggle_timeout, pconn, NULL);
315 dbus_connection_set_wakeup_main_function(conn, wakeup_main, pconn, NULL);
316
317 pconn->dispatch_event = pconn->mainloop->defer_new(pconn->mainloop, dispatch_cb, conn);
318
319 return pconn;
320 }
321
322 void pa_dbus_wrap_connection_free(pa_dbus_wrap_connection* c) {
323 pa_assert(c);
324
325 if (dbus_connection_get_is_connected(c->connection)) {
326 dbus_connection_close(c->connection);
327 /* must process remaining messages, bit of a kludge to handle
328 * both unload and shutdown */
329 while (dbus_connection_read_write_dispatch(c->connection, -1))
330 ;
331 }
332
333 c->mainloop->defer_free(c->dispatch_event);
334 dbus_connection_unref(c->connection);
335 pa_xfree(c);
336 }
337
338 DBusConnection* pa_dbus_wrap_connection_get(pa_dbus_wrap_connection *c) {
339 pa_assert(c);
340 pa_assert(c->connection);
341
342 return c->connection;
343 }
344
345 int pa_dbus_add_matches(DBusConnection *c, DBusError *error, ...) {
346 const char *t;
347 va_list ap;
348 unsigned k = 0;
349
350 pa_assert(c);
351 pa_assert(error);
352
353 va_start(ap, error);
354 while ((t = va_arg(ap, const char*))) {
355 dbus_bus_add_match(c, t, error);
356
357 if (dbus_error_is_set(error))
358 goto fail;
359
360 k++;
361 }
362 va_end(ap);
363 return 0;
364
365 fail:
366
367 va_end(ap);
368 va_start(ap, error);
369 for (; k > 0; k--) {
370 DBusError e;
371
372 pa_assert_se(t = va_arg(ap, const char*));
373
374 dbus_error_init(&e);
375 dbus_bus_remove_match(c, t, &e);
376 dbus_error_free(&e);
377 }
378 va_end(ap);
379
380 return -1;
381 }
382
383 void pa_dbus_remove_matches(DBusConnection *c, ...) {
384 const char *t;
385 va_list ap;
386 DBusError error;
387
388 pa_assert(c);
389
390 dbus_error_init(&error);
391
392 va_start(ap, c);
393 while ((t = va_arg(ap, const char*))) {
394 dbus_bus_remove_match(c, t, &error);
395 dbus_error_free(&error);
396 }
397 va_end(ap);
398 }
399
400 pa_dbus_pending *pa_dbus_pending_new(
401 DBusConnection *c,
402 DBusMessage *m,
403 DBusPendingCall *pending,
404 void *context_data,
405 void *call_data) {
406
407 pa_dbus_pending *p;
408
409 pa_assert(pending);
410
411 p = pa_xnew(pa_dbus_pending, 1);
412 p->connection = c;
413 p->message = m;
414 p->pending = pending;
415 p->context_data = context_data;
416 p->call_data = call_data;
417
418 PA_LLIST_INIT(pa_dbus_pending, p);
419
420 return p;
421 }
422
423 void pa_dbus_pending_free(pa_dbus_pending *p) {
424 pa_assert(p);
425
426 if (p->pending) {
427 dbus_pending_call_cancel(p->pending);
428 dbus_pending_call_unref(p->pending);
429 }
430
431 if (p->message)
432 dbus_message_unref(p->message);
433
434 pa_xfree(p);
435 }
436
437 void pa_dbus_sync_pending_list(pa_dbus_pending **p) {
438 pa_assert(p);
439
440 while (*p && dbus_connection_read_write_dispatch((*p)->connection, -1))
441 ;
442 }
443
444 void pa_dbus_free_pending_list(pa_dbus_pending **p) {
445 pa_dbus_pending *i;
446
447 pa_assert(p);
448
449 while ((i = *p)) {
450 PA_LLIST_REMOVE(pa_dbus_pending, *p, i);
451 pa_dbus_pending_free(i);
452 }
453 }
454
455 void pa_dbus_send_error(DBusConnection *c, DBusMessage *in_reply_to, const char *name, const char *format, ...) {
456 va_list ap;
457 char *message;
458 DBusMessage *reply = NULL;
459
460 pa_assert(c);
461 pa_assert(in_reply_to);
462 pa_assert(name);
463 pa_assert(format);
464
465 va_start(ap, format);
466 message = pa_vsprintf_malloc(format, ap);
467 va_end(ap);
468 pa_assert_se((reply = dbus_message_new_error(in_reply_to, name, message)));
469 pa_assert_se(dbus_connection_send(c, reply, NULL));
470
471 dbus_message_unref(reply);
472
473 pa_xfree(message);
474 }
475
476 void pa_dbus_send_empty_reply(DBusConnection *c, DBusMessage *in_reply_to) {
477 DBusMessage *reply = NULL;
478
479 pa_assert(c);
480 pa_assert(in_reply_to);
481
482 pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
483 pa_assert_se(dbus_connection_send(c, reply, NULL));
484 dbus_message_unref(reply);
485 }
486
487 void pa_dbus_send_basic_value_reply(DBusConnection *c, DBusMessage *in_reply_to, int type, void *data) {
488 DBusMessage *reply = NULL;
489
490 pa_assert(c);
491 pa_assert(in_reply_to);
492 pa_assert(dbus_type_is_basic(type));
493 pa_assert(data);
494
495 pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
496 pa_assert_se(dbus_message_append_args(reply, type, data, DBUS_TYPE_INVALID));
497 pa_assert_se(dbus_connection_send(c, reply, NULL));
498 dbus_message_unref(reply);
499 }
500
501 static const char *signature_from_basic_type(int type) {
502 switch (type) {
503 case DBUS_TYPE_BOOLEAN: return DBUS_TYPE_BOOLEAN_AS_STRING;
504 case DBUS_TYPE_BYTE: return DBUS_TYPE_BYTE_AS_STRING;
505 case DBUS_TYPE_INT16: return DBUS_TYPE_INT16_AS_STRING;
506 case DBUS_TYPE_UINT16: return DBUS_TYPE_UINT16_AS_STRING;
507 case DBUS_TYPE_INT32: return DBUS_TYPE_INT32_AS_STRING;
508 case DBUS_TYPE_UINT32: return DBUS_TYPE_UINT32_AS_STRING;
509 case DBUS_TYPE_INT64: return DBUS_TYPE_INT64_AS_STRING;
510 case DBUS_TYPE_UINT64: return DBUS_TYPE_UINT64_AS_STRING;
511 case DBUS_TYPE_DOUBLE: return DBUS_TYPE_DOUBLE_AS_STRING;
512 case DBUS_TYPE_STRING: return DBUS_TYPE_STRING_AS_STRING;
513 case DBUS_TYPE_OBJECT_PATH: return DBUS_TYPE_OBJECT_PATH_AS_STRING;
514 case DBUS_TYPE_SIGNATURE: return DBUS_TYPE_SIGNATURE_AS_STRING;
515 default: pa_assert_not_reached();
516 }
517 }
518
519 void pa_dbus_send_basic_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, int type, void *data) {
520 DBusMessage *reply = NULL;
521 DBusMessageIter msg_iter;
522 DBusMessageIter variant_iter;
523
524 pa_assert(c);
525 pa_assert(in_reply_to);
526 pa_assert(dbus_type_is_basic(type));
527 pa_assert(data);
528
529 pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
530 dbus_message_iter_init_append(reply, &msg_iter);
531 pa_assert_se(dbus_message_iter_open_container(&msg_iter,
532 DBUS_TYPE_VARIANT,
533 signature_from_basic_type(type),
534 &variant_iter));
535 pa_assert_se(dbus_message_iter_append_basic(&variant_iter, type, data));
536 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &variant_iter));
537 pa_assert_se(dbus_connection_send(c, reply, NULL));
538 dbus_message_unref(reply);
539 }
540
541 /* Note: returns sizeof(char*) for strings, object paths and signatures. */
542 static unsigned basic_type_size(int type) {
543 switch (type) {
544 case DBUS_TYPE_BOOLEAN: return sizeof(dbus_bool_t);
545 case DBUS_TYPE_BYTE: return 1;
546 case DBUS_TYPE_INT16: return sizeof(dbus_int16_t);
547 case DBUS_TYPE_UINT16: return sizeof(dbus_uint16_t);
548 case DBUS_TYPE_INT32: return sizeof(dbus_int32_t);
549 case DBUS_TYPE_UINT32: return sizeof(dbus_uint32_t);
550 case DBUS_TYPE_INT64: return sizeof(dbus_int64_t);
551 case DBUS_TYPE_UINT64: return sizeof(dbus_uint64_t);
552 case DBUS_TYPE_DOUBLE: return sizeof(double);
553 case DBUS_TYPE_STRING:
554 case DBUS_TYPE_OBJECT_PATH:
555 case DBUS_TYPE_SIGNATURE: return sizeof(char*);
556 default: pa_assert_not_reached();
557 }
558 }
559
560 void pa_dbus_send_basic_array_variant_reply(
561 DBusConnection *c,
562 DBusMessage *in_reply_to,
563 int item_type,
564 void *array,
565 unsigned n) {
566 DBusMessage *reply = NULL;
567 DBusMessageIter msg_iter;
568
569 pa_assert(c);
570 pa_assert(in_reply_to);
571 pa_assert(dbus_type_is_basic(item_type));
572 pa_assert(array || n == 0);
573
574 pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
575 dbus_message_iter_init_append(reply, &msg_iter);
576 pa_dbus_append_basic_array_variant(&msg_iter, item_type, array, n);
577 pa_assert_se(dbus_connection_send(c, reply, NULL));
578 dbus_message_unref(reply);
579 }
580
581 void pa_dbus_send_proplist_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, pa_proplist *proplist) {
582 DBusMessage *reply = NULL;
583 DBusMessageIter msg_iter;
584
585 pa_assert(c);
586 pa_assert(in_reply_to);
587 pa_assert(proplist);
588
589 pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
590 dbus_message_iter_init_append(reply, &msg_iter);
591 pa_dbus_append_proplist_variant(&msg_iter, proplist);
592 pa_assert_se(dbus_connection_send(c, reply, NULL));
593 dbus_message_unref(reply);
594 }
595
596 void pa_dbus_append_basic_array(DBusMessageIter *iter, int item_type, const void *array, unsigned n) {
597 DBusMessageIter array_iter;
598
599 pa_assert(iter);
600 pa_assert(dbus_type_is_basic(item_type));
601 pa_assert(array || n == 0);
602
603 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, signature_from_basic_type(item_type), &array_iter));
604
605 pa_assert_se(dbus_message_iter_append_fixed_array(&array_iter, item_type, array, n));
606
607 pa_assert_se(dbus_message_iter_close_container(iter, &array_iter));
608 };
609
610 void pa_dbus_append_basic_variant(DBusMessageIter *iter, int type, void *data) {
611 DBusMessageIter variant_iter;
612
613 pa_assert(iter);
614 pa_assert(dbus_type_is_basic(type));
615 pa_assert(data);
616
617 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, signature_from_basic_type(type), &variant_iter));
618 pa_assert_se(dbus_message_iter_append_basic(&variant_iter, type, data));
619 pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
620 }
621
622 void pa_dbus_append_basic_array_variant(DBusMessageIter *iter, int item_type, const void *array, unsigned n) {
623 DBusMessageIter variant_iter;
624 char *array_signature;
625
626 pa_assert(iter);
627 pa_assert(dbus_type_is_basic(item_type));
628 pa_assert(array || n == 0);
629
630 array_signature = pa_sprintf_malloc("a%c", *signature_from_basic_type(item_type));
631
632 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, array_signature, &variant_iter));
633 pa_dbus_append_basic_array(&variant_iter, item_type, array, n);
634 pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
635
636 pa_xfree(array_signature);
637 }
638
639 void pa_dbus_append_basic_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, int type, void *data) {
640 DBusMessageIter dict_entry_iter;
641
642 pa_assert(dict_iter);
643 pa_assert(key);
644 pa_assert(dbus_type_is_basic(type));
645 pa_assert(data);
646
647 pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
648 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
649 pa_dbus_append_basic_variant(&dict_entry_iter, type, data);
650 pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
651 }
652
653 void pa_dbus_append_basic_array_variant_dict_entry(
654 DBusMessageIter *dict_iter,
655 const char *key,
656 int item_type,
657 const void *array,
658 unsigned n) {
659 DBusMessageIter dict_entry_iter;
660
661 pa_assert(dict_iter);
662 pa_assert(key);
663 pa_assert(dbus_type_is_basic(item_type));
664 pa_assert(array || n == 0);
665
666 pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
667 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
668 pa_dbus_append_basic_array_variant(&dict_entry_iter, item_type, array, n);
669 pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
670 }
671
672 void pa_dbus_append_proplist(DBusMessageIter *iter, pa_proplist *proplist) {
673 DBusMessageIter dict_iter;
674 DBusMessageIter dict_entry_iter;
675 DBusMessageIter array_iter;
676 void *state = NULL;
677 const char *key;
678
679 pa_assert(iter);
680 pa_assert(proplist);
681
682 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{say}", &dict_iter));
683
684 while ((key = pa_proplist_iterate(proplist, &state))) {
685 const void *value = NULL;
686 size_t nbytes;
687
688 pa_assert_se(pa_proplist_get(proplist, key, &value, &nbytes) >= 0);
689
690 pa_assert_se(dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
691
692 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
693
694 pa_assert_se(dbus_message_iter_open_container(&dict_entry_iter, DBUS_TYPE_ARRAY, "y", &array_iter));
695 pa_assert_se(dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, &value, nbytes));
696 pa_assert_se(dbus_message_iter_close_container(&dict_entry_iter, &array_iter));
697
698 pa_assert_se(dbus_message_iter_close_container(&dict_iter, &dict_entry_iter));
699 }
700
701 pa_assert_se(dbus_message_iter_close_container(iter, &dict_iter));
702 }
703
704 void pa_dbus_append_proplist_variant(DBusMessageIter *iter, pa_proplist *proplist) {
705 DBusMessageIter variant_iter;
706
707 pa_assert(iter);
708 pa_assert(proplist);
709
710 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{say}", &variant_iter));
711 pa_dbus_append_proplist(&variant_iter, proplist);
712 pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
713 }
714
715 void pa_dbus_append_proplist_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, pa_proplist *proplist) {
716 DBusMessageIter dict_entry_iter;
717
718 pa_assert(dict_iter);
719 pa_assert(key);
720 pa_assert(proplist);
721
722 pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
723 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
724 pa_dbus_append_proplist_variant(&dict_entry_iter, proplist);
725 pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
726 }
727
728 pa_proplist *pa_dbus_get_proplist_arg(DBusConnection *c, DBusMessage *msg, DBusMessageIter *iter) {
729 DBusMessageIter dict_iter;
730 DBusMessageIter dict_entry_iter;
731 pa_proplist *proplist = NULL;
732 const char *key = NULL;
733 const uint8_t *value = NULL;
734 int value_length = 0;
735
736 pa_assert(c);
737 pa_assert(msg);
738 pa_assert(iter);
739 pa_assert(pa_streq(dbus_message_iter_get_signature(iter), "a{say}"));
740
741 proplist = pa_proplist_new();
742
743 dbus_message_iter_recurse(iter, &dict_iter);
744
745 while (dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_INVALID) {
746 dbus_message_iter_recurse(&dict_iter, &dict_entry_iter);
747
748 dbus_message_iter_get_basic(&dict_entry_iter, &key);
749 dbus_message_iter_next(&dict_entry_iter);
750
751 if (strlen(key) <= 0 || !pa_ascii_valid(key)) {
752 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Invalid property list key: '%s'.", key);
753 goto fail;
754 }
755
756 dbus_message_iter_get_fixed_array(&dict_entry_iter, &value, &value_length);
757
758 pa_assert(value_length >= 0);
759
760 pa_assert_se(pa_proplist_set(proplist, key, value, value_length) >= 0);
761
762 dbus_message_iter_next(&dict_iter);
763 }
764
765 dbus_message_iter_next(iter);
766
767 return proplist;
768
769 fail:
770 if (proplist)
771 pa_proplist_free(proplist);
772
773 return NULL;
774 }