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 47static 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 211PA_STATIC_FLIST_DECLARE(reply_infos, 0, pa_xfree); 212 213struct 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 223struct 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 235static 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 249pa_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 266static 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 279static 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 301int 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 364finish: 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 375static 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 387void 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 411int 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 418void 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 427void 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 438void 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 446pa_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 456const 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() */ 469pa_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