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