]> code.delx.au - pulseaudio/blob - src/pulse/context.c
context: document why we only do minimal cleanups before the autospawn exec()
[pulseaudio] / src / pulse / context.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2008 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
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 <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 #include <sys/stat.h>
33 #include <errno.h>
34 #include <signal.h>
35 #include <limits.h>
36 #include <locale.h>
37
38 #ifdef HAVE_SYS_WAIT_H
39 #include <sys/wait.h>
40 #endif
41
42 #ifdef HAVE_SYS_SOCKET_H
43 #include <sys/socket.h>
44 #endif
45 #ifdef HAVE_SYS_UN_H
46 #include <sys/un.h>
47 #endif
48 #ifdef HAVE_NETDB_H
49 #include <netdb.h>
50 #endif
51
52 #include <pulse/version.h>
53 #include <pulse/xmalloc.h>
54 #include <pulse/utf8.h>
55 #include <pulse/util.h>
56 #include <pulse/i18n.h>
57 #include <pulse/mainloop.h>
58 #include <pulse/timeval.h>
59
60 #include <pulsecore/winsock.h>
61 #include <pulsecore/core-error.h>
62
63 #include <pulsecore/native-common.h>
64 #include <pulsecore/pdispatch.h>
65 #include <pulsecore/pstream.h>
66 #include <pulsecore/dynarray.h>
67 #include <pulsecore/socket-client.h>
68 #include <pulsecore/pstream-util.h>
69 #include <pulsecore/core-rtclock.h>
70 #include <pulsecore/core-util.h>
71 #include <pulsecore/log.h>
72 #include <pulsecore/socket-util.h>
73 #include <pulsecore/creds.h>
74 #include <pulsecore/macro.h>
75 #include <pulsecore/proplist-util.h>
76
77 #include "internal.h"
78
79 #include "client-conf.h"
80 #include "fork-detect.h"
81
82 #ifdef HAVE_X11
83 #include "client-conf-x11.h"
84 #endif
85
86 #include "context.h"
87
88 void pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
89
90 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
91 [PA_COMMAND_REQUEST] = pa_command_request,
92 [PA_COMMAND_OVERFLOW] = pa_command_overflow_or_underflow,
93 [PA_COMMAND_UNDERFLOW] = pa_command_overflow_or_underflow,
94 [PA_COMMAND_PLAYBACK_STREAM_KILLED] = pa_command_stream_killed,
95 [PA_COMMAND_RECORD_STREAM_KILLED] = pa_command_stream_killed,
96 [PA_COMMAND_PLAYBACK_STREAM_MOVED] = pa_command_stream_moved,
97 [PA_COMMAND_RECORD_STREAM_MOVED] = pa_command_stream_moved,
98 [PA_COMMAND_PLAYBACK_STREAM_SUSPENDED] = pa_command_stream_suspended,
99 [PA_COMMAND_RECORD_STREAM_SUSPENDED] = pa_command_stream_suspended,
100 [PA_COMMAND_STARTED] = pa_command_stream_started,
101 [PA_COMMAND_SUBSCRIBE_EVENT] = pa_command_subscribe_event,
102 [PA_COMMAND_EXTENSION] = pa_command_extension,
103 [PA_COMMAND_PLAYBACK_STREAM_EVENT] = pa_command_stream_event,
104 [PA_COMMAND_RECORD_STREAM_EVENT] = pa_command_stream_event,
105 [PA_COMMAND_CLIENT_EVENT] = pa_command_client_event,
106 [PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED] = pa_command_stream_buffer_attr,
107 [PA_COMMAND_RECORD_BUFFER_ATTR_CHANGED] = pa_command_stream_buffer_attr
108 };
109 static void context_free(pa_context *c);
110
111 #ifdef HAVE_DBUS
112 static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, void *userdata);
113 #endif
114
115 pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) {
116 return pa_context_new_with_proplist(mainloop, name, NULL);
117 }
118
119 static void reset_callbacks(pa_context *c) {
120 pa_assert(c);
121
122 c->state_callback = NULL;
123 c->state_userdata = NULL;
124
125 c->subscribe_callback = NULL;
126 c->subscribe_userdata = NULL;
127
128 c->event_callback = NULL;
129 c->event_userdata = NULL;
130
131 c->ext_stream_restore.callback = NULL;
132 c->ext_stream_restore.userdata = NULL;
133 }
134
135 pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *p) {
136 pa_context *c;
137
138 pa_assert(mainloop);
139
140 if (pa_detect_fork())
141 return NULL;
142
143 pa_init_i18n();
144
145 c = pa_xnew(pa_context, 1);
146 PA_REFCNT_INIT(c);
147
148 c->proplist = p ? pa_proplist_copy(p) : pa_proplist_new();
149
150 if (name)
151 pa_proplist_sets(c->proplist, PA_PROP_APPLICATION_NAME, name);
152
153 #ifdef HAVE_DBUS
154 c->system_bus = c->session_bus = NULL;
155 #endif
156 c->mainloop = mainloop;
157 c->client = NULL;
158 c->pstream = NULL;
159 c->pdispatch = NULL;
160 c->playback_streams = pa_dynarray_new();
161 c->record_streams = pa_dynarray_new();
162 c->client_index = PA_INVALID_INDEX;
163 c->use_rtclock = pa_mainloop_is_our_api(mainloop);
164
165 PA_LLIST_HEAD_INIT(pa_stream, c->streams);
166 PA_LLIST_HEAD_INIT(pa_operation, c->operations);
167
168 c->error = PA_OK;
169 c->state = PA_CONTEXT_UNCONNECTED;
170 c->ctag = 0;
171 c->csyncid = 0;
172
173 reset_callbacks(c);
174
175 c->is_local = FALSE;
176 c->server_list = NULL;
177 c->server = NULL;
178
179 c->do_shm = FALSE;
180
181 c->server_specified = FALSE;
182 c->no_fail = FALSE;
183 c->do_autospawn = FALSE;
184 memset(&c->spawn_api, 0, sizeof(c->spawn_api));
185
186 #ifndef MSG_NOSIGNAL
187 #ifdef SIGPIPE
188 pa_check_signal_is_blocked(SIGPIPE);
189 #endif
190 #endif
191
192 c->conf = pa_client_conf_new();
193 pa_client_conf_load(c->conf, NULL);
194 #ifdef HAVE_X11
195 pa_client_conf_from_x11(c->conf, NULL);
196 #endif
197 pa_client_conf_env(c->conf);
198
199 if (!(c->mempool = pa_mempool_new(!c->conf->disable_shm, c->conf->shm_size))) {
200
201 if (!c->conf->disable_shm)
202 c->mempool = pa_mempool_new(FALSE, c->conf->shm_size);
203
204 if (!c->mempool) {
205 context_free(c);
206 return NULL;
207 }
208 }
209
210 return c;
211 }
212
213 static void context_unlink(pa_context *c) {
214 pa_stream *s;
215
216 pa_assert(c);
217
218 s = c->streams ? pa_stream_ref(c->streams) : NULL;
219 while (s) {
220 pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL;
221 pa_stream_set_state(s, c->state == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED);
222 pa_stream_unref(s);
223 s = n;
224 }
225
226 while (c->operations)
227 pa_operation_cancel(c->operations);
228
229 if (c->pdispatch) {
230 pa_pdispatch_unref(c->pdispatch);
231 c->pdispatch = NULL;
232 }
233
234 if (c->pstream) {
235 pa_pstream_unlink(c->pstream);
236 pa_pstream_unref(c->pstream);
237 c->pstream = NULL;
238 }
239
240 if (c->client) {
241 pa_socket_client_unref(c->client);
242 c->client = NULL;
243 }
244
245 reset_callbacks(c);
246 }
247
248 static void context_free(pa_context *c) {
249 pa_assert(c);
250
251 context_unlink(c);
252
253 #ifdef HAVE_DBUS
254 if (c->system_bus) {
255 dbus_connection_remove_filter(pa_dbus_wrap_connection_get(c->system_bus), filter_cb, c);
256 pa_dbus_wrap_connection_free(c->system_bus);
257 }
258
259 if (c->session_bus) {
260 dbus_connection_remove_filter(pa_dbus_wrap_connection_get(c->session_bus), filter_cb, c);
261 pa_dbus_wrap_connection_free(c->session_bus);
262 }
263 #endif
264
265 if (c->record_streams)
266 pa_dynarray_free(c->record_streams, NULL, NULL);
267 if (c->playback_streams)
268 pa_dynarray_free(c->playback_streams, NULL, NULL);
269
270 if (c->mempool)
271 pa_mempool_free(c->mempool);
272
273 if (c->conf)
274 pa_client_conf_free(c->conf);
275
276 pa_strlist_free(c->server_list);
277
278 if (c->proplist)
279 pa_proplist_free(c->proplist);
280
281 pa_xfree(c->server);
282 pa_xfree(c);
283 }
284
285 pa_context* pa_context_ref(pa_context *c) {
286 pa_assert(c);
287 pa_assert(PA_REFCNT_VALUE(c) >= 1);
288
289 PA_REFCNT_INC(c);
290 return c;
291 }
292
293 void pa_context_unref(pa_context *c) {
294 pa_assert(c);
295 pa_assert(PA_REFCNT_VALUE(c) >= 1);
296
297 if (PA_REFCNT_DEC(c) <= 0)
298 context_free(c);
299 }
300
301 void pa_context_set_state(pa_context *c, pa_context_state_t st) {
302 pa_assert(c);
303 pa_assert(PA_REFCNT_VALUE(c) >= 1);
304
305 if (c->state == st)
306 return;
307
308 pa_context_ref(c);
309
310 c->state = st;
311
312 if (c->state_callback)
313 c->state_callback(c, c->state_userdata);
314
315 if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED)
316 context_unlink(c);
317
318 pa_context_unref(c);
319 }
320
321 int pa_context_set_error(pa_context *c, int error) {
322 pa_assert(error >= 0);
323 pa_assert(error < PA_ERR_MAX);
324
325 if (c)
326 c->error = error;
327
328 return error;
329 }
330
331 void pa_context_fail(pa_context *c, int error) {
332 pa_assert(c);
333 pa_assert(PA_REFCNT_VALUE(c) >= 1);
334
335 pa_context_set_error(c, error);
336 pa_context_set_state(c, PA_CONTEXT_FAILED);
337 }
338
339 static void pstream_die_callback(pa_pstream *p, void *userdata) {
340 pa_context *c = userdata;
341
342 pa_assert(p);
343 pa_assert(c);
344
345 pa_context_fail(c, PA_ERR_CONNECTIONTERMINATED);
346 }
347
348 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
349 pa_context *c = userdata;
350
351 pa_assert(p);
352 pa_assert(packet);
353 pa_assert(c);
354
355 pa_context_ref(c);
356
357 if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0)
358 pa_context_fail(c, PA_ERR_PROTOCOL);
359
360 pa_context_unref(c);
361 }
362
363 static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) {
364 pa_context *c = userdata;
365 pa_stream *s;
366
367 pa_assert(p);
368 pa_assert(chunk);
369 pa_assert(chunk->length > 0);
370 pa_assert(c);
371 pa_assert(PA_REFCNT_VALUE(c) >= 1);
372
373 pa_context_ref(c);
374
375 if ((s = pa_dynarray_get(c->record_streams, channel))) {
376
377 if (chunk->memblock) {
378 pa_memblockq_seek(s->record_memblockq, offset, seek, TRUE);
379 pa_memblockq_push_align(s->record_memblockq, chunk);
380 } else
381 pa_memblockq_seek(s->record_memblockq, offset+chunk->length, seek, TRUE);
382
383 if (s->read_callback) {
384 size_t l;
385
386 if ((l = pa_memblockq_get_length(s->record_memblockq)) > 0)
387 s->read_callback(s, l, s->read_userdata);
388 }
389 }
390
391 pa_context_unref(c);
392 }
393
394 int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t, pa_bool_t fail) {
395 uint32_t err;
396 pa_assert(c);
397 pa_assert(PA_REFCNT_VALUE(c) >= 1);
398
399 if (command == PA_COMMAND_ERROR) {
400 pa_assert(t);
401
402 if (pa_tagstruct_getu32(t, &err) < 0 ||
403 !pa_tagstruct_eof(t)) {
404 pa_context_fail(c, PA_ERR_PROTOCOL);
405 return -1;
406 }
407
408 } else if (command == PA_COMMAND_TIMEOUT)
409 err = PA_ERR_TIMEOUT;
410 else {
411 pa_context_fail(c, PA_ERR_PROTOCOL);
412 return -1;
413 }
414
415 if (err == PA_OK) {
416 pa_context_fail(c, PA_ERR_PROTOCOL);
417 return -1;
418 }
419
420 if (err >= PA_ERR_MAX)
421 err = PA_ERR_UNKNOWN;
422
423 if (fail) {
424 pa_context_fail(c, (int) err);
425 return -1;
426 }
427
428 pa_context_set_error(c, (int) err);
429
430 return 0;
431 }
432
433 static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
434 pa_context *c = userdata;
435
436 pa_assert(pd);
437 pa_assert(c);
438 pa_assert(c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME);
439
440 pa_context_ref(c);
441
442 if (command != PA_COMMAND_REPLY) {
443 pa_context_handle_error(c, command, t, TRUE);
444 goto finish;
445 }
446
447 switch(c->state) {
448 case PA_CONTEXT_AUTHORIZING: {
449 pa_tagstruct *reply;
450 pa_bool_t shm_on_remote = FALSE;
451
452 if (pa_tagstruct_getu32(t, &c->version) < 0 ||
453 !pa_tagstruct_eof(t)) {
454 pa_context_fail(c, PA_ERR_PROTOCOL);
455 goto finish;
456 }
457
458 /* Minimum supported version */
459 if (c->version < 8) {
460 pa_context_fail(c, PA_ERR_VERSION);
461 goto finish;
462 }
463
464 /* Starting with protocol version 13 the MSB of the version
465 tag reflects if shm is available for this connection or
466 not. */
467 if (c->version >= 13) {
468 shm_on_remote = !!(c->version & 0x80000000U);
469 c->version &= 0x7FFFFFFFU;
470 }
471
472 pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
473
474 /* Enable shared memory support if possible */
475 if (c->do_shm)
476 if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
477 c->do_shm = FALSE;
478
479 if (c->do_shm) {
480
481 /* Only enable SHM if both sides are owned by the same
482 * user. This is a security measure because otherwise
483 * data private to the user might leak. */
484
485 #ifdef HAVE_CREDS
486 const pa_creds *creds;
487 if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
488 c->do_shm = FALSE;
489 #endif
490 }
491
492 pa_log_debug("Negotiated SHM: %s", pa_yes_no(c->do_shm));
493 pa_pstream_enable_shm(c->pstream, c->do_shm);
494
495 reply = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag);
496
497 if (c->version >= 13) {
498 pa_init_proplist(c->proplist);
499 pa_tagstruct_put_proplist(reply, c->proplist);
500 } else
501 pa_tagstruct_puts(reply, pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME));
502
503 pa_pstream_send_tagstruct(c->pstream, reply);
504 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL);
505
506 pa_context_set_state(c, PA_CONTEXT_SETTING_NAME);
507 break;
508 }
509
510 case PA_CONTEXT_SETTING_NAME :
511
512 if ((c->version >= 13 && (pa_tagstruct_getu32(t, &c->client_index) < 0 ||
513 c->client_index == PA_INVALID_INDEX)) ||
514 !pa_tagstruct_eof(t)) {
515 pa_context_fail(c, PA_ERR_PROTOCOL);
516 goto finish;
517 }
518
519 pa_context_set_state(c, PA_CONTEXT_READY);
520 break;
521
522 default:
523 pa_assert_not_reached();
524 }
525
526 finish:
527 pa_context_unref(c);
528 }
529
530 static void setup_context(pa_context *c, pa_iochannel *io) {
531 pa_tagstruct *t;
532 uint32_t tag;
533
534 pa_assert(c);
535 pa_assert(io);
536
537 pa_context_ref(c);
538
539 pa_assert(!c->pstream);
540 c->pstream = pa_pstream_new(c->mainloop, io, c->mempool);
541
542 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
543 pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
544 pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
545
546 pa_assert(!c->pdispatch);
547 c->pdispatch = pa_pdispatch_new(c->mainloop, c->use_rtclock, command_table, PA_COMMAND_MAX);
548
549 if (!c->conf->cookie_valid)
550 pa_log_info(_("No cookie loaded. Attempting to connect without."));
551
552 t = pa_tagstruct_command(c, PA_COMMAND_AUTH, &tag);
553
554 c->do_shm =
555 pa_mempool_is_shared(c->mempool) &&
556 c->is_local;
557
558 pa_log_debug("SHM possible: %s", pa_yes_no(c->do_shm));
559
560 /* Starting with protocol version 13 we use the MSB of the version
561 * tag for informing the other side if we could do SHM or not */
562 pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION | (c->do_shm ? 0x80000000U : 0));
563 pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie));
564
565 #ifdef HAVE_CREDS
566 {
567 pa_creds ucred;
568
569 if (pa_iochannel_creds_supported(io))
570 pa_iochannel_creds_enable(io);
571
572 ucred.uid = getuid();
573 ucred.gid = getgid();
574
575 pa_pstream_send_tagstruct_with_creds(c->pstream, t, &ucred);
576 }
577 #else
578 pa_pstream_send_tagstruct(c->pstream, t);
579 #endif
580
581 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL);
582
583 pa_context_set_state(c, PA_CONTEXT_AUTHORIZING);
584
585 pa_context_unref(c);
586 }
587
588 #ifdef ENABLE_LEGACY_RUNTIME_DIR
589 static char *get_old_legacy_runtime_dir(void) {
590 char *p, u[128];
591 struct stat st;
592
593 if (!pa_get_user_name(u, sizeof(u)))
594 return NULL;
595
596 p = pa_sprintf_malloc("/tmp/pulse-%s", u);
597
598 if (stat(p, &st) < 0) {
599 pa_xfree(p);
600 return NULL;
601 }
602
603 if (st.st_uid != getuid()) {
604 pa_xfree(p);
605 return NULL;
606 }
607
608 return p;
609 }
610
611 static char *get_very_old_legacy_runtime_dir(void) {
612 char *p, h[128];
613 struct stat st;
614
615 if (!pa_get_home_dir(h, sizeof(h)))
616 return NULL;
617
618 p = pa_sprintf_malloc("%s/.pulse", h);
619
620 if (stat(p, &st) < 0) {
621 pa_xfree(p);
622 return NULL;
623 }
624
625 if (st.st_uid != getuid()) {
626 pa_xfree(p);
627 return NULL;
628 }
629
630 return p;
631 }
632 #endif
633
634 static pa_strlist *prepend_per_user(pa_strlist *l) {
635 char *ufn;
636
637 #ifdef ENABLE_LEGACY_RUNTIME_DIR
638 static char *legacy_dir;
639
640 /* The very old per-user instance path (< 0.9.11). This is supported only to ease upgrades */
641 if ((legacy_dir = get_very_old_legacy_runtime_dir())) {
642 char *p = pa_sprintf_malloc("%s" PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET, legacy_dir);
643 l = pa_strlist_prepend(l, p);
644 pa_xfree(p);
645 pa_xfree(legacy_dir);
646 }
647
648 /* The old per-user instance path (< 0.9.12). This is supported only to ease upgrades */
649 if ((legacy_dir = get_old_legacy_runtime_dir())) {
650 char *p = pa_sprintf_malloc("%s" PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET, legacy_dir);
651 l = pa_strlist_prepend(l, p);
652 pa_xfree(p);
653 pa_xfree(legacy_dir);
654 }
655 #endif
656
657 /* The per-user instance */
658 if ((ufn = pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET))) {
659 l = pa_strlist_prepend(l, ufn);
660 pa_xfree(ufn);
661 }
662
663 return l;
664 }
665
666 #ifndef OS_IS_WIN32
667
668 static int context_autospawn(pa_context *c) {
669 pid_t pid;
670 int status, r;
671 struct sigaction sa;
672
673 pa_context_ref(c);
674
675 if (sigaction(SIGCHLD, NULL, &sa) < 0) {
676 pa_log_debug("sigaction() failed: %s", pa_cstrerror(errno));
677 pa_context_fail(c, PA_ERR_INTERNAL);
678 goto fail;
679 }
680
681 if ((sa.sa_flags & SA_NOCLDWAIT) || sa.sa_handler == SIG_IGN) {
682 pa_log_debug("Process disabled waitpid(), cannot autospawn.");
683 pa_context_fail(c, PA_ERR_CONNECTIONREFUSED);
684 goto fail;
685 }
686
687 pa_log_debug("Trying to autospawn...");
688
689 if (c->spawn_api.prefork)
690 c->spawn_api.prefork();
691
692 if ((pid = fork()) < 0) {
693 pa_log_error(_("fork(): %s"), pa_cstrerror(errno));
694 pa_context_fail(c, PA_ERR_INTERNAL);
695
696 if (c->spawn_api.postfork)
697 c->spawn_api.postfork();
698
699 goto fail;
700 } else if (!pid) {
701 /* Child */
702
703 const char *state = NULL;
704 const char * argv[32];
705 unsigned n = 0;
706
707 if (c->spawn_api.atfork)
708 c->spawn_api.atfork();
709
710 /* We leave most of the cleaning up of the process environment
711 * to the executable. We only clean up the file descriptors to
712 * make sure the executable can actually be loaded
713 * correctly. */
714 pa_close_all(-1);
715
716 /* Setup argv */
717 argv[n++] = c->conf->daemon_binary;
718 argv[n++] = "--start";
719
720 while (n < PA_ELEMENTSOF(argv)-1) {
721 char *a;
722
723 if (!(a = pa_split_spaces(c->conf->extra_arguments, &state)))
724 break;
725
726 argv[n++] = a;
727 }
728
729 argv[n++] = NULL;
730 pa_assert(n <= PA_ELEMENTSOF(argv));
731
732 execv(argv[0], (char * const *) argv);
733 _exit(1);
734 }
735
736 /* Parent */
737
738 if (c->spawn_api.postfork)
739 c->spawn_api.postfork();
740
741 do {
742 r = waitpid(pid, &status, 0);
743 } while (r < 0 && errno == EINTR);
744
745 if (r < 0) {
746
747 if (errno != ESRCH) {
748 pa_log(_("waitpid(): %s"), pa_cstrerror(errno));
749 pa_context_fail(c, PA_ERR_INTERNAL);
750 goto fail;
751 }
752
753 /* hmm, something already reaped our child, so we assume
754 * startup worked, even if we cannot know */
755
756 } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
757 pa_context_fail(c, PA_ERR_CONNECTIONREFUSED);
758 goto fail;
759 }
760
761 pa_context_unref(c);
762
763 return 0;
764
765 fail:
766
767 pa_context_unref(c);
768
769 return -1;
770 }
771
772 #endif /* OS_IS_WIN32 */
773
774 static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata);
775
776 #ifdef HAVE_DBUS
777 static void track_pulseaudio_on_dbus(pa_context *c, DBusBusType type, pa_dbus_wrap_connection **conn) {
778 DBusError error;
779
780 pa_assert(c);
781 pa_assert(conn);
782
783 dbus_error_init(&error);
784
785 if (!(*conn = pa_dbus_wrap_connection_new(c->mainloop, c->use_rtclock, type, &error)) || dbus_error_is_set(&error)) {
786 pa_log_warn("Unable to contact DBUS: %s: %s", error.name, error.message);
787 goto fail;
788 }
789
790 if (!dbus_connection_add_filter(pa_dbus_wrap_connection_get(*conn), filter_cb, c, NULL)) {
791 pa_log_warn("Failed to add filter function");
792 goto fail;
793 }
794
795 if (pa_dbus_add_matches(
796 pa_dbus_wrap_connection_get(*conn), &error,
797 "type='signal',sender='" DBUS_SERVICE_DBUS "',interface='" DBUS_INTERFACE_DBUS "',member='NameOwnerChanged',arg0='org.pulseaudio.Server',arg1=''", NULL) < 0) {
798
799 pa_log_warn("Unable to track org.pulseaudio.Server: %s: %s", error.name, error.message);
800 goto fail;
801 }
802
803 return;
804
805 fail:
806 if (*conn) {
807 pa_dbus_wrap_connection_free(*conn);
808 *conn = NULL;
809 }
810
811 dbus_error_free(&error);
812 }
813 #endif
814
815 static int try_next_connection(pa_context *c) {
816 char *u = NULL;
817 int r = -1;
818
819 pa_assert(c);
820 pa_assert(!c->client);
821
822 for (;;) {
823 pa_xfree(u);
824 u = NULL;
825
826 c->server_list = pa_strlist_pop(c->server_list, &u);
827
828 if (!u) {
829
830 #ifndef OS_IS_WIN32
831 if (c->do_autospawn) {
832
833 if ((r = context_autospawn(c)) < 0)
834 goto finish;
835
836 /* Autospawn only once */
837 c->do_autospawn = FALSE;
838
839 /* Connect only to per-user sockets this time */
840 c->server_list = prepend_per_user(c->server_list);
841
842 /* Retry connection */
843 continue;
844 }
845 #endif
846
847 #ifdef HAVE_DBUS
848 if (c->no_fail && !c->server_specified) {
849 if (!c->session_bus)
850 track_pulseaudio_on_dbus(c, DBUS_BUS_SESSION, &c->session_bus);
851 if (!c->system_bus)
852 track_pulseaudio_on_dbus(c, DBUS_BUS_SYSTEM, &c->system_bus);
853 } else
854 #endif
855 pa_context_fail(c, PA_ERR_CONNECTIONREFUSED);
856
857 goto finish;
858 }
859
860 pa_log_debug("Trying to connect to %s...", u);
861
862 pa_xfree(c->server);
863 c->server = pa_xstrdup(u);
864
865 if (!(c->client = pa_socket_client_new_string(c->mainloop, c->use_rtclock, u, PA_NATIVE_DEFAULT_PORT)))
866 continue;
867
868 c->is_local = !!pa_socket_client_is_local(c->client);
869 pa_socket_client_set_callback(c->client, on_connection, c);
870 break;
871 }
872
873 r = 0;
874
875 finish:
876 pa_xfree(u);
877
878 return r;
879 }
880
881 static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata) {
882 pa_context *c = userdata;
883 int saved_errno = errno;
884
885 pa_assert(client);
886 pa_assert(c);
887 pa_assert(c->state == PA_CONTEXT_CONNECTING);
888
889 pa_context_ref(c);
890
891 pa_socket_client_unref(client);
892 c->client = NULL;
893
894 if (!io) {
895 /* Try the next item in the list */
896 if (saved_errno == ECONNREFUSED ||
897 saved_errno == ETIMEDOUT ||
898 saved_errno == EHOSTUNREACH) {
899 try_next_connection(c);
900 goto finish;
901 }
902
903 pa_context_fail(c, PA_ERR_CONNECTIONREFUSED);
904 goto finish;
905 }
906
907 setup_context(c, io);
908
909 finish:
910 pa_context_unref(c);
911 }
912
913 #ifdef HAVE_DBUS
914 static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, void *userdata) {
915 pa_context *c = userdata;
916 pa_bool_t is_session;
917
918 pa_assert(bus);
919 pa_assert(message);
920 pa_assert(c);
921
922 if (c->state != PA_CONTEXT_CONNECTING)
923 goto finish;
924
925 if (!c->no_fail)
926 goto finish;
927
928 /* FIXME: We probably should check if this is actually the NameOwnerChanged we were looking for */
929
930 is_session = c->session_bus && bus == pa_dbus_wrap_connection_get(c->session_bus);
931 pa_log_debug("Rock!! PulseAudio might be back on %s bus", is_session ? "session" : "system");
932
933 if (is_session)
934 /* The user instance via PF_LOCAL */
935 c->server_list = prepend_per_user(c->server_list);
936 else
937 /* The system wide instance via PF_LOCAL */
938 c->server_list = pa_strlist_prepend(c->server_list, PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET);
939
940 if (!c->client)
941 try_next_connection(c);
942
943 finish:
944 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
945 }
946 #endif
947
948 int pa_context_connect(
949 pa_context *c,
950 const char *server,
951 pa_context_flags_t flags,
952 const pa_spawn_api *api) {
953
954 int r = -1;
955
956 pa_assert(c);
957 pa_assert(PA_REFCNT_VALUE(c) >= 1);
958
959 PA_CHECK_VALIDITY(c, !pa_detect_fork(), PA_ERR_FORKED);
960 PA_CHECK_VALIDITY(c, c->state == PA_CONTEXT_UNCONNECTED, PA_ERR_BADSTATE);
961 PA_CHECK_VALIDITY(c, !(flags & ~(PA_CONTEXT_NOAUTOSPAWN|PA_CONTEXT_NOFAIL)), PA_ERR_INVALID);
962 PA_CHECK_VALIDITY(c, !server || *server, PA_ERR_INVALID);
963
964 if (server)
965 c->conf->autospawn = FALSE;
966 else
967 server = c->conf->default_server;
968
969 pa_context_ref(c);
970
971 c->no_fail = !!(flags & PA_CONTEXT_NOFAIL);
972 c->server_specified = !!server;
973 pa_assert(!c->server_list);
974
975 if (server) {
976 if (!(c->server_list = pa_strlist_parse(server))) {
977 pa_context_fail(c, PA_ERR_INVALIDSERVER);
978 goto finish;
979 }
980
981 } else {
982 char *d;
983
984 /* Prepend in reverse order */
985
986 /* Follow the X display */
987 if ((d = getenv("DISPLAY"))) {
988 d = pa_xstrndup(d, strcspn(d, ":"));
989
990 if (*d)
991 c->server_list = pa_strlist_prepend(c->server_list, d);
992
993 pa_xfree(d);
994 }
995
996 /* Add TCP/IP on the localhost */
997 c->server_list = pa_strlist_prepend(c->server_list, "tcp6:[::1]");
998 c->server_list = pa_strlist_prepend(c->server_list, "tcp4:127.0.0.1");
999
1000 /* The system wide instance via PF_LOCAL */
1001 c->server_list = pa_strlist_prepend(c->server_list, PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET);
1002
1003 /* The user instance via PF_LOCAL */
1004 c->server_list = prepend_per_user(c->server_list);
1005 }
1006
1007 /* Set up autospawning */
1008 if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) {
1009
1010 if (getuid() == 0)
1011 pa_log_debug("Not doing autospawn since we are root.");
1012 else {
1013 c->do_autospawn = TRUE;
1014
1015 if (api)
1016 c->spawn_api = *api;
1017 }
1018 }
1019
1020 pa_context_set_state(c, PA_CONTEXT_CONNECTING);
1021 r = try_next_connection(c);
1022
1023 finish:
1024 pa_context_unref(c);
1025
1026 return r;
1027 }
1028
1029 void pa_context_disconnect(pa_context *c) {
1030 pa_assert(c);
1031 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1032
1033 if (pa_detect_fork())
1034 return;
1035
1036 if (PA_CONTEXT_IS_GOOD(c->state))
1037 pa_context_set_state(c, PA_CONTEXT_TERMINATED);
1038 }
1039
1040 pa_context_state_t pa_context_get_state(pa_context *c) {
1041 pa_assert(c);
1042 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1043
1044 return c->state;
1045 }
1046
1047 int pa_context_errno(pa_context *c) {
1048 pa_assert(c);
1049 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1050
1051 return c->error;
1052 }
1053
1054 void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
1055 pa_assert(c);
1056 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1057
1058 if (pa_detect_fork())
1059 return;
1060
1061 if (c->state == PA_CONTEXT_TERMINATED || c->state == PA_CONTEXT_FAILED)
1062 return;
1063
1064 c->state_callback = cb;
1065 c->state_userdata = userdata;
1066 }
1067
1068 void pa_context_set_event_callback(pa_context *c, pa_context_event_cb_t cb, void *userdata) {
1069 pa_assert(c);
1070 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1071
1072 if (pa_detect_fork())
1073 return;
1074
1075 if (c->state == PA_CONTEXT_TERMINATED || c->state == PA_CONTEXT_FAILED)
1076 return;
1077
1078 c->event_callback = cb;
1079 c->event_userdata = userdata;
1080 }
1081
1082 int pa_context_is_pending(pa_context *c) {
1083 pa_assert(c);
1084 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1085
1086 PA_CHECK_VALIDITY(c, !pa_detect_fork(), PA_ERR_FORKED);
1087 PA_CHECK_VALIDITY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE);
1088
1089 return (c->pstream && pa_pstream_is_pending(c->pstream)) ||
1090 (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) ||
1091 c->client;
1092 }
1093
1094 static void set_dispatch_callbacks(pa_operation *o);
1095
1096 static void pdispatch_drain_callback(pa_pdispatch*pd, void *userdata) {
1097 set_dispatch_callbacks(userdata);
1098 }
1099
1100 static void pstream_drain_callback(pa_pstream *s, void *userdata) {
1101 set_dispatch_callbacks(userdata);
1102 }
1103
1104 static void set_dispatch_callbacks(pa_operation *o) {
1105 int done = 1;
1106
1107 pa_assert(o);
1108 pa_assert(PA_REFCNT_VALUE(o) >= 1);
1109 pa_assert(o->context);
1110 pa_assert(PA_REFCNT_VALUE(o->context) >= 1);
1111 pa_assert(o->context->state == PA_CONTEXT_READY);
1112
1113 pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL);
1114 pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL);
1115
1116 if (pa_pdispatch_is_pending(o->context->pdispatch)) {
1117 pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o);
1118 done = 0;
1119 }
1120
1121 if (pa_pstream_is_pending(o->context->pstream)) {
1122 pa_pstream_set_drain_callback(o->context->pstream, pstream_drain_callback, o);
1123 done = 0;
1124 }
1125
1126 if (done) {
1127 if (o->callback) {
1128 pa_context_notify_cb_t cb = (pa_context_notify_cb_t) o->callback;
1129 cb(o->context, o->userdata);
1130 }
1131
1132 pa_operation_done(o);
1133 pa_operation_unref(o);
1134 }
1135 }
1136
1137 pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
1138 pa_operation *o;
1139
1140 pa_assert(c);
1141 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1142
1143 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1144 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1145 PA_CHECK_VALIDITY_RETURN_NULL(c, pa_context_is_pending(c), PA_ERR_BADSTATE);
1146
1147 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1148 set_dispatch_callbacks(pa_operation_ref(o));
1149
1150 return o;
1151 }
1152
1153 void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1154 pa_operation *o = userdata;
1155 int success = 1;
1156
1157 pa_assert(pd);
1158 pa_assert(o);
1159 pa_assert(PA_REFCNT_VALUE(o) >= 1);
1160
1161 if (!o->context)
1162 goto finish;
1163
1164 if (command != PA_COMMAND_REPLY) {
1165 if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
1166 goto finish;
1167
1168 success = 0;
1169 } else if (!pa_tagstruct_eof(t)) {
1170 pa_context_fail(o->context, PA_ERR_PROTOCOL);
1171 goto finish;
1172 }
1173
1174 if (o->callback) {
1175 pa_context_success_cb_t cb = (pa_context_success_cb_t) o->callback;
1176 cb(o->context, success, o->userdata);
1177 }
1178
1179 finish:
1180 pa_operation_done(o);
1181 pa_operation_unref(o);
1182 }
1183
1184 pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, pa_pdispatch_cb_t internal_cb, pa_operation_cb_t cb, void *userdata) {
1185 pa_tagstruct *t;
1186 pa_operation *o;
1187 uint32_t tag;
1188
1189 pa_assert(c);
1190 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1191
1192 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1193 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1194
1195 o = pa_operation_new(c, NULL, cb, userdata);
1196
1197 t = pa_tagstruct_command(c, command, &tag);
1198 pa_pstream_send_tagstruct(c->pstream, t);
1199 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1200
1201 return o;
1202 }
1203
1204 pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata) {
1205 pa_assert(c);
1206 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1207
1208 return pa_context_send_simple_command(c, PA_COMMAND_EXIT, pa_context_simple_ack_callback, (pa_operation_cb_t) cb, userdata);
1209 }
1210
1211 pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
1212 pa_tagstruct *t;
1213 pa_operation *o;
1214 uint32_t tag;
1215
1216 pa_assert(c);
1217 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1218
1219 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1220 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1221
1222 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1223 t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SINK, &tag);
1224 pa_tagstruct_puts(t, name);
1225 pa_pstream_send_tagstruct(c->pstream, t);
1226 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1227
1228 return o;
1229 }
1230
1231 pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
1232 pa_tagstruct *t;
1233 pa_operation *o;
1234 uint32_t tag;
1235
1236 pa_assert(c);
1237 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1238
1239 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1240 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1241
1242 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1243 t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SOURCE, &tag);
1244 pa_tagstruct_puts(t, name);
1245 pa_pstream_send_tagstruct(c->pstream, t);
1246 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1247
1248 return o;
1249 }
1250
1251 int pa_context_is_local(pa_context *c) {
1252 pa_assert(c);
1253 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1254
1255 PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, -1);
1256 PA_CHECK_VALIDITY_RETURN_ANY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE, -1);
1257
1258 return !!c->is_local;
1259 }
1260
1261 pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
1262 pa_operation *o;
1263
1264 pa_assert(c);
1265 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1266 pa_assert(name);
1267
1268 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1269 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1270
1271 if (c->version >= 13) {
1272 pa_proplist *p = pa_proplist_new();
1273
1274 pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name);
1275 o = pa_context_proplist_update(c, PA_UPDATE_REPLACE, p, cb, userdata);
1276 pa_proplist_free(p);
1277 } else {
1278 pa_tagstruct *t;
1279 uint32_t tag;
1280
1281 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1282 t = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag);
1283 pa_tagstruct_puts(t, name);
1284 pa_pstream_send_tagstruct(c->pstream, t);
1285 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1286 }
1287
1288 return o;
1289 }
1290
1291 const char* pa_get_library_version(void) {
1292 return PACKAGE_VERSION;
1293 }
1294
1295 const char* pa_context_get_server(pa_context *c) {
1296 pa_assert(c);
1297 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1298
1299 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1300 PA_CHECK_VALIDITY_RETURN_NULL(c, c->server, PA_ERR_NOENTITY);
1301
1302 if (*c->server == '{') {
1303 char *e = strchr(c->server+1, '}');
1304 return e ? e+1 : c->server;
1305 }
1306
1307 return c->server;
1308 }
1309
1310 uint32_t pa_context_get_protocol_version(pa_context *c) {
1311 return PA_PROTOCOL_VERSION;
1312 }
1313
1314 uint32_t pa_context_get_server_protocol_version(pa_context *c) {
1315 pa_assert(c);
1316 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1317
1318 PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, PA_INVALID_INDEX);
1319 PA_CHECK_VALIDITY_RETURN_ANY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE, PA_INVALID_INDEX);
1320
1321 return c->version;
1322 }
1323
1324 pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *tag) {
1325 pa_tagstruct *t;
1326
1327 pa_assert(c);
1328 pa_assert(tag);
1329
1330 t = pa_tagstruct_new(NULL, 0);
1331 pa_tagstruct_putu32(t, command);
1332 pa_tagstruct_putu32(t, *tag = c->ctag++);
1333
1334 return t;
1335 }
1336
1337 uint32_t pa_context_get_index(pa_context *c) {
1338 pa_assert(c);
1339 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1340
1341 PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, PA_INVALID_INDEX);
1342 PA_CHECK_VALIDITY_RETURN_ANY(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX);
1343 PA_CHECK_VALIDITY_RETURN_ANY(c, c->version >= 13, PA_ERR_NOTSUPPORTED, PA_INVALID_INDEX);
1344
1345 return c->client_index;
1346 }
1347
1348 pa_operation *pa_context_proplist_update(pa_context *c, pa_update_mode_t mode, pa_proplist *p, pa_context_success_cb_t cb, void *userdata) {
1349 pa_operation *o;
1350 pa_tagstruct *t;
1351 uint32_t tag;
1352
1353 pa_assert(c);
1354 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1355
1356 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1357 PA_CHECK_VALIDITY_RETURN_NULL(c, mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE, PA_ERR_INVALID);
1358 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1359 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 13, PA_ERR_NOTSUPPORTED);
1360
1361 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1362
1363 t = pa_tagstruct_command(c, PA_COMMAND_UPDATE_CLIENT_PROPLIST, &tag);
1364 pa_tagstruct_putu32(t, (uint32_t) mode);
1365 pa_tagstruct_put_proplist(t, p);
1366
1367 pa_pstream_send_tagstruct(c->pstream, t);
1368 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1369
1370 /* Please note that we don't update c->proplist here, because we
1371 * don't export that field */
1372
1373 return o;
1374 }
1375
1376 pa_operation *pa_context_proplist_remove(pa_context *c, const char *const keys[], pa_context_success_cb_t cb, void *userdata) {
1377 pa_operation *o;
1378 pa_tagstruct *t;
1379 uint32_t tag;
1380 const char * const *k;
1381
1382 pa_assert(c);
1383 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1384
1385 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
1386 PA_CHECK_VALIDITY_RETURN_NULL(c, keys && keys[0], PA_ERR_INVALID);
1387 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1388 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 13, PA_ERR_NOTSUPPORTED);
1389
1390 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
1391
1392 t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_CLIENT_PROPLIST, &tag);
1393
1394 for (k = keys; *k; k++)
1395 pa_tagstruct_puts(t, *k);
1396
1397 pa_tagstruct_puts(t, NULL);
1398
1399 pa_pstream_send_tagstruct(c->pstream, t);
1400 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1401
1402 /* Please note that we don't update c->proplist here, because we
1403 * don't export that field */
1404
1405 return o;
1406 }
1407
1408 void pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1409 pa_context *c = userdata;
1410 uint32_t idx;
1411 const char *name;
1412
1413 pa_assert(pd);
1414 pa_assert(command == PA_COMMAND_EXTENSION);
1415 pa_assert(t);
1416 pa_assert(c);
1417 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1418
1419 pa_context_ref(c);
1420
1421 if (c->version < 15) {
1422 pa_context_fail(c, PA_ERR_PROTOCOL);
1423 goto finish;
1424 }
1425
1426 if (pa_tagstruct_getu32(t, &idx) < 0 ||
1427 pa_tagstruct_gets(t, &name) < 0) {
1428 pa_context_fail(c, PA_ERR_PROTOCOL);
1429 goto finish;
1430 }
1431
1432 if (!strcmp(name, "module-stream-restore"))
1433 pa_ext_stream_restore_command(c, tag, t);
1434 else
1435 pa_log(_("Received message for unknown extension '%s'"), name);
1436
1437 finish:
1438 pa_context_unref(c);
1439 }
1440
1441
1442 void pa_command_client_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1443 pa_context *c = userdata;
1444 pa_proplist *pl = NULL;
1445 const char *event;
1446
1447 pa_assert(pd);
1448 pa_assert(command == PA_COMMAND_CLIENT_EVENT);
1449 pa_assert(t);
1450 pa_assert(c);
1451 pa_assert(PA_REFCNT_VALUE(c) >= 1);
1452
1453 pa_context_ref(c);
1454
1455 if (c->version < 15) {
1456 pa_context_fail(c, PA_ERR_PROTOCOL);
1457 goto finish;
1458 }
1459
1460 pl = pa_proplist_new();
1461
1462 if (pa_tagstruct_gets(t, &event) < 0 ||
1463 pa_tagstruct_get_proplist(t, pl) < 0 ||
1464 !pa_tagstruct_eof(t) || !event) {
1465 pa_context_fail(c, PA_ERR_PROTOCOL);
1466 goto finish;
1467 }
1468
1469 if (c->event_callback)
1470 c->event_callback(c, event, pl, c->event_userdata);
1471
1472 finish:
1473 pa_context_unref(c);
1474
1475 if (pl)
1476 pa_proplist_free(pl);
1477 }
1478
1479 pa_time_event* pa_context_rttime_new(pa_context *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata) {
1480 struct timeval tv;
1481
1482 pa_assert(c);
1483 pa_assert(c->mainloop);
1484
1485 if (usec == PA_USEC_INVALID)
1486 return c->mainloop->time_new(c->mainloop, NULL, cb, userdata);
1487
1488 pa_timeval_rtstore(&tv, usec, c->use_rtclock);
1489
1490 return c->mainloop->time_new(c->mainloop, &tv, cb, userdata);
1491 }
1492
1493 void pa_context_rttime_restart(pa_context *c, pa_time_event *e, pa_usec_t usec) {
1494 struct timeval tv;
1495
1496 pa_assert(c);
1497 pa_assert(c->mainloop);
1498
1499 if (usec == PA_USEC_INVALID)
1500 c->mainloop->time_restart(e, NULL);
1501 else {
1502 pa_timeval_rtstore(&tv, usec, c->use_rtclock);
1503 c->mainloop->time_restart(e, &tv);
1504 }
1505 }