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