1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 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
9 published by the Free Software Foundation; either version 2.1 of the
10 License, 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 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #include <pulse/rtclock.h>
29 #include <pulse/timeval.h>
30 #include <pulse/xmalloc.h>
31
32 #include <pulsecore/native-common.h>
33 #include <pulsecore/llist.h>
34 #include <pulsecore/log.h>
35 #include <pulsecore/core-util.h>
36 #include <pulsecore/macro.h>
37 #include <pulsecore/refcnt.h>
38 #include <pulsecore/flist.h>
39 #include <pulsecore/core-rtclock.h>
40
41 #include "pdispatch.h"
42
43 #define DEBUG_OPCODES
44
45 #ifdef DEBUG_OPCODES
46
47 static const char *command_names[PA_COMMAND_MAX] = {
48 /* Generic commands */
49 [PA_COMMAND_ERROR] = "ERROR",
50 [PA_COMMAND_TIMEOUT] = "TIMEOUT",
51 [PA_COMMAND_REPLY] = "REPLY",
52
53 /* CLIENT->SERVER */
54 [PA_COMMAND_CREATE_PLAYBACK_STREAM] = "CREATE_PLAYBACK_STREAM",
55 [PA_COMMAND_DELETE_PLAYBACK_STREAM] = "DELETE_PLAYBACK_STREAM",
56 [PA_COMMAND_CREATE_RECORD_STREAM] = "CREATE_RECORD_STREAM",
57 [PA_COMMAND_DELETE_RECORD_STREAM] = "DELETE_RECORD_STREAM",
58 [PA_COMMAND_AUTH] = "AUTH",
59 [PA_COMMAND_EXIT] = "EXIT",
60 [PA_COMMAND_SET_CLIENT_NAME] = "SET_CLIENT_NAME",
61 [PA_COMMAND_LOOKUP_SINK] = "LOOKUP_SINK",
62 [PA_COMMAND_LOOKUP_SOURCE] = "LOOKUP_SOURCE",
63 [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = "DRAIN_PLAYBACK_STREAM",
64 [PA_COMMAND_STAT] = "STAT",
65 [PA_COMMAND_GET_PLAYBACK_LATENCY] = "GET_PLAYBACK_LATENCY",
66 [PA_COMMAND_CREATE_UPLOAD_STREAM] = "CREATE_UPLOAD_STREAM",
67 [PA_COMMAND_DELETE_UPLOAD_STREAM] = "DELETE_UPLOAD_STREAM",
68 [PA_COMMAND_FINISH_UPLOAD_STREAM] = "FINISH_UPLOAD_STREAM",
69 [PA_COMMAND_PLAY_SAMPLE] = "PLAY_SAMPLE",
70 [PA_COMMAND_REMOVE_SAMPLE] = "REMOVE_SAMPLE",
71
72 [PA_COMMAND_GET_SERVER_INFO] = "GET_SERVER_INFO",
73 [PA_COMMAND_GET_SINK_INFO] = "GET_SINK_INFO",
74 [PA_COMMAND_GET_SINK_INFO_LIST] = "GET_SINK_INFO_LIST",
75 [PA_COMMAND_GET_SOURCE_INFO] = "GET_SOURCE_INFO",
76 [PA_COMMAND_GET_SOURCE_INFO_LIST] = "GET_SOURCE_INFO_LIST",
77 [PA_COMMAND_GET_MODULE_INFO] = "GET_MODULE_INFO",
78 [PA_COMMAND_GET_MODULE_INFO_LIST] = "GET_MODULE_INFO_LIST",
79 [PA_COMMAND_GET_CLIENT_INFO] = "GET_CLIENT_INFO",
80 [PA_COMMAND_GET_CLIENT_INFO_LIST] = "GET_CLIENT_INFO_LIST",
81 [PA_COMMAND_GET_SAMPLE_INFO] = "GET_SAMPLE_INFO",
82 [PA_COMMAND_GET_SAMPLE_INFO_LIST] = "GET_SAMPLE_INFO_LIST",
83 [PA_COMMAND_GET_SINK_INPUT_INFO] = "GET_SINK_INPUT_INFO",
84 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = "GET_SINK_INPUT_INFO_LIST",
85 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = "GET_SOURCE_OUTPUT_INFO",
86 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = "GET_SOURCE_OUTPUT_INFO_LIST",
87 [PA_COMMAND_SUBSCRIBE] = "SUBSCRIBE",
88
89 [PA_COMMAND_SET_SINK_VOLUME] = "SET_SINK_VOLUME",
90 [PA_COMMAND_SET_SINK_INPUT_VOLUME] = "SET_SINK_INPUT_VOLUME",
91 [PA_COMMAND_SET_SOURCE_VOLUME] = "SET_SOURCE_VOLUME",
92
93 [PA_COMMAND_SET_SINK_MUTE] = "SET_SINK_MUTE",
94 [PA_COMMAND_SET_SOURCE_MUTE] = "SET_SOURCE_MUTE",
95
96 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = "TRIGGER_PLAYBACK_STREAM",
97 [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = "FLUSH_PLAYBACK_STREAM",
98 [PA_COMMAND_CORK_PLAYBACK_STREAM] = "CORK_PLAYBACK_STREAM",
99
100 [PA_COMMAND_SET_DEFAULT_SINK] = "SET_DEFAULT_SINK",
101 [PA_COMMAND_SET_DEFAULT_SOURCE] = "SET_DEFAULT_SOURCE",
102
103 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = "SET_PLAYBACK_STREAM_NAME",
104 [PA_COMMAND_SET_RECORD_STREAM_NAME] = "SET_RECORD_STREAM_NAME",
105
106 [PA_COMMAND_KILL_CLIENT] = "KILL_CLIENT",
107 [PA_COMMAND_KILL_SINK_INPUT] = "KILL_SINK_INPUT",
108 [PA_COMMAND_KILL_SOURCE_OUTPUT] = "KILL_SOURCE_OUTPUT",
109
110 [PA_COMMAND_LOAD_MODULE] = "LOAD_MODULE",
111 [PA_COMMAND_UNLOAD_MODULE] = "UNLOAD_MODULE",
112
113 [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE] = "ADD_AUTOLOAD (obsolete)",
114 [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE] = "REMOVE_AUTOLOAD (obsolete)",
115 [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE] = "GET_AUTOLOAD_INFO (obsolete)",
116 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE] = "GET_AUTOLOAD_INFO_LIST (obsolete)",
117
118 [PA_COMMAND_GET_RECORD_LATENCY] = "GET_RECORD_LATENCY",
119 [PA_COMMAND_CORK_RECORD_STREAM] = "CORK_RECORD_STREAM",
120 [PA_COMMAND_FLUSH_RECORD_STREAM] = "FLUSH_RECORD_STREAM",
121 [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = "PREBUF_PLAYBACK_STREAM",
122
123 /* SERVER->CLIENT */
124 [PA_COMMAND_REQUEST] = "REQUEST",
125 [PA_COMMAND_OVERFLOW] = "OVERFLOW",
126 [PA_COMMAND_UNDERFLOW] = "UNDERFLOW",
127 [PA_COMMAND_PLAYBACK_STREAM_KILLED] = "PLAYBACK_STREAM_KILLED",
128 [PA_COMMAND_RECORD_STREAM_KILLED] = "RECORD_STREAM_KILLED",
129 [PA_COMMAND_SUBSCRIBE_EVENT] = "SUBSCRIBE_EVENT",
130
131 /* A few more client->server commands */
132
133 /* Supported since protocol v10 (0.9.5) */
134 [PA_COMMAND_MOVE_SINK_INPUT] = "MOVE_SINK_INPUT",
135 [PA_COMMAND_MOVE_SOURCE_OUTPUT] = "MOVE_SOURCE_OUTPUT",
136
137 /* Supported since protocol v11 (0.9.7) */
138 [PA_COMMAND_SET_SINK_INPUT_MUTE] = "SET_SINK_INPUT_MUTE",
139
140 [PA_COMMAND_SUSPEND_SINK] = "SUSPEND_SINK",
141 [PA_COMMAND_SUSPEND_SOURCE] = "SUSPEND_SOURCE",
142
143 /* Supported since protocol v12 (0.9.8) */
144 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR] = "SET_PLAYBACK_STREAM_BUFFER_ATTR",
145 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR] = "SET_RECORD_STREAM_BUFFER_ATTR",
146
147 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE] = "UPDATE_PLAYBACK_STREAM_SAMPLE_RATE",
148 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE] = "UPDATE_RECORD_STREAM_SAMPLE_RATE",
149
150 /* SERVER->CLIENT */
151 [PA_COMMAND_PLAYBACK_STREAM_SUSPENDED] = "PLAYBACK_STREAM_SUSPENDED",
152 [PA_COMMAND_RECORD_STREAM_SUSPENDED] = "RECORD_STREAM_SUSPENDED",
153 [PA_COMMAND_PLAYBACK_STREAM_MOVED] = "PLAYBACK_STREAM_MOVED",
154 [PA_COMMAND_RECORD_STREAM_MOVED] = "RECORD_STREAM_MOVED",
155
156 /* Supported since protocol v13 (0.9.11) */
157 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST] = "UPDATE_RECORD_STREAM_PROPLIST",
158 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST] = "UPDATE_PLAYBACK_STREAM_PROPLIST",
159 [PA_COMMAND_UPDATE_CLIENT_PROPLIST] = "UPDATE_CLIENT_PROPLIST",
160 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST] = "REMOVE_RECORD_STREAM_PROPLIST",
161 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST] = "REMOVE_PLAYBACK_STREAM_PROPLIST",
162 [PA_COMMAND_REMOVE_CLIENT_PROPLIST] = "REMOVE_CLIENT_PROPLIST",
163
164 /* SERVER->CLIENT */
165 [PA_COMMAND_STARTED] = "STARTED",
166
167 /* Supported since protocol v14 (0.9.12) */
168 [PA_COMMAND_EXTENSION] = "EXTENSION",
169
170 /* Supported since protocol v15 (0.9.15) */
171 [PA_COMMAND_GET_CARD_INFO] = "GET_CARD_INFO",
172 [PA_COMMAND_GET_CARD_INFO_LIST] = "GET_CARD_INFO_LIST",
173 [PA_COMMAND_SET_CARD_PROFILE] = "SET_CARD_PROFILE",
174
175 [PA_COMMAND_CLIENT_EVENT] = "CLIENT_EVENT",
176 [PA_COMMAND_PLAYBACK_STREAM_EVENT] = "PLAYBACK_STREAM_EVENT",
177 [PA_COMMAND_RECORD_STREAM_EVENT] = "RECORD_STREAM_EVENT",
178
179 /* SERVER->CLIENT */
180 [PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED] = "PLAYBACK_BUFFER_ATTR_CHANGED",
181 [PA_COMMAND_RECORD_BUFFER_ATTR_CHANGED] = "RECORD_BUFFER_ATTR_CHANGED",
182
183 /* Supported since protocol v16 (0.9.16) */
184 [PA_COMMAND_SET_SINK_PORT] = "SET_SINK_PORT",
185 [PA_COMMAND_SET_SOURCE_PORT] = "SET_SOURCE_PORT",
186
187 /* Supported since protocol v22 (1.0) */
188 [PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME] = "SET_SOURCE_OUTPUT_VOLUME",
189 [PA_COMMAND_SET_SOURCE_OUTPUT_MUTE] = "SET_SOURCE_OUTPUT_MUTE",
190
191 /* Supported since protocol v27 (3.0) */
192 [PA_COMMAND_SET_PORT_LATENCY_OFFSET] = "SET_PORT_LATENCY_OFFSET",
193
194 /* Supported since protocol v30 (6.0) */
195 /* BOTH DIRECTIONS */
196 [PA_COMMAND_ENABLE_SRBCHANNEL] = "ENABLE_SRBCHANNEL",
197 [PA_COMMAND_DISABLE_SRBCHANNEL] = "DISABLE_SRBCHANNEL",
198
199 /* Supported since protocol v31 (9.0) */
200 /* BOTH DIRECTIONS */
201 [PA_COMMAND_REGISTER_MEMFD_SHMID] = "REGISTER_MEMFD_SHMID",
202
203 /* Supported since protocol v35 (15.0) */
204 [PA_COMMAND_SEND_OBJECT_MESSAGE] = "SEND_OBJECT_MESSAGE",
205
206 [PA_COMMAND_UNDERFLOW_OHOS] = "UNDERFLOW_OHOS",
207 };
208
209 #endif
210
211 PA_STATIC_FLIST_DECLARE(reply_infos, 0, pa_xfree);
212
213 struct reply_info {
214 pa_pdispatch *pdispatch;
215 PA_LLIST_FIELDS(struct reply_info);
216 pa_pdispatch_cb_t callback;
217 void *userdata;
218 pa_free_cb_t free_cb;
219 uint32_t tag;
220 pa_time_event *time_event;
221 };
222
223 struct pa_pdispatch {
224 PA_REFCNT_DECLARE;
225 pa_mainloop_api *mainloop;
226 const pa_pdispatch_cb_t *callback_table;
227 unsigned n_commands;
228 PA_LLIST_HEAD(struct reply_info, replies);
229 pa_pdispatch_drain_cb_t drain_callback;
230 void *drain_userdata;
231 pa_cmsg_ancil_data *ancil_data;
232 bool use_rtclock;
233 };
234
reply_info_free(struct reply_info *r)235 static void reply_info_free(struct reply_info *r) {
236 pa_assert(r);
237 pa_assert(r->pdispatch);
238 pa_assert(r->pdispatch->mainloop);
239
240 if (r->time_event)
241 r->pdispatch->mainloop->time_free(r->time_event);
242
243 PA_LLIST_REMOVE(struct reply_info, r->pdispatch->replies, r);
244
245 if (pa_flist_push(PA_STATIC_FLIST_GET(reply_infos), r) < 0)
246 pa_xfree(r);
247 }
248
pa_pdispatch_new(pa_mainloop_api *mainloop, bool use_rtclock, const pa_pdispatch_cb_t *table, unsigned entries)249 pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, bool use_rtclock, const pa_pdispatch_cb_t *table, unsigned entries) {
250 pa_pdispatch *pd;
251
252 pa_assert(mainloop);
253 pa_assert((entries && table) || (!entries && !table));
254
255 pd = pa_xnew0(pa_pdispatch, 1);
256 PA_REFCNT_INIT(pd);
257 pd->mainloop = mainloop;
258 pd->callback_table = table;
259 pd->n_commands = entries;
260 PA_LLIST_HEAD_INIT(struct reply_info, pd->replies);
261 pd->use_rtclock = use_rtclock;
262
263 return pd;
264 }
265
pdispatch_free(pa_pdispatch *pd)266 static void pdispatch_free(pa_pdispatch *pd) {
267 pa_assert(pd);
268
269 while (pd->replies) {
270 if (pd->replies->free_cb)
271 pd->replies->free_cb(pd->replies->userdata);
272
273 reply_info_free(pd->replies);
274 }
275
276 pa_xfree(pd);
277 }
278
run_action(pa_pdispatch *pd, struct reply_info *r, uint32_t command, pa_tagstruct *ts)279 static void run_action(pa_pdispatch *pd, struct reply_info *r, uint32_t command, pa_tagstruct *ts) {
280 pa_pdispatch_cb_t callback;
281 void *userdata;
282 uint32_t tag;
283 pa_assert(r);
284
285 pa_pdispatch_ref(pd);
286
287 callback = r->callback;
288 userdata = r->userdata;
289 tag = r->tag;
290
291 reply_info_free(r);
292
293 callback(pd, command, tag, ts, userdata);
294
295 if (pd->drain_callback && !pa_pdispatch_is_pending(pd))
296 pd->drain_callback(pd, pd->drain_userdata);
297
298 pa_pdispatch_unref(pd);
299 }
300
pa_pdispatch_run(pa_pdispatch *pd, pa_packet *packet, pa_cmsg_ancil_data *ancil_data, void *userdata)301 int pa_pdispatch_run(pa_pdispatch *pd, pa_packet *packet, pa_cmsg_ancil_data *ancil_data, void *userdata) {
302 uint32_t tag, command;
303 pa_tagstruct *ts = NULL;
304 int ret = -1;
305 const void *pdata;
306 size_t plen;
307
308 pa_assert(pd);
309 pa_assert(PA_REFCNT_VALUE(pd) >= 1);
310 pa_assert(packet);
311
312 pa_pdispatch_ref(pd);
313
314 pdata = pa_packet_data(packet, &plen);
315 if (plen <= 8)
316 goto finish;
317
318 ts = pa_tagstruct_new_fixed(pdata, plen);
319
320 if (pa_tagstruct_getu32(ts, &command) < 0 ||
321 pa_tagstruct_getu32(ts, &tag) < 0)
322 goto finish;
323
324 char const *p = NULL;
325 #ifdef DEBUG_OPCODES
326 {
327 char t[256];
328
329 if (command >= PA_COMMAND_MAX || !(p = command_names[command]))
330 pa_snprintf((char*) (p = t), sizeof(t), "%u", command);
331
332 // pa_log("[%p] Received opcode <%s>", pd, p);
333 }
334 #endif
335 char oht[256] = {0}; // PA CMD 256bytes max
336 pa_snprintf(oht, sizeof(oht), "PA_RECV_CMD[%u] <%s>", command, p);
337 CallStart(oht);
338
339 pd->ancil_data = ancil_data;
340
341 if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) {
342 struct reply_info *r;
343
344 PA_LLIST_FOREACH(r, pd->replies)
345 if (r->tag == tag)
346 break;
347
348 if (r)
349 run_action(pd, r, command, ts);
350
351 } else if (pd->callback_table && (command < pd->n_commands) && pd->callback_table[command]) {
352 const pa_pdispatch_cb_t *cb = pd->callback_table+command;
353
354 (*cb)(pd, command, tag, ts, userdata);
355 } else {
356 pa_log("Received unsupported command %u", command);
357 CallEnd();
358 goto finish;
359 }
360 CallEnd();
361
362 ret = 0;
363
364 finish:
365 pd->ancil_data = NULL;
366
367 if (ts)
368 pa_tagstruct_free(ts);
369
370 pa_pdispatch_unref(pd);
371
372 return ret;
373 }
374
timeout_callback(pa_mainloop_api*m, pa_time_event*e, const struct timeval *t, void *userdata)375 static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, const struct timeval *t, void *userdata) {
376 struct reply_info*r = userdata;
377
378 pa_assert(r);
379 pa_assert(r->time_event == e);
380 pa_assert(r->pdispatch);
381 pa_assert(r->pdispatch->mainloop == m);
382 pa_assert(r->callback);
383
384 run_action(r->pdispatch, r, PA_COMMAND_TIMEOUT, NULL);
385 }
386
pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t cb, void *userdata, pa_free_cb_t free_cb)387 void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t cb, void *userdata, pa_free_cb_t free_cb) {
388 struct reply_info *r;
389 struct timeval tv;
390
391 pa_assert(pd);
392 pa_assert(PA_REFCNT_VALUE(pd) >= 1);
393 pa_assert(cb);
394
395 if (!(r = pa_flist_pop(PA_STATIC_FLIST_GET(reply_infos))))
396 r = pa_xnew(struct reply_info, 1);
397
398 r->pdispatch = pd;
399 r->callback = cb;
400 r->userdata = userdata;
401 r->free_cb = free_cb;
402 r->tag = tag;
403
404 pa_assert_se(r->time_event = pd->mainloop->time_new(pd->mainloop,
405 pa_timeval_rtstore(&tv, pa_rtclock_now() + timeout * PA_USEC_PER_SEC, pd->use_rtclock),
406 timeout_callback, r));
407
408 PA_LLIST_PREPEND(struct reply_info, pd->replies, r);
409 }
410
pa_pdispatch_is_pending(pa_pdispatch *pd)411 int pa_pdispatch_is_pending(pa_pdispatch *pd) {
412 pa_assert(pd);
413 pa_assert(PA_REFCNT_VALUE(pd) >= 1);
414
415 return !!pd->replies;
416 }
417
pa_pdispatch_set_drain_callback(pa_pdispatch *pd, pa_pdispatch_drain_cb_t cb, void *userdata)418 void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, pa_pdispatch_drain_cb_t cb, void *userdata) {
419 pa_assert(pd);
420 pa_assert(PA_REFCNT_VALUE(pd) >= 1);
421 pa_assert(!cb || pa_pdispatch_is_pending(pd));
422
423 pd->drain_callback = cb;
424 pd->drain_userdata = userdata;
425 }
426
pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata)427 void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata) {
428 struct reply_info *r, *n;
429
430 pa_assert(pd);
431 pa_assert(PA_REFCNT_VALUE(pd) >= 1);
432
433 PA_LLIST_FOREACH_SAFE(r, n, pd->replies)
434 if (r->userdata == userdata)
435 reply_info_free(r);
436 }
437
pa_pdispatch_unref(pa_pdispatch *pd)438 void pa_pdispatch_unref(pa_pdispatch *pd) {
439 pa_assert(pd);
440 pa_assert(PA_REFCNT_VALUE(pd) >= 1);
441
442 if (PA_REFCNT_DEC(pd) <= 0)
443 pdispatch_free(pd);
444 }
445
pa_pdispatch_ref(pa_pdispatch *pd)446 pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd) {
447 pa_assert(pd);
448 pa_assert(PA_REFCNT_VALUE(pd) >= 1);
449
450 PA_REFCNT_INC(pd);
451 return pd;
452 }
453
454 #ifdef HAVE_CREDS
455
pa_pdispatch_creds(pa_pdispatch *pd)456 const pa_creds * pa_pdispatch_creds(pa_pdispatch *pd) {
457 pa_assert(pd);
458 pa_assert(PA_REFCNT_VALUE(pd) >= 1);
459
460 if (pd->ancil_data && pd->ancil_data->creds_valid)
461 return &pd->ancil_data->creds;
462 return NULL;
463 }
464
465 /* Should be called only once during the dispatcher lifetime
466 *
467 * If the returned ancillary data contains any fds, caller maintains sole
468 * responsibility of closing them down using pa_cmsg_ancil_data_close_fds() */
pa_pdispatch_take_ancil_data(pa_pdispatch *pd)469 pa_cmsg_ancil_data *pa_pdispatch_take_ancil_data(pa_pdispatch *pd) {
470 pa_cmsg_ancil_data *ancil;
471
472 pa_assert(pd);
473 pa_assert(PA_REFCNT_VALUE(pd) >= 1);
474
475 ancil = pd->ancil_data;
476
477 /* iochannel guarantees us that nfd will always be capped */
478 if (ancil)
479 pa_assert(ancil->nfd <= MAX_ANCIL_DATA_FDS);
480
481 pd->ancil_data = NULL;
482 return ancil;
483 }
484
485 #endif
486