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