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