• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         pa_usec_t startTime = pa_rtclock_now();
355         (*cb)(pd, command, tag, ts, userdata);
356         pa_usec_t executionTime = pa_rtclock_now() - startTime;
357         if (executionTime > OH_DAEMON_TIMEOUT_THRESHOLD_ON_US) {  // too long block of daemon thread, dangerous
358             AUDIO_WARNING_LOG("Execution time of this command is too long: CMD[%{public}s] (%{public}" PRIu64 "ms)",
359                 p, executionTime / PA_USEC_PER_MSEC);
360         }
361     } else {
362         pa_log("Received unsupported command %u", command);
363         CallEnd();
364         goto finish;
365     }
366     CallEnd();
367 
368     ret = 0;
369 
370 finish:
371     pd->ancil_data = NULL;
372 
373     if (ts)
374         pa_tagstruct_free(ts);
375 
376     pa_pdispatch_unref(pd);
377 
378     return ret;
379 }
380 
timeout_callback(pa_mainloop_api * m,pa_time_event * e,const struct timeval * t,void * userdata)381 static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, const struct timeval *t, void *userdata) {
382     struct reply_info*r = userdata;
383 
384     pa_assert(r);
385     pa_assert(r->time_event == e);
386     pa_assert(r->pdispatch);
387     pa_assert(r->pdispatch->mainloop == m);
388     pa_assert(r->callback);
389 
390     run_action(r->pdispatch, r, PA_COMMAND_TIMEOUT, NULL);
391 }
392 
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)393 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) {
394     struct reply_info *r;
395     struct timeval tv;
396 
397     pa_assert(pd);
398     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
399     pa_assert(cb);
400 
401     if (!(r = pa_flist_pop(PA_STATIC_FLIST_GET(reply_infos))))
402         r = pa_xnew(struct reply_info, 1);
403 
404     r->pdispatch = pd;
405     r->callback = cb;
406     r->userdata = userdata;
407     r->free_cb = free_cb;
408     r->tag = tag;
409 
410     pa_assert_se(r->time_event = pd->mainloop->time_new(pd->mainloop,
411                                                         pa_timeval_rtstore(&tv, pa_rtclock_now() + timeout * PA_USEC_PER_SEC, pd->use_rtclock),
412                                                         timeout_callback, r));
413 
414     PA_LLIST_PREPEND(struct reply_info, pd->replies, r);
415 }
416 
pa_pdispatch_is_pending(pa_pdispatch * pd)417 int pa_pdispatch_is_pending(pa_pdispatch *pd) {
418     pa_assert(pd);
419     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
420 
421     return !!pd->replies;
422 }
423 
pa_pdispatch_set_drain_callback(pa_pdispatch * pd,pa_pdispatch_drain_cb_t cb,void * userdata)424 void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, pa_pdispatch_drain_cb_t cb, void *userdata) {
425     pa_assert(pd);
426     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
427     pa_assert(!cb || pa_pdispatch_is_pending(pd));
428 
429     pd->drain_callback = cb;
430     pd->drain_userdata = userdata;
431 }
432 
pa_pdispatch_unregister_reply(pa_pdispatch * pd,void * userdata)433 void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata) {
434     struct reply_info *r, *n;
435 
436     pa_assert(pd);
437     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
438 
439     PA_LLIST_FOREACH_SAFE(r, n, pd->replies)
440         if (r->userdata == userdata)
441             reply_info_free(r);
442 }
443 
pa_pdispatch_unref(pa_pdispatch * pd)444 void pa_pdispatch_unref(pa_pdispatch *pd) {
445     pa_assert(pd);
446     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
447 
448     if (PA_REFCNT_DEC(pd) <= 0)
449         pdispatch_free(pd);
450 }
451 
pa_pdispatch_ref(pa_pdispatch * pd)452 pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd) {
453     pa_assert(pd);
454     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
455 
456     PA_REFCNT_INC(pd);
457     return pd;
458 }
459 
460 #ifdef HAVE_CREDS
461 
pa_pdispatch_creds(pa_pdispatch * pd)462 const pa_creds * pa_pdispatch_creds(pa_pdispatch *pd) {
463     pa_assert(pd);
464     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
465 
466     if (pd->ancil_data && pd->ancil_data->creds_valid)
467          return &pd->ancil_data->creds;
468     return NULL;
469 }
470 
471 /* Should be called only once during the dispatcher lifetime
472  *
473  * If the returned ancillary data contains any fds, caller maintains sole
474  * responsibility of closing them down using pa_cmsg_ancil_data_close_fds() */
pa_pdispatch_take_ancil_data(pa_pdispatch * pd)475 pa_cmsg_ancil_data *pa_pdispatch_take_ancil_data(pa_pdispatch *pd) {
476     pa_cmsg_ancil_data *ancil;
477 
478     pa_assert(pd);
479     pa_assert(PA_REFCNT_VALUE(pd) >= 1);
480 
481     ancil = pd->ancil_data;
482 
483     /* iochannel guarantees us that nfd will always be capped */
484     if (ancil)
485         pa_assert(ancil->nfd <= MAX_ANCIL_DATA_FDS);
486 
487     pd->ancil_data = NULL;
488     return ancil;
489 }
490 
491 #endif
492