153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2004-2006 Lennart Poettering 553a5a1b3Sopenharmony_ci Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB 653a5a1b3Sopenharmony_ci 753a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 853a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as 953a5a1b3Sopenharmony_ci published by the Free Software Foundation; either version 2.1 of the 1053a5a1b3Sopenharmony_ci License, or (at your option) any later version. 1153a5a1b3Sopenharmony_ci 1253a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1353a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1453a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1553a5a1b3Sopenharmony_ci Lesser General Public License for more details. 1653a5a1b3Sopenharmony_ci 1753a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public 1853a5a1b3Sopenharmony_ci License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1953a5a1b3Sopenharmony_ci***/ 2053a5a1b3Sopenharmony_ci 2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2253a5a1b3Sopenharmony_ci#include <config.h> 2353a5a1b3Sopenharmony_ci#endif 2453a5a1b3Sopenharmony_ci 2553a5a1b3Sopenharmony_ci#include <stdio.h> 2653a5a1b3Sopenharmony_ci#include <stdlib.h> 2753a5a1b3Sopenharmony_ci#include <unistd.h> 2853a5a1b3Sopenharmony_ci 2953a5a1b3Sopenharmony_ci#ifdef HAVE_NETINET_IN_H 3053a5a1b3Sopenharmony_ci#include <netinet/in.h> 3153a5a1b3Sopenharmony_ci#endif 3253a5a1b3Sopenharmony_ci 3353a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 3453a5a1b3Sopenharmony_ci 3553a5a1b3Sopenharmony_ci#include <pulsecore/idxset.h> 3653a5a1b3Sopenharmony_ci#include <pulsecore/socket.h> 3753a5a1b3Sopenharmony_ci#include <pulsecore/queue.h> 3853a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 3953a5a1b3Sopenharmony_ci#include <pulsecore/creds.h> 4053a5a1b3Sopenharmony_ci#include <pulsecore/refcnt.h> 4153a5a1b3Sopenharmony_ci#include <pulsecore/flist.h> 4253a5a1b3Sopenharmony_ci#include <pulsecore/macro.h> 4353a5a1b3Sopenharmony_ci 4453a5a1b3Sopenharmony_ci#include "pstream.h" 4553a5a1b3Sopenharmony_ci 4653a5a1b3Sopenharmony_ci/* We piggyback information if audio data blocks are stored in SHM on the seek mode */ 4753a5a1b3Sopenharmony_ci#define PA_FLAG_SHMDATA 0x80000000LU 4853a5a1b3Sopenharmony_ci#define PA_FLAG_SHMDATA_MEMFD_BLOCK 0x20000000LU 4953a5a1b3Sopenharmony_ci#define PA_FLAG_SHMRELEASE 0x40000000LU 5053a5a1b3Sopenharmony_ci#define PA_FLAG_SHMREVOKE 0xC0000000LU 5153a5a1b3Sopenharmony_ci#define PA_FLAG_SHMMASK 0xFF000000LU 5253a5a1b3Sopenharmony_ci#define PA_FLAG_SEEKMASK 0x000000FFLU 5353a5a1b3Sopenharmony_ci#define PA_FLAG_SHMWRITABLE 0x00800000LU 5453a5a1b3Sopenharmony_ci 5553a5a1b3Sopenharmony_ci/* The sequence descriptor header consists of 5 32bit integers: */ 5653a5a1b3Sopenharmony_cienum { 5753a5a1b3Sopenharmony_ci PA_PSTREAM_DESCRIPTOR_LENGTH, 5853a5a1b3Sopenharmony_ci PA_PSTREAM_DESCRIPTOR_CHANNEL, 5953a5a1b3Sopenharmony_ci PA_PSTREAM_DESCRIPTOR_OFFSET_HI, 6053a5a1b3Sopenharmony_ci PA_PSTREAM_DESCRIPTOR_OFFSET_LO, 6153a5a1b3Sopenharmony_ci PA_PSTREAM_DESCRIPTOR_FLAGS, 6253a5a1b3Sopenharmony_ci PA_PSTREAM_DESCRIPTOR_MAX 6353a5a1b3Sopenharmony_ci}; 6453a5a1b3Sopenharmony_ci 6553a5a1b3Sopenharmony_ci/* If we have an SHM block, this info follows the descriptor */ 6653a5a1b3Sopenharmony_cienum { 6753a5a1b3Sopenharmony_ci PA_PSTREAM_SHM_BLOCKID, 6853a5a1b3Sopenharmony_ci PA_PSTREAM_SHM_SHMID, 6953a5a1b3Sopenharmony_ci PA_PSTREAM_SHM_INDEX, 7053a5a1b3Sopenharmony_ci PA_PSTREAM_SHM_LENGTH, 7153a5a1b3Sopenharmony_ci PA_PSTREAM_SHM_MAX 7253a5a1b3Sopenharmony_ci}; 7353a5a1b3Sopenharmony_ci 7453a5a1b3Sopenharmony_citypedef uint32_t pa_pstream_descriptor[PA_PSTREAM_DESCRIPTOR_MAX]; 7553a5a1b3Sopenharmony_ci 7653a5a1b3Sopenharmony_ci#define PA_PSTREAM_DESCRIPTOR_SIZE (PA_PSTREAM_DESCRIPTOR_MAX*sizeof(uint32_t)) 7753a5a1b3Sopenharmony_ci 7853a5a1b3Sopenharmony_ci#define MINIBUF_SIZE (256) 7953a5a1b3Sopenharmony_ci 8053a5a1b3Sopenharmony_ci/* To allow uploading a single sample in one frame, this value should be the 8153a5a1b3Sopenharmony_ci * same size (16 MB) as PA_SCACHE_ENTRY_SIZE_MAX from pulsecore/core-scache.h. 8253a5a1b3Sopenharmony_ci */ 8353a5a1b3Sopenharmony_ci#define FRAME_SIZE_MAX_ALLOW (1024*1024*16) 8453a5a1b3Sopenharmony_ci 8553a5a1b3Sopenharmony_ciPA_STATIC_FLIST_DECLARE(items, 0, pa_xfree); 8653a5a1b3Sopenharmony_ci 8753a5a1b3Sopenharmony_cistruct item_info { 8853a5a1b3Sopenharmony_ci enum { 8953a5a1b3Sopenharmony_ci PA_PSTREAM_ITEM_PACKET, 9053a5a1b3Sopenharmony_ci PA_PSTREAM_ITEM_MEMBLOCK, 9153a5a1b3Sopenharmony_ci PA_PSTREAM_ITEM_SHMRELEASE, 9253a5a1b3Sopenharmony_ci PA_PSTREAM_ITEM_SHMREVOKE 9353a5a1b3Sopenharmony_ci } type; 9453a5a1b3Sopenharmony_ci 9553a5a1b3Sopenharmony_ci /* packet info */ 9653a5a1b3Sopenharmony_ci pa_packet *packet; 9753a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 9853a5a1b3Sopenharmony_ci bool with_ancil_data; 9953a5a1b3Sopenharmony_ci pa_cmsg_ancil_data ancil_data; 10053a5a1b3Sopenharmony_ci#endif 10153a5a1b3Sopenharmony_ci 10253a5a1b3Sopenharmony_ci /* memblock info */ 10353a5a1b3Sopenharmony_ci pa_memchunk chunk; 10453a5a1b3Sopenharmony_ci uint32_t channel; 10553a5a1b3Sopenharmony_ci int64_t offset; 10653a5a1b3Sopenharmony_ci pa_seek_mode_t seek_mode; 10753a5a1b3Sopenharmony_ci 10853a5a1b3Sopenharmony_ci /* release/revoke info */ 10953a5a1b3Sopenharmony_ci uint32_t block_id; 11053a5a1b3Sopenharmony_ci}; 11153a5a1b3Sopenharmony_ci 11253a5a1b3Sopenharmony_cistruct pstream_read { 11353a5a1b3Sopenharmony_ci pa_pstream_descriptor descriptor; 11453a5a1b3Sopenharmony_ci pa_memblock *memblock; 11553a5a1b3Sopenharmony_ci pa_packet *packet; 11653a5a1b3Sopenharmony_ci uint32_t shm_info[PA_PSTREAM_SHM_MAX]; 11753a5a1b3Sopenharmony_ci void *data; 11853a5a1b3Sopenharmony_ci size_t index; 11953a5a1b3Sopenharmony_ci}; 12053a5a1b3Sopenharmony_ci 12153a5a1b3Sopenharmony_cistruct pa_pstream { 12253a5a1b3Sopenharmony_ci PA_REFCNT_DECLARE; 12353a5a1b3Sopenharmony_ci 12453a5a1b3Sopenharmony_ci pa_mainloop_api *mainloop; 12553a5a1b3Sopenharmony_ci pa_defer_event *defer_event; 12653a5a1b3Sopenharmony_ci pa_iochannel *io; 12753a5a1b3Sopenharmony_ci pa_srbchannel *srb, *srbpending; 12853a5a1b3Sopenharmony_ci bool is_srbpending; 12953a5a1b3Sopenharmony_ci 13053a5a1b3Sopenharmony_ci pa_queue *send_queue; 13153a5a1b3Sopenharmony_ci 13253a5a1b3Sopenharmony_ci bool dead; 13353a5a1b3Sopenharmony_ci 13453a5a1b3Sopenharmony_ci struct { 13553a5a1b3Sopenharmony_ci union { 13653a5a1b3Sopenharmony_ci uint8_t minibuf[MINIBUF_SIZE]; 13753a5a1b3Sopenharmony_ci pa_pstream_descriptor descriptor; 13853a5a1b3Sopenharmony_ci }; 13953a5a1b3Sopenharmony_ci struct item_info* current; 14053a5a1b3Sopenharmony_ci void *data; 14153a5a1b3Sopenharmony_ci size_t index; 14253a5a1b3Sopenharmony_ci int minibuf_validsize; 14353a5a1b3Sopenharmony_ci pa_memchunk memchunk; 14453a5a1b3Sopenharmony_ci } write; 14553a5a1b3Sopenharmony_ci 14653a5a1b3Sopenharmony_ci struct pstream_read readio, readsrb; 14753a5a1b3Sopenharmony_ci 14853a5a1b3Sopenharmony_ci /* @use_shm: beside copying the full audio data to the other 14953a5a1b3Sopenharmony_ci * PA end, this pipe supports just sending references of the 15053a5a1b3Sopenharmony_ci * same audio data blocks if they reside in a SHM pool. 15153a5a1b3Sopenharmony_ci * 15253a5a1b3Sopenharmony_ci * @use_memfd: pipe supports sending SHM memfd block references 15353a5a1b3Sopenharmony_ci * 15453a5a1b3Sopenharmony_ci * @registered_memfd_ids: registered memfd pools SHM IDs. Check 15553a5a1b3Sopenharmony_ci * pa_pstream_register_memfd_mempool() for more information. */ 15653a5a1b3Sopenharmony_ci bool use_shm, use_memfd; 15753a5a1b3Sopenharmony_ci bool non_registered_memfd_id_error_logged; 15853a5a1b3Sopenharmony_ci pa_idxset *registered_memfd_ids; 15953a5a1b3Sopenharmony_ci 16053a5a1b3Sopenharmony_ci pa_memimport *import; 16153a5a1b3Sopenharmony_ci pa_memexport *export; 16253a5a1b3Sopenharmony_ci 16353a5a1b3Sopenharmony_ci pa_pstream_packet_cb_t receive_packet_callback; 16453a5a1b3Sopenharmony_ci void *receive_packet_callback_userdata; 16553a5a1b3Sopenharmony_ci 16653a5a1b3Sopenharmony_ci pa_pstream_memblock_cb_t receive_memblock_callback; 16753a5a1b3Sopenharmony_ci void *receive_memblock_callback_userdata; 16853a5a1b3Sopenharmony_ci 16953a5a1b3Sopenharmony_ci pa_pstream_notify_cb_t drain_callback; 17053a5a1b3Sopenharmony_ci void *drain_callback_userdata; 17153a5a1b3Sopenharmony_ci 17253a5a1b3Sopenharmony_ci pa_pstream_notify_cb_t die_callback; 17353a5a1b3Sopenharmony_ci void *die_callback_userdata; 17453a5a1b3Sopenharmony_ci 17553a5a1b3Sopenharmony_ci pa_pstream_block_id_cb_t revoke_callback; 17653a5a1b3Sopenharmony_ci void *revoke_callback_userdata; 17753a5a1b3Sopenharmony_ci 17853a5a1b3Sopenharmony_ci pa_pstream_block_id_cb_t release_callback; 17953a5a1b3Sopenharmony_ci void *release_callback_userdata; 18053a5a1b3Sopenharmony_ci 18153a5a1b3Sopenharmony_ci pa_mempool *mempool; 18253a5a1b3Sopenharmony_ci 18353a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 18453a5a1b3Sopenharmony_ci pa_cmsg_ancil_data read_ancil_data, *write_ancil_data; 18553a5a1b3Sopenharmony_ci bool send_ancil_data_now; 18653a5a1b3Sopenharmony_ci#endif 18753a5a1b3Sopenharmony_ci}; 18853a5a1b3Sopenharmony_ci 18953a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 19053a5a1b3Sopenharmony_ci/* 19153a5a1b3Sopenharmony_ci * memfd-backed SHM pools blocks transfer occur without passing the pool's 19253a5a1b3Sopenharmony_ci * fd every time, thus minimizing overhead and avoiding fd leaks. A 19353a5a1b3Sopenharmony_ci * REGISTER_MEMFD_SHMID command is sent, with the pool's memfd fd, very early 19453a5a1b3Sopenharmony_ci * on. This command has an ID that uniquely identifies the pool in question. 19553a5a1b3Sopenharmony_ci * Further pool's block references can then be exclusively done using such ID; 19653a5a1b3Sopenharmony_ci * the fd can be safely closed – on both ends – afterwards. 19753a5a1b3Sopenharmony_ci * 19853a5a1b3Sopenharmony_ci * On the sending side of this command, we want to close the passed fds 19953a5a1b3Sopenharmony_ci * directly after being sent. Meanwhile we're only allowed to asynchronously 20053a5a1b3Sopenharmony_ci * schedule packet writes to the pstream, so the job of closing passed fds is 20153a5a1b3Sopenharmony_ci * left to the pstream's actual writing function do_write(): it knows the 20253a5a1b3Sopenharmony_ci * exact point in time where the fds are passed to the other end through 20353a5a1b3Sopenharmony_ci * iochannels and the sendmsg() system call. 20453a5a1b3Sopenharmony_ci * 20553a5a1b3Sopenharmony_ci * Nonetheless not all code paths in the system desire their socket-passed 20653a5a1b3Sopenharmony_ci * fds to be closed after the send. srbchannel needs the passed fds to still 20753a5a1b3Sopenharmony_ci * be open for further communication. System-wide global memfd-backed pools 20853a5a1b3Sopenharmony_ci * also require the passed fd to be open: they pass the same fd, with the same 20953a5a1b3Sopenharmony_ci * ID registration mechanism, for each newly connected client to the system. 21053a5a1b3Sopenharmony_ci * 21153a5a1b3Sopenharmony_ci * So from all of the above, never close the ancillary fds by your own and 21253a5a1b3Sopenharmony_ci * always call below method instead. It takes care of closing the passed fds 21353a5a1b3Sopenharmony_ci * _only if allowed_ by the code paths that originally created them to do so. 21453a5a1b3Sopenharmony_ci * Moreover, it is multiple-invocations safe: failure handlers can, and 21553a5a1b3Sopenharmony_ci * should, call it for passed fds cleanup without worrying too much about 21653a5a1b3Sopenharmony_ci * the system state. 21753a5a1b3Sopenharmony_ci */ 21853a5a1b3Sopenharmony_civoid pa_cmsg_ancil_data_close_fds(struct pa_cmsg_ancil_data *ancil) { 21953a5a1b3Sopenharmony_ci if (ancil && ancil->nfd > 0 && ancil->close_fds_on_cleanup) { 22053a5a1b3Sopenharmony_ci int i; 22153a5a1b3Sopenharmony_ci 22253a5a1b3Sopenharmony_ci pa_assert(ancil->nfd <= MAX_ANCIL_DATA_FDS); 22353a5a1b3Sopenharmony_ci 22453a5a1b3Sopenharmony_ci for (i = 0; i < ancil->nfd; i++) 22553a5a1b3Sopenharmony_ci if (ancil->fds[i] != -1) { 22653a5a1b3Sopenharmony_ci pa_assert_se(pa_close(ancil->fds[i]) == 0); 22753a5a1b3Sopenharmony_ci ancil->fds[i] = -1; 22853a5a1b3Sopenharmony_ci } 22953a5a1b3Sopenharmony_ci 23053a5a1b3Sopenharmony_ci ancil->nfd = 0; 23153a5a1b3Sopenharmony_ci ancil->close_fds_on_cleanup = false; 23253a5a1b3Sopenharmony_ci } 23353a5a1b3Sopenharmony_ci} 23453a5a1b3Sopenharmony_ci#endif 23553a5a1b3Sopenharmony_ci 23653a5a1b3Sopenharmony_cistatic int do_write(pa_pstream *p); 23753a5a1b3Sopenharmony_cistatic int do_read(pa_pstream *p, struct pstream_read *re); 23853a5a1b3Sopenharmony_ci 23953a5a1b3Sopenharmony_cistatic void do_pstream_read_write(pa_pstream *p) { 24053a5a1b3Sopenharmony_ci pa_assert(p); 24153a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 24253a5a1b3Sopenharmony_ci 24353a5a1b3Sopenharmony_ci pa_pstream_ref(p); 24453a5a1b3Sopenharmony_ci 24553a5a1b3Sopenharmony_ci p->mainloop->defer_enable(p->defer_event, 0); 24653a5a1b3Sopenharmony_ci 24753a5a1b3Sopenharmony_ci if (!p->dead && p->srb) { 24853a5a1b3Sopenharmony_ci int r = 0; 24953a5a1b3Sopenharmony_ci 25053a5a1b3Sopenharmony_ci if(do_write(p) < 0) 25153a5a1b3Sopenharmony_ci goto fail; 25253a5a1b3Sopenharmony_ci 25353a5a1b3Sopenharmony_ci while (!p->dead && r == 0) { 25453a5a1b3Sopenharmony_ci r = do_read(p, &p->readsrb); 25553a5a1b3Sopenharmony_ci if (r < 0) 25653a5a1b3Sopenharmony_ci goto fail; 25753a5a1b3Sopenharmony_ci } 25853a5a1b3Sopenharmony_ci } 25953a5a1b3Sopenharmony_ci 26053a5a1b3Sopenharmony_ci if (!p->dead && pa_iochannel_is_readable(p->io)) { 26153a5a1b3Sopenharmony_ci if (do_read(p, &p->readio) < 0) 26253a5a1b3Sopenharmony_ci goto fail; 26353a5a1b3Sopenharmony_ci } else if (!p->dead && pa_iochannel_is_hungup(p->io)) 26453a5a1b3Sopenharmony_ci goto fail; 26553a5a1b3Sopenharmony_ci 26653a5a1b3Sopenharmony_ci while (!p->dead && pa_iochannel_is_writable(p->io)) { 26753a5a1b3Sopenharmony_ci int r = do_write(p); 26853a5a1b3Sopenharmony_ci if (r < 0) 26953a5a1b3Sopenharmony_ci goto fail; 27053a5a1b3Sopenharmony_ci if (r == 0) 27153a5a1b3Sopenharmony_ci break; 27253a5a1b3Sopenharmony_ci } 27353a5a1b3Sopenharmony_ci 27453a5a1b3Sopenharmony_ci pa_pstream_unref(p); 27553a5a1b3Sopenharmony_ci return; 27653a5a1b3Sopenharmony_ci 27753a5a1b3Sopenharmony_cifail: 27853a5a1b3Sopenharmony_ci 27953a5a1b3Sopenharmony_ci if (p->die_callback) 28053a5a1b3Sopenharmony_ci p->die_callback(p, p->die_callback_userdata); 28153a5a1b3Sopenharmony_ci 28253a5a1b3Sopenharmony_ci pa_pstream_unlink(p); 28353a5a1b3Sopenharmony_ci pa_pstream_unref(p); 28453a5a1b3Sopenharmony_ci} 28553a5a1b3Sopenharmony_ci 28653a5a1b3Sopenharmony_cistatic bool srb_callback(pa_srbchannel *srb, void *userdata) { 28753a5a1b3Sopenharmony_ci bool b; 28853a5a1b3Sopenharmony_ci pa_pstream *p = userdata; 28953a5a1b3Sopenharmony_ci 29053a5a1b3Sopenharmony_ci pa_assert(p); 29153a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 29253a5a1b3Sopenharmony_ci pa_assert(p->srb == srb); 29353a5a1b3Sopenharmony_ci 29453a5a1b3Sopenharmony_ci pa_pstream_ref(p); 29553a5a1b3Sopenharmony_ci 29653a5a1b3Sopenharmony_ci do_pstream_read_write(p); 29753a5a1b3Sopenharmony_ci 29853a5a1b3Sopenharmony_ci /* If either pstream or the srb is going away, return false. 29953a5a1b3Sopenharmony_ci We need to check this before p is destroyed. */ 30053a5a1b3Sopenharmony_ci b = (PA_REFCNT_VALUE(p) > 1) && (p->srb == srb); 30153a5a1b3Sopenharmony_ci pa_pstream_unref(p); 30253a5a1b3Sopenharmony_ci 30353a5a1b3Sopenharmony_ci return b; 30453a5a1b3Sopenharmony_ci} 30553a5a1b3Sopenharmony_ci 30653a5a1b3Sopenharmony_cistatic void io_callback(pa_iochannel*io, void *userdata) { 30753a5a1b3Sopenharmony_ci pa_pstream *p = userdata; 30853a5a1b3Sopenharmony_ci 30953a5a1b3Sopenharmony_ci pa_assert(p); 31053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 31153a5a1b3Sopenharmony_ci pa_assert(p->io == io); 31253a5a1b3Sopenharmony_ci 31353a5a1b3Sopenharmony_ci do_pstream_read_write(p); 31453a5a1b3Sopenharmony_ci} 31553a5a1b3Sopenharmony_ci 31653a5a1b3Sopenharmony_cistatic void defer_callback(pa_mainloop_api *m, pa_defer_event *e, void*userdata) { 31753a5a1b3Sopenharmony_ci pa_pstream *p = userdata; 31853a5a1b3Sopenharmony_ci 31953a5a1b3Sopenharmony_ci pa_assert(p); 32053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 32153a5a1b3Sopenharmony_ci pa_assert(p->defer_event == e); 32253a5a1b3Sopenharmony_ci pa_assert(p->mainloop == m); 32353a5a1b3Sopenharmony_ci 32453a5a1b3Sopenharmony_ci do_pstream_read_write(p); 32553a5a1b3Sopenharmony_ci} 32653a5a1b3Sopenharmony_ci 32753a5a1b3Sopenharmony_cistatic void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userdata); 32853a5a1b3Sopenharmony_ci 32953a5a1b3Sopenharmony_cipa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *pool) { 33053a5a1b3Sopenharmony_ci pa_pstream *p; 33153a5a1b3Sopenharmony_ci 33253a5a1b3Sopenharmony_ci pa_assert(m); 33353a5a1b3Sopenharmony_ci pa_assert(io); 33453a5a1b3Sopenharmony_ci pa_assert(pool); 33553a5a1b3Sopenharmony_ci 33653a5a1b3Sopenharmony_ci p = pa_xnew0(pa_pstream, 1); 33753a5a1b3Sopenharmony_ci PA_REFCNT_INIT(p); 33853a5a1b3Sopenharmony_ci p->io = io; 33953a5a1b3Sopenharmony_ci pa_iochannel_set_callback(io, io_callback, p); 34053a5a1b3Sopenharmony_ci 34153a5a1b3Sopenharmony_ci p->mainloop = m; 34253a5a1b3Sopenharmony_ci p->defer_event = m->defer_new(m, defer_callback, p); 34353a5a1b3Sopenharmony_ci m->defer_enable(p->defer_event, 0); 34453a5a1b3Sopenharmony_ci 34553a5a1b3Sopenharmony_ci p->send_queue = pa_queue_new(); 34653a5a1b3Sopenharmony_ci 34753a5a1b3Sopenharmony_ci p->mempool = pool; 34853a5a1b3Sopenharmony_ci 34953a5a1b3Sopenharmony_ci /* We do importing unconditionally */ 35053a5a1b3Sopenharmony_ci p->import = pa_memimport_new(p->mempool, memimport_release_cb, p); 35153a5a1b3Sopenharmony_ci 35253a5a1b3Sopenharmony_ci pa_iochannel_socket_set_rcvbuf(io, pa_mempool_block_size_max(p->mempool)); 35353a5a1b3Sopenharmony_ci pa_iochannel_socket_set_sndbuf(io, pa_mempool_block_size_max(p->mempool)); 35453a5a1b3Sopenharmony_ci 35553a5a1b3Sopenharmony_ci return p; 35653a5a1b3Sopenharmony_ci} 35753a5a1b3Sopenharmony_ci 35853a5a1b3Sopenharmony_ci/* Attach memfd<->SHM_ID mapping to given pstream and its memimport. 35953a5a1b3Sopenharmony_ci * Check pa_pstream_register_memfd_mempool() for further info. 36053a5a1b3Sopenharmony_ci * 36153a5a1b3Sopenharmony_ci * Caller owns the passed @memfd_fd and must close it down when appropriate. */ 36253a5a1b3Sopenharmony_ciint pa_pstream_attach_memfd_shmid(pa_pstream *p, unsigned shm_id, int memfd_fd) { 36353a5a1b3Sopenharmony_ci int err = -1; 36453a5a1b3Sopenharmony_ci 36553a5a1b3Sopenharmony_ci pa_assert(memfd_fd != -1); 36653a5a1b3Sopenharmony_ci 36753a5a1b3Sopenharmony_ci if (!p->use_memfd) { 36853a5a1b3Sopenharmony_ci pa_log_warn("Received memfd ID registration request over a pipe " 36953a5a1b3Sopenharmony_ci "that does not support memfds"); 37053a5a1b3Sopenharmony_ci return err; 37153a5a1b3Sopenharmony_ci } 37253a5a1b3Sopenharmony_ci 37353a5a1b3Sopenharmony_ci if (pa_idxset_get_by_data(p->registered_memfd_ids, PA_UINT32_TO_PTR(shm_id), NULL)) { 37453a5a1b3Sopenharmony_ci pa_log_warn("previously registered memfd SHM ID = %u", shm_id); 37553a5a1b3Sopenharmony_ci return err; 37653a5a1b3Sopenharmony_ci } 37753a5a1b3Sopenharmony_ci 37853a5a1b3Sopenharmony_ci if (pa_memimport_attach_memfd(p->import, shm_id, memfd_fd, true)) { 37953a5a1b3Sopenharmony_ci pa_log("Failed to create permanent mapping for memfd region with ID = %u", shm_id); 38053a5a1b3Sopenharmony_ci return err; 38153a5a1b3Sopenharmony_ci } 38253a5a1b3Sopenharmony_ci 38353a5a1b3Sopenharmony_ci pa_assert_se(pa_idxset_put(p->registered_memfd_ids, PA_UINT32_TO_PTR(shm_id), NULL) == 0); 38453a5a1b3Sopenharmony_ci return 0; 38553a5a1b3Sopenharmony_ci} 38653a5a1b3Sopenharmony_ci 38753a5a1b3Sopenharmony_cistatic void item_free(void *item) { 38853a5a1b3Sopenharmony_ci struct item_info *i = item; 38953a5a1b3Sopenharmony_ci pa_assert(i); 39053a5a1b3Sopenharmony_ci 39153a5a1b3Sopenharmony_ci if (i->type == PA_PSTREAM_ITEM_MEMBLOCK) { 39253a5a1b3Sopenharmony_ci pa_assert(i->chunk.memblock); 39353a5a1b3Sopenharmony_ci pa_memblock_unref(i->chunk.memblock); 39453a5a1b3Sopenharmony_ci } else if (i->type == PA_PSTREAM_ITEM_PACKET) { 39553a5a1b3Sopenharmony_ci pa_assert(i->packet); 39653a5a1b3Sopenharmony_ci pa_packet_unref(i->packet); 39753a5a1b3Sopenharmony_ci } 39853a5a1b3Sopenharmony_ci 39953a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 40053a5a1b3Sopenharmony_ci /* On error recovery paths, there might be lingering items 40153a5a1b3Sopenharmony_ci * on the pstream send queue and they are usually freed with 40253a5a1b3Sopenharmony_ci * a call to 'pa_queue_free(p->send_queue, item_free)'. Make 40353a5a1b3Sopenharmony_ci * sure we do not leak any fds in that case! */ 40453a5a1b3Sopenharmony_ci if (i->with_ancil_data) 40553a5a1b3Sopenharmony_ci pa_cmsg_ancil_data_close_fds(&i->ancil_data); 40653a5a1b3Sopenharmony_ci#endif 40753a5a1b3Sopenharmony_ci 40853a5a1b3Sopenharmony_ci if (pa_flist_push(PA_STATIC_FLIST_GET(items), i) < 0) 40953a5a1b3Sopenharmony_ci pa_xfree(i); 41053a5a1b3Sopenharmony_ci} 41153a5a1b3Sopenharmony_ci 41253a5a1b3Sopenharmony_cistatic void pstream_free(pa_pstream *p) { 41353a5a1b3Sopenharmony_ci pa_assert(p); 41453a5a1b3Sopenharmony_ci 41553a5a1b3Sopenharmony_ci pa_pstream_unlink(p); 41653a5a1b3Sopenharmony_ci 41753a5a1b3Sopenharmony_ci pa_queue_free(p->send_queue, item_free); 41853a5a1b3Sopenharmony_ci 41953a5a1b3Sopenharmony_ci if (p->write.current) 42053a5a1b3Sopenharmony_ci item_free(p->write.current); 42153a5a1b3Sopenharmony_ci 42253a5a1b3Sopenharmony_ci if (p->write.memchunk.memblock) 42353a5a1b3Sopenharmony_ci pa_memblock_unref(p->write.memchunk.memblock); 42453a5a1b3Sopenharmony_ci 42553a5a1b3Sopenharmony_ci if (p->readsrb.memblock) 42653a5a1b3Sopenharmony_ci pa_memblock_unref(p->readsrb.memblock); 42753a5a1b3Sopenharmony_ci 42853a5a1b3Sopenharmony_ci if (p->readsrb.packet) 42953a5a1b3Sopenharmony_ci pa_packet_unref(p->readsrb.packet); 43053a5a1b3Sopenharmony_ci 43153a5a1b3Sopenharmony_ci if (p->readio.memblock) 43253a5a1b3Sopenharmony_ci pa_memblock_unref(p->readio.memblock); 43353a5a1b3Sopenharmony_ci 43453a5a1b3Sopenharmony_ci if (p->readio.packet) 43553a5a1b3Sopenharmony_ci pa_packet_unref(p->readio.packet); 43653a5a1b3Sopenharmony_ci 43753a5a1b3Sopenharmony_ci if (p->registered_memfd_ids) 43853a5a1b3Sopenharmony_ci pa_idxset_free(p->registered_memfd_ids, NULL); 43953a5a1b3Sopenharmony_ci 44053a5a1b3Sopenharmony_ci pa_xfree(p); 44153a5a1b3Sopenharmony_ci} 44253a5a1b3Sopenharmony_ci 44353a5a1b3Sopenharmony_civoid pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, pa_cmsg_ancil_data *ancil_data) { 44453a5a1b3Sopenharmony_ci struct item_info *i; 44553a5a1b3Sopenharmony_ci 44653a5a1b3Sopenharmony_ci pa_assert(p); 44753a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 44853a5a1b3Sopenharmony_ci pa_assert(packet); 44953a5a1b3Sopenharmony_ci 45053a5a1b3Sopenharmony_ci if (p->dead) { 45153a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 45253a5a1b3Sopenharmony_ci pa_cmsg_ancil_data_close_fds(ancil_data); 45353a5a1b3Sopenharmony_ci#endif 45453a5a1b3Sopenharmony_ci return; 45553a5a1b3Sopenharmony_ci } 45653a5a1b3Sopenharmony_ci 45753a5a1b3Sopenharmony_ci if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(items)))) 45853a5a1b3Sopenharmony_ci i = pa_xnew(struct item_info, 1); 45953a5a1b3Sopenharmony_ci 46053a5a1b3Sopenharmony_ci i->type = PA_PSTREAM_ITEM_PACKET; 46153a5a1b3Sopenharmony_ci i->packet = pa_packet_ref(packet); 46253a5a1b3Sopenharmony_ci 46353a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 46453a5a1b3Sopenharmony_ci if ((i->with_ancil_data = !!ancil_data)) { 46553a5a1b3Sopenharmony_ci i->ancil_data = *ancil_data; 46653a5a1b3Sopenharmony_ci if (ancil_data->creds_valid) 46753a5a1b3Sopenharmony_ci pa_assert(ancil_data->nfd == 0); 46853a5a1b3Sopenharmony_ci else 46953a5a1b3Sopenharmony_ci pa_assert(ancil_data->nfd > 0); 47053a5a1b3Sopenharmony_ci } 47153a5a1b3Sopenharmony_ci#endif 47253a5a1b3Sopenharmony_ci 47353a5a1b3Sopenharmony_ci pa_queue_push(p->send_queue, i); 47453a5a1b3Sopenharmony_ci if (PaQueueGetLen(p->send_queue) >= 10) { // 10 maybe have msg backlog 47553a5a1b3Sopenharmony_ci pa_log_warn("[MSG backlog]: PaQueueLen = %u", PaQueueGetLen(p->send_queue)); 47653a5a1b3Sopenharmony_ci } 47753a5a1b3Sopenharmony_ci 47853a5a1b3Sopenharmony_ci p->mainloop->defer_enable(p->defer_event, 1); 47953a5a1b3Sopenharmony_ci} 48053a5a1b3Sopenharmony_ci 48153a5a1b3Sopenharmony_civoid pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek_mode, const pa_memchunk *chunk) { 48253a5a1b3Sopenharmony_ci size_t length, idx; 48353a5a1b3Sopenharmony_ci size_t bsm; 48453a5a1b3Sopenharmony_ci 48553a5a1b3Sopenharmony_ci pa_assert(p); 48653a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 48753a5a1b3Sopenharmony_ci pa_assert(channel != (uint32_t) -1); 48853a5a1b3Sopenharmony_ci pa_assert(chunk); 48953a5a1b3Sopenharmony_ci 49053a5a1b3Sopenharmony_ci if (p->dead) 49153a5a1b3Sopenharmony_ci return; 49253a5a1b3Sopenharmony_ci 49353a5a1b3Sopenharmony_ci idx = 0; 49453a5a1b3Sopenharmony_ci length = chunk->length; 49553a5a1b3Sopenharmony_ci 49653a5a1b3Sopenharmony_ci bsm = pa_mempool_block_size_max(p->mempool); 49753a5a1b3Sopenharmony_ci 49853a5a1b3Sopenharmony_ci while (length > 0) { 49953a5a1b3Sopenharmony_ci struct item_info *i; 50053a5a1b3Sopenharmony_ci size_t n; 50153a5a1b3Sopenharmony_ci 50253a5a1b3Sopenharmony_ci if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(items)))) 50353a5a1b3Sopenharmony_ci i = pa_xnew(struct item_info, 1); 50453a5a1b3Sopenharmony_ci i->type = PA_PSTREAM_ITEM_MEMBLOCK; 50553a5a1b3Sopenharmony_ci 50653a5a1b3Sopenharmony_ci n = PA_MIN(length, bsm); 50753a5a1b3Sopenharmony_ci i->chunk.index = chunk->index + idx; 50853a5a1b3Sopenharmony_ci i->chunk.length = n; 50953a5a1b3Sopenharmony_ci i->chunk.memblock = pa_memblock_ref(chunk->memblock); 51053a5a1b3Sopenharmony_ci 51153a5a1b3Sopenharmony_ci i->channel = channel; 51253a5a1b3Sopenharmony_ci i->offset = offset; 51353a5a1b3Sopenharmony_ci i->seek_mode = seek_mode; 51453a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 51553a5a1b3Sopenharmony_ci i->with_ancil_data = false; 51653a5a1b3Sopenharmony_ci#endif 51753a5a1b3Sopenharmony_ci 51853a5a1b3Sopenharmony_ci pa_queue_push(p->send_queue, i); 51953a5a1b3Sopenharmony_ci 52053a5a1b3Sopenharmony_ci idx += n; 52153a5a1b3Sopenharmony_ci length -= n; 52253a5a1b3Sopenharmony_ci } 52353a5a1b3Sopenharmony_ci 52453a5a1b3Sopenharmony_ci p->mainloop->defer_enable(p->defer_event, 1); 52553a5a1b3Sopenharmony_ci} 52653a5a1b3Sopenharmony_ci 52753a5a1b3Sopenharmony_civoid pa_pstream_send_release(pa_pstream *p, uint32_t block_id) { 52853a5a1b3Sopenharmony_ci struct item_info *item; 52953a5a1b3Sopenharmony_ci pa_assert(p); 53053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 53153a5a1b3Sopenharmony_ci 53253a5a1b3Sopenharmony_ci if (p->dead) 53353a5a1b3Sopenharmony_ci return; 53453a5a1b3Sopenharmony_ci 53553a5a1b3Sopenharmony_ci/* pa_log("Releasing block %u", block_id); */ 53653a5a1b3Sopenharmony_ci 53753a5a1b3Sopenharmony_ci if (!(item = pa_flist_pop(PA_STATIC_FLIST_GET(items)))) 53853a5a1b3Sopenharmony_ci item = pa_xnew(struct item_info, 1); 53953a5a1b3Sopenharmony_ci item->type = PA_PSTREAM_ITEM_SHMRELEASE; 54053a5a1b3Sopenharmony_ci item->block_id = block_id; 54153a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 54253a5a1b3Sopenharmony_ci item->with_ancil_data = false; 54353a5a1b3Sopenharmony_ci#endif 54453a5a1b3Sopenharmony_ci 54553a5a1b3Sopenharmony_ci pa_queue_push(p->send_queue, item); 54653a5a1b3Sopenharmony_ci p->mainloop->defer_enable(p->defer_event, 1); 54753a5a1b3Sopenharmony_ci} 54853a5a1b3Sopenharmony_ci 54953a5a1b3Sopenharmony_ci/* might be called from thread context */ 55053a5a1b3Sopenharmony_cistatic void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userdata) { 55153a5a1b3Sopenharmony_ci pa_pstream *p = userdata; 55253a5a1b3Sopenharmony_ci 55353a5a1b3Sopenharmony_ci pa_assert(p); 55453a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 55553a5a1b3Sopenharmony_ci 55653a5a1b3Sopenharmony_ci if (p->dead) 55753a5a1b3Sopenharmony_ci return; 55853a5a1b3Sopenharmony_ci 55953a5a1b3Sopenharmony_ci if (p->release_callback) 56053a5a1b3Sopenharmony_ci p->release_callback(p, block_id, p->release_callback_userdata); 56153a5a1b3Sopenharmony_ci else 56253a5a1b3Sopenharmony_ci pa_pstream_send_release(p, block_id); 56353a5a1b3Sopenharmony_ci} 56453a5a1b3Sopenharmony_ci 56553a5a1b3Sopenharmony_civoid pa_pstream_send_revoke(pa_pstream *p, uint32_t block_id) { 56653a5a1b3Sopenharmony_ci struct item_info *item; 56753a5a1b3Sopenharmony_ci pa_assert(p); 56853a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 56953a5a1b3Sopenharmony_ci 57053a5a1b3Sopenharmony_ci if (p->dead) 57153a5a1b3Sopenharmony_ci return; 57253a5a1b3Sopenharmony_ci/* pa_log("Revoking block %u", block_id); */ 57353a5a1b3Sopenharmony_ci 57453a5a1b3Sopenharmony_ci if (!(item = pa_flist_pop(PA_STATIC_FLIST_GET(items)))) 57553a5a1b3Sopenharmony_ci item = pa_xnew(struct item_info, 1); 57653a5a1b3Sopenharmony_ci item->type = PA_PSTREAM_ITEM_SHMREVOKE; 57753a5a1b3Sopenharmony_ci item->block_id = block_id; 57853a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 57953a5a1b3Sopenharmony_ci item->with_ancil_data = false; 58053a5a1b3Sopenharmony_ci#endif 58153a5a1b3Sopenharmony_ci 58253a5a1b3Sopenharmony_ci pa_queue_push(p->send_queue, item); 58353a5a1b3Sopenharmony_ci p->mainloop->defer_enable(p->defer_event, 1); 58453a5a1b3Sopenharmony_ci} 58553a5a1b3Sopenharmony_ci 58653a5a1b3Sopenharmony_ci/* might be called from thread context */ 58753a5a1b3Sopenharmony_cistatic void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userdata) { 58853a5a1b3Sopenharmony_ci pa_pstream *p = userdata; 58953a5a1b3Sopenharmony_ci 59053a5a1b3Sopenharmony_ci pa_assert(p); 59153a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 59253a5a1b3Sopenharmony_ci 59353a5a1b3Sopenharmony_ci if (p->revoke_callback) 59453a5a1b3Sopenharmony_ci p->revoke_callback(p, block_id, p->revoke_callback_userdata); 59553a5a1b3Sopenharmony_ci else 59653a5a1b3Sopenharmony_ci pa_pstream_send_revoke(p, block_id); 59753a5a1b3Sopenharmony_ci} 59853a5a1b3Sopenharmony_ci 59953a5a1b3Sopenharmony_cistatic void prepare_next_write_item(pa_pstream *p) { 60053a5a1b3Sopenharmony_ci pa_assert(p); 60153a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 60253a5a1b3Sopenharmony_ci 60353a5a1b3Sopenharmony_ci p->write.current = pa_queue_pop(p->send_queue); 60453a5a1b3Sopenharmony_ci 60553a5a1b3Sopenharmony_ci if (!p->write.current) 60653a5a1b3Sopenharmony_ci return; 60753a5a1b3Sopenharmony_ci p->write.index = 0; 60853a5a1b3Sopenharmony_ci p->write.data = NULL; 60953a5a1b3Sopenharmony_ci p->write.minibuf_validsize = 0; 61053a5a1b3Sopenharmony_ci pa_memchunk_reset(&p->write.memchunk); 61153a5a1b3Sopenharmony_ci 61253a5a1b3Sopenharmony_ci p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = 0; 61353a5a1b3Sopenharmony_ci p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl((uint32_t) -1); 61453a5a1b3Sopenharmony_ci p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = 0; 61553a5a1b3Sopenharmony_ci p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = 0; 61653a5a1b3Sopenharmony_ci p->write.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS] = 0; 61753a5a1b3Sopenharmony_ci 61853a5a1b3Sopenharmony_ci if (p->write.current->type == PA_PSTREAM_ITEM_PACKET) { 61953a5a1b3Sopenharmony_ci size_t plen; 62053a5a1b3Sopenharmony_ci 62153a5a1b3Sopenharmony_ci pa_assert(p->write.current->packet); 62253a5a1b3Sopenharmony_ci 62353a5a1b3Sopenharmony_ci p->write.data = (void *) pa_packet_data(p->write.current->packet, &plen); 62453a5a1b3Sopenharmony_ci p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl((uint32_t) plen); 62553a5a1b3Sopenharmony_ci 62653a5a1b3Sopenharmony_ci if (plen <= MINIBUF_SIZE - PA_PSTREAM_DESCRIPTOR_SIZE) { 62753a5a1b3Sopenharmony_ci memcpy(&p->write.minibuf[PA_PSTREAM_DESCRIPTOR_SIZE], p->write.data, plen); 62853a5a1b3Sopenharmony_ci p->write.minibuf_validsize = PA_PSTREAM_DESCRIPTOR_SIZE + plen; 62953a5a1b3Sopenharmony_ci } 63053a5a1b3Sopenharmony_ci 63153a5a1b3Sopenharmony_ci } else if (p->write.current->type == PA_PSTREAM_ITEM_SHMRELEASE) { 63253a5a1b3Sopenharmony_ci 63353a5a1b3Sopenharmony_ci p->write.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS] = htonl(PA_FLAG_SHMRELEASE); 63453a5a1b3Sopenharmony_ci p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = htonl(p->write.current->block_id); 63553a5a1b3Sopenharmony_ci 63653a5a1b3Sopenharmony_ci } else if (p->write.current->type == PA_PSTREAM_ITEM_SHMREVOKE) { 63753a5a1b3Sopenharmony_ci 63853a5a1b3Sopenharmony_ci p->write.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS] = htonl(PA_FLAG_SHMREVOKE); 63953a5a1b3Sopenharmony_ci p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = htonl(p->write.current->block_id); 64053a5a1b3Sopenharmony_ci 64153a5a1b3Sopenharmony_ci } else { 64253a5a1b3Sopenharmony_ci uint32_t flags; 64353a5a1b3Sopenharmony_ci bool send_payload = true; 64453a5a1b3Sopenharmony_ci 64553a5a1b3Sopenharmony_ci pa_assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK); 64653a5a1b3Sopenharmony_ci pa_assert(p->write.current->chunk.memblock); 64753a5a1b3Sopenharmony_ci 64853a5a1b3Sopenharmony_ci p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl(p->write.current->channel); 64953a5a1b3Sopenharmony_ci p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = htonl((uint32_t) (((uint64_t) p->write.current->offset) >> 32)); 65053a5a1b3Sopenharmony_ci p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = htonl((uint32_t) ((uint64_t) p->write.current->offset)); 65153a5a1b3Sopenharmony_ci 65253a5a1b3Sopenharmony_ci flags = (uint32_t) (p->write.current->seek_mode & PA_FLAG_SEEKMASK); 65353a5a1b3Sopenharmony_ci 65453a5a1b3Sopenharmony_ci if (p->use_shm) { 65553a5a1b3Sopenharmony_ci pa_mem_type_t type; 65653a5a1b3Sopenharmony_ci uint32_t block_id, shm_id; 65753a5a1b3Sopenharmony_ci size_t offset, length; 65853a5a1b3Sopenharmony_ci uint32_t *shm_info = (uint32_t *) &p->write.minibuf[PA_PSTREAM_DESCRIPTOR_SIZE]; 65953a5a1b3Sopenharmony_ci size_t shm_size = sizeof(uint32_t) * PA_PSTREAM_SHM_MAX; 66053a5a1b3Sopenharmony_ci pa_mempool *current_pool = pa_memblock_get_pool(p->write.current->chunk.memblock); 66153a5a1b3Sopenharmony_ci pa_memexport *current_export; 66253a5a1b3Sopenharmony_ci 66353a5a1b3Sopenharmony_ci if (p->mempool == current_pool) 66453a5a1b3Sopenharmony_ci pa_assert_se(current_export = p->export); 66553a5a1b3Sopenharmony_ci else 66653a5a1b3Sopenharmony_ci pa_assert_se(current_export = pa_memexport_new(current_pool, memexport_revoke_cb, p)); 66753a5a1b3Sopenharmony_ci 66853a5a1b3Sopenharmony_ci if (pa_memexport_put(current_export, 66953a5a1b3Sopenharmony_ci p->write.current->chunk.memblock, 67053a5a1b3Sopenharmony_ci &type, 67153a5a1b3Sopenharmony_ci &block_id, 67253a5a1b3Sopenharmony_ci &shm_id, 67353a5a1b3Sopenharmony_ci &offset, 67453a5a1b3Sopenharmony_ci &length) >= 0) { 67553a5a1b3Sopenharmony_ci 67653a5a1b3Sopenharmony_ci if (type == PA_MEM_TYPE_SHARED_POSIX) 67753a5a1b3Sopenharmony_ci send_payload = false; 67853a5a1b3Sopenharmony_ci 67953a5a1b3Sopenharmony_ci if (type == PA_MEM_TYPE_SHARED_MEMFD && p->use_memfd) { 68053a5a1b3Sopenharmony_ci if (pa_idxset_get_by_data(p->registered_memfd_ids, PA_UINT32_TO_PTR(shm_id), NULL)) { 68153a5a1b3Sopenharmony_ci flags |= PA_FLAG_SHMDATA_MEMFD_BLOCK; 68253a5a1b3Sopenharmony_ci send_payload = false; 68353a5a1b3Sopenharmony_ci } else { 68453a5a1b3Sopenharmony_ci if (!p->non_registered_memfd_id_error_logged) { 68553a5a1b3Sopenharmony_ci pa_log("Cannot send block reference with non-registered memfd ID = %u", shm_id); 68653a5a1b3Sopenharmony_ci pa_log("Falling back to copying full block data over socket"); 68753a5a1b3Sopenharmony_ci pa_log("There's a bug report about this: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/824"); 68853a5a1b3Sopenharmony_ci p->non_registered_memfd_id_error_logged = true; 68953a5a1b3Sopenharmony_ci } 69053a5a1b3Sopenharmony_ci } 69153a5a1b3Sopenharmony_ci } 69253a5a1b3Sopenharmony_ci 69353a5a1b3Sopenharmony_ci if (send_payload) { 69453a5a1b3Sopenharmony_ci pa_assert_se(pa_memexport_process_release(current_export, block_id) == 0); 69553a5a1b3Sopenharmony_ci } else { 69653a5a1b3Sopenharmony_ci flags |= PA_FLAG_SHMDATA; 69753a5a1b3Sopenharmony_ci if (pa_mempool_is_remote_writable(current_pool)) 69853a5a1b3Sopenharmony_ci flags |= PA_FLAG_SHMWRITABLE; 69953a5a1b3Sopenharmony_ci 70053a5a1b3Sopenharmony_ci shm_info[PA_PSTREAM_SHM_BLOCKID] = htonl(block_id); 70153a5a1b3Sopenharmony_ci shm_info[PA_PSTREAM_SHM_SHMID] = htonl(shm_id); 70253a5a1b3Sopenharmony_ci shm_info[PA_PSTREAM_SHM_INDEX] = htonl((uint32_t) (offset + p->write.current->chunk.index)); 70353a5a1b3Sopenharmony_ci shm_info[PA_PSTREAM_SHM_LENGTH] = htonl((uint32_t) p->write.current->chunk.length); 70453a5a1b3Sopenharmony_ci 70553a5a1b3Sopenharmony_ci p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(shm_size); 70653a5a1b3Sopenharmony_ci p->write.minibuf_validsize = PA_PSTREAM_DESCRIPTOR_SIZE + shm_size; 70753a5a1b3Sopenharmony_ci } 70853a5a1b3Sopenharmony_ci } 70953a5a1b3Sopenharmony_ci/* else */ 71053a5a1b3Sopenharmony_ci/* FIXME: Avoid memexport slot leaks. Call pa_memexport_process_release() */ 71153a5a1b3Sopenharmony_ci/* pa_log_warn("Failed to export memory block."); */ 71253a5a1b3Sopenharmony_ci 71353a5a1b3Sopenharmony_ci if (current_export != p->export) 71453a5a1b3Sopenharmony_ci pa_memexport_free(current_export); 71553a5a1b3Sopenharmony_ci pa_mempool_unref(current_pool); 71653a5a1b3Sopenharmony_ci } 71753a5a1b3Sopenharmony_ci 71853a5a1b3Sopenharmony_ci if (send_payload) { 71953a5a1b3Sopenharmony_ci p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl((uint32_t) p->write.current->chunk.length); 72053a5a1b3Sopenharmony_ci p->write.memchunk = p->write.current->chunk; 72153a5a1b3Sopenharmony_ci pa_memblock_ref(p->write.memchunk.memblock); 72253a5a1b3Sopenharmony_ci } 72353a5a1b3Sopenharmony_ci 72453a5a1b3Sopenharmony_ci p->write.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS] = htonl(flags); 72553a5a1b3Sopenharmony_ci } 72653a5a1b3Sopenharmony_ci 72753a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 72853a5a1b3Sopenharmony_ci if ((p->send_ancil_data_now = p->write.current->with_ancil_data)) 72953a5a1b3Sopenharmony_ci p->write_ancil_data = &p->write.current->ancil_data; 73053a5a1b3Sopenharmony_ci#endif 73153a5a1b3Sopenharmony_ci} 73253a5a1b3Sopenharmony_ci 73353a5a1b3Sopenharmony_cistatic void check_srbpending(pa_pstream *p) { 73453a5a1b3Sopenharmony_ci if (!p->is_srbpending) 73553a5a1b3Sopenharmony_ci return; 73653a5a1b3Sopenharmony_ci 73753a5a1b3Sopenharmony_ci if (p->srb) 73853a5a1b3Sopenharmony_ci pa_srbchannel_free(p->srb); 73953a5a1b3Sopenharmony_ci 74053a5a1b3Sopenharmony_ci p->srb = p->srbpending; 74153a5a1b3Sopenharmony_ci p->is_srbpending = false; 74253a5a1b3Sopenharmony_ci 74353a5a1b3Sopenharmony_ci if (p->srb) 74453a5a1b3Sopenharmony_ci pa_srbchannel_set_callback(p->srb, srb_callback, p); 74553a5a1b3Sopenharmony_ci} 74653a5a1b3Sopenharmony_ci 74753a5a1b3Sopenharmony_cistatic int do_write(pa_pstream *p) { 74853a5a1b3Sopenharmony_ci void *d; 74953a5a1b3Sopenharmony_ci size_t l; 75053a5a1b3Sopenharmony_ci ssize_t r; 75153a5a1b3Sopenharmony_ci pa_memblock *release_memblock = NULL; 75253a5a1b3Sopenharmony_ci 75353a5a1b3Sopenharmony_ci pa_assert(p); 75453a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 75553a5a1b3Sopenharmony_ci 75653a5a1b3Sopenharmony_ci if (!p->write.current) 75753a5a1b3Sopenharmony_ci prepare_next_write_item(p); 75853a5a1b3Sopenharmony_ci 75953a5a1b3Sopenharmony_ci if (!p->write.current) { 76053a5a1b3Sopenharmony_ci /* The out queue is empty, so switching channels is safe */ 76153a5a1b3Sopenharmony_ci check_srbpending(p); 76253a5a1b3Sopenharmony_ci return 0; 76353a5a1b3Sopenharmony_ci } 76453a5a1b3Sopenharmony_ci 76553a5a1b3Sopenharmony_ci if (p->write.minibuf_validsize > 0) { 76653a5a1b3Sopenharmony_ci d = p->write.minibuf + p->write.index; 76753a5a1b3Sopenharmony_ci l = p->write.minibuf_validsize - p->write.index; 76853a5a1b3Sopenharmony_ci } else if (p->write.index < PA_PSTREAM_DESCRIPTOR_SIZE) { 76953a5a1b3Sopenharmony_ci d = (uint8_t*) p->write.descriptor + p->write.index; 77053a5a1b3Sopenharmony_ci l = PA_PSTREAM_DESCRIPTOR_SIZE - p->write.index; 77153a5a1b3Sopenharmony_ci } else { 77253a5a1b3Sopenharmony_ci pa_assert(p->write.data || p->write.memchunk.memblock); 77353a5a1b3Sopenharmony_ci 77453a5a1b3Sopenharmony_ci if (p->write.data) 77553a5a1b3Sopenharmony_ci d = p->write.data; 77653a5a1b3Sopenharmony_ci else { 77753a5a1b3Sopenharmony_ci d = pa_memblock_acquire_chunk(&p->write.memchunk); 77853a5a1b3Sopenharmony_ci release_memblock = p->write.memchunk.memblock; 77953a5a1b3Sopenharmony_ci } 78053a5a1b3Sopenharmony_ci 78153a5a1b3Sopenharmony_ci d = (uint8_t*) d + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE; 78253a5a1b3Sopenharmony_ci l = ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE); 78353a5a1b3Sopenharmony_ci } 78453a5a1b3Sopenharmony_ci 78553a5a1b3Sopenharmony_ci pa_assert(l > 0); 78653a5a1b3Sopenharmony_ci 78753a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 78853a5a1b3Sopenharmony_ci if (p->send_ancil_data_now) { 78953a5a1b3Sopenharmony_ci if (p->write_ancil_data->creds_valid) { 79053a5a1b3Sopenharmony_ci pa_assert(p->write_ancil_data->nfd == 0); 79153a5a1b3Sopenharmony_ci if ((r = pa_iochannel_write_with_creds(p->io, d, l, &p->write_ancil_data->creds)) < 0) 79253a5a1b3Sopenharmony_ci goto fail; 79353a5a1b3Sopenharmony_ci } 79453a5a1b3Sopenharmony_ci else 79553a5a1b3Sopenharmony_ci if ((r = pa_iochannel_write_with_fds(p->io, d, l, p->write_ancil_data->nfd, p->write_ancil_data->fds)) < 0) 79653a5a1b3Sopenharmony_ci goto fail; 79753a5a1b3Sopenharmony_ci 79853a5a1b3Sopenharmony_ci pa_cmsg_ancil_data_close_fds(p->write_ancil_data); 79953a5a1b3Sopenharmony_ci p->send_ancil_data_now = false; 80053a5a1b3Sopenharmony_ci } else 80153a5a1b3Sopenharmony_ci#endif 80253a5a1b3Sopenharmony_ci if (p->srb) 80353a5a1b3Sopenharmony_ci r = pa_srbchannel_write(p->srb, d, l); 80453a5a1b3Sopenharmony_ci else if ((r = pa_iochannel_write(p->io, d, l)) < 0) 80553a5a1b3Sopenharmony_ci goto fail; 80653a5a1b3Sopenharmony_ci 80753a5a1b3Sopenharmony_ci if (release_memblock) 80853a5a1b3Sopenharmony_ci pa_memblock_release(release_memblock); 80953a5a1b3Sopenharmony_ci 81053a5a1b3Sopenharmony_ci p->write.index += (size_t) r; 81153a5a1b3Sopenharmony_ci 81253a5a1b3Sopenharmony_ci if (p->write.index >= PA_PSTREAM_DESCRIPTOR_SIZE + ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])) { 81353a5a1b3Sopenharmony_ci pa_assert(p->write.current); 81453a5a1b3Sopenharmony_ci item_free(p->write.current); 81553a5a1b3Sopenharmony_ci p->write.current = NULL; 81653a5a1b3Sopenharmony_ci 81753a5a1b3Sopenharmony_ci if (p->write.memchunk.memblock) 81853a5a1b3Sopenharmony_ci pa_memblock_unref(p->write.memchunk.memblock); 81953a5a1b3Sopenharmony_ci 82053a5a1b3Sopenharmony_ci pa_memchunk_reset(&p->write.memchunk); 82153a5a1b3Sopenharmony_ci 82253a5a1b3Sopenharmony_ci if (p->drain_callback && !pa_pstream_is_pending(p)) 82353a5a1b3Sopenharmony_ci p->drain_callback(p, p->drain_callback_userdata); 82453a5a1b3Sopenharmony_ci } 82553a5a1b3Sopenharmony_ci 82653a5a1b3Sopenharmony_ci return (size_t) r == l ? 1 : 0; 82753a5a1b3Sopenharmony_ci 82853a5a1b3Sopenharmony_cifail: 82953a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 83053a5a1b3Sopenharmony_ci if (p->send_ancil_data_now) 83153a5a1b3Sopenharmony_ci pa_cmsg_ancil_data_close_fds(p->write_ancil_data); 83253a5a1b3Sopenharmony_ci#endif 83353a5a1b3Sopenharmony_ci 83453a5a1b3Sopenharmony_ci if (release_memblock) 83553a5a1b3Sopenharmony_ci pa_memblock_release(release_memblock); 83653a5a1b3Sopenharmony_ci 83753a5a1b3Sopenharmony_ci return -1; 83853a5a1b3Sopenharmony_ci} 83953a5a1b3Sopenharmony_ci 84053a5a1b3Sopenharmony_cistatic void memblock_complete(pa_pstream *p, struct pstream_read *re) { 84153a5a1b3Sopenharmony_ci pa_memchunk chunk; 84253a5a1b3Sopenharmony_ci int64_t offset; 84353a5a1b3Sopenharmony_ci 84453a5a1b3Sopenharmony_ci if (!p->receive_memblock_callback) 84553a5a1b3Sopenharmony_ci return; 84653a5a1b3Sopenharmony_ci 84753a5a1b3Sopenharmony_ci chunk.memblock = re->memblock; 84853a5a1b3Sopenharmony_ci chunk.index = 0; 84953a5a1b3Sopenharmony_ci chunk.length = re->index - PA_PSTREAM_DESCRIPTOR_SIZE; 85053a5a1b3Sopenharmony_ci 85153a5a1b3Sopenharmony_ci offset = (int64_t) ( 85253a5a1b3Sopenharmony_ci (((uint64_t) ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])) << 32) | 85353a5a1b3Sopenharmony_ci (((uint64_t) ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO])))); 85453a5a1b3Sopenharmony_ci 85553a5a1b3Sopenharmony_ci p->receive_memblock_callback( 85653a5a1b3Sopenharmony_ci p, 85753a5a1b3Sopenharmony_ci ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]), 85853a5a1b3Sopenharmony_ci offset, 85953a5a1b3Sopenharmony_ci ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS]) & PA_FLAG_SEEKMASK, 86053a5a1b3Sopenharmony_ci &chunk, 86153a5a1b3Sopenharmony_ci p->receive_memblock_callback_userdata); 86253a5a1b3Sopenharmony_ci} 86353a5a1b3Sopenharmony_ci 86453a5a1b3Sopenharmony_cistatic int do_read(pa_pstream *p, struct pstream_read *re) { 86553a5a1b3Sopenharmony_ci void *d; 86653a5a1b3Sopenharmony_ci size_t l; 86753a5a1b3Sopenharmony_ci ssize_t r; 86853a5a1b3Sopenharmony_ci pa_memblock *release_memblock = NULL; 86953a5a1b3Sopenharmony_ci pa_assert(p); 87053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 87153a5a1b3Sopenharmony_ci 87253a5a1b3Sopenharmony_ci if (re->index < PA_PSTREAM_DESCRIPTOR_SIZE) { 87353a5a1b3Sopenharmony_ci d = (uint8_t*) re->descriptor + re->index; 87453a5a1b3Sopenharmony_ci l = PA_PSTREAM_DESCRIPTOR_SIZE - re->index; 87553a5a1b3Sopenharmony_ci } else { 87653a5a1b3Sopenharmony_ci pa_assert(re->data || re->memblock); 87753a5a1b3Sopenharmony_ci 87853a5a1b3Sopenharmony_ci if (re->data) 87953a5a1b3Sopenharmony_ci d = re->data; 88053a5a1b3Sopenharmony_ci else { 88153a5a1b3Sopenharmony_ci d = pa_memblock_acquire(re->memblock); 88253a5a1b3Sopenharmony_ci release_memblock = re->memblock; 88353a5a1b3Sopenharmony_ci } 88453a5a1b3Sopenharmony_ci 88553a5a1b3Sopenharmony_ci d = (uint8_t*) d + re->index - PA_PSTREAM_DESCRIPTOR_SIZE; 88653a5a1b3Sopenharmony_ci l = ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (re->index - PA_PSTREAM_DESCRIPTOR_SIZE); 88753a5a1b3Sopenharmony_ci } 88853a5a1b3Sopenharmony_ci 88953a5a1b3Sopenharmony_ci if (re == &p->readsrb) { 89053a5a1b3Sopenharmony_ci r = pa_srbchannel_read(p->srb, d, l); 89153a5a1b3Sopenharmony_ci if (r == 0) { 89253a5a1b3Sopenharmony_ci if (release_memblock) 89353a5a1b3Sopenharmony_ci pa_memblock_release(release_memblock); 89453a5a1b3Sopenharmony_ci return 1; 89553a5a1b3Sopenharmony_ci } 89653a5a1b3Sopenharmony_ci } 89753a5a1b3Sopenharmony_ci else 89853a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 89953a5a1b3Sopenharmony_ci { 90053a5a1b3Sopenharmony_ci pa_cmsg_ancil_data b; 90153a5a1b3Sopenharmony_ci 90253a5a1b3Sopenharmony_ci if ((r = pa_iochannel_read_with_ancil_data(p->io, d, l, &b)) <= 0) 90353a5a1b3Sopenharmony_ci goto fail; 90453a5a1b3Sopenharmony_ci 90553a5a1b3Sopenharmony_ci if (b.creds_valid) { 90653a5a1b3Sopenharmony_ci p->read_ancil_data.creds_valid = true; 90753a5a1b3Sopenharmony_ci p->read_ancil_data.creds = b.creds; 90853a5a1b3Sopenharmony_ci } 90953a5a1b3Sopenharmony_ci if (b.nfd > 0) { 91053a5a1b3Sopenharmony_ci pa_assert(b.nfd <= MAX_ANCIL_DATA_FDS); 91153a5a1b3Sopenharmony_ci p->read_ancil_data.nfd = b.nfd; 91253a5a1b3Sopenharmony_ci memcpy(p->read_ancil_data.fds, b.fds, sizeof(int) * b.nfd); 91353a5a1b3Sopenharmony_ci p->read_ancil_data.close_fds_on_cleanup = b.close_fds_on_cleanup; 91453a5a1b3Sopenharmony_ci } 91553a5a1b3Sopenharmony_ci } 91653a5a1b3Sopenharmony_ci#else 91753a5a1b3Sopenharmony_ci if ((r = pa_iochannel_read(p->io, d, l)) <= 0) 91853a5a1b3Sopenharmony_ci goto fail; 91953a5a1b3Sopenharmony_ci#endif 92053a5a1b3Sopenharmony_ci 92153a5a1b3Sopenharmony_ci if (release_memblock) 92253a5a1b3Sopenharmony_ci pa_memblock_release(release_memblock); 92353a5a1b3Sopenharmony_ci 92453a5a1b3Sopenharmony_ci re->index += (size_t) r; 92553a5a1b3Sopenharmony_ci 92653a5a1b3Sopenharmony_ci if (re->index == PA_PSTREAM_DESCRIPTOR_SIZE) { 92753a5a1b3Sopenharmony_ci uint32_t flags, length, channel; 92853a5a1b3Sopenharmony_ci /* Reading of frame descriptor complete */ 92953a5a1b3Sopenharmony_ci 93053a5a1b3Sopenharmony_ci flags = ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS]); 93153a5a1b3Sopenharmony_ci 93253a5a1b3Sopenharmony_ci if (!p->use_shm && (flags & PA_FLAG_SHMMASK) != 0) { 93353a5a1b3Sopenharmony_ci pa_log_warn("Received SHM frame on a socket where SHM is disabled."); 93453a5a1b3Sopenharmony_ci return -1; 93553a5a1b3Sopenharmony_ci } 93653a5a1b3Sopenharmony_ci 93753a5a1b3Sopenharmony_ci if (flags == PA_FLAG_SHMRELEASE) { 93853a5a1b3Sopenharmony_ci 93953a5a1b3Sopenharmony_ci /* This is a SHM memblock release frame with no payload */ 94053a5a1b3Sopenharmony_ci 94153a5a1b3Sopenharmony_ci/* pa_log("Got release frame for %u", ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); */ 94253a5a1b3Sopenharmony_ci 94353a5a1b3Sopenharmony_ci pa_assert(p->export); 94453a5a1b3Sopenharmony_ci pa_memexport_process_release(p->export, ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); 94553a5a1b3Sopenharmony_ci 94653a5a1b3Sopenharmony_ci goto frame_done; 94753a5a1b3Sopenharmony_ci 94853a5a1b3Sopenharmony_ci } else if (flags == PA_FLAG_SHMREVOKE) { 94953a5a1b3Sopenharmony_ci 95053a5a1b3Sopenharmony_ci /* This is a SHM memblock revoke frame with no payload */ 95153a5a1b3Sopenharmony_ci 95253a5a1b3Sopenharmony_ci/* pa_log("Got revoke frame for %u", ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); */ 95353a5a1b3Sopenharmony_ci 95453a5a1b3Sopenharmony_ci pa_assert(p->import); 95553a5a1b3Sopenharmony_ci pa_memimport_process_revoke(p->import, ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); 95653a5a1b3Sopenharmony_ci 95753a5a1b3Sopenharmony_ci goto frame_done; 95853a5a1b3Sopenharmony_ci } 95953a5a1b3Sopenharmony_ci 96053a5a1b3Sopenharmony_ci length = ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]); 96153a5a1b3Sopenharmony_ci 96253a5a1b3Sopenharmony_ci if (length > FRAME_SIZE_MAX_ALLOW || length <= 0) { 96353a5a1b3Sopenharmony_ci pa_log_warn("Received invalid frame size: %lu", (unsigned long) length); 96453a5a1b3Sopenharmony_ci return -1; 96553a5a1b3Sopenharmony_ci } 96653a5a1b3Sopenharmony_ci 96753a5a1b3Sopenharmony_ci pa_assert(!re->packet && !re->memblock); 96853a5a1b3Sopenharmony_ci 96953a5a1b3Sopenharmony_ci channel = ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]); 97053a5a1b3Sopenharmony_ci 97153a5a1b3Sopenharmony_ci if (channel == (uint32_t) -1) { 97253a5a1b3Sopenharmony_ci size_t plen; 97353a5a1b3Sopenharmony_ci 97453a5a1b3Sopenharmony_ci if (flags != 0) { 97553a5a1b3Sopenharmony_ci pa_log_warn("Received packet frame with invalid flags value."); 97653a5a1b3Sopenharmony_ci return -1; 97753a5a1b3Sopenharmony_ci } 97853a5a1b3Sopenharmony_ci 97953a5a1b3Sopenharmony_ci /* Frame is a packet frame */ 98053a5a1b3Sopenharmony_ci re->packet = pa_packet_new(length); 98153a5a1b3Sopenharmony_ci re->data = (void *) pa_packet_data(re->packet, &plen); 98253a5a1b3Sopenharmony_ci 98353a5a1b3Sopenharmony_ci } else { 98453a5a1b3Sopenharmony_ci 98553a5a1b3Sopenharmony_ci if ((flags & PA_FLAG_SEEKMASK) > PA_SEEK_RELATIVE_END) { 98653a5a1b3Sopenharmony_ci pa_log_warn("Received memblock frame with invalid seek mode."); 98753a5a1b3Sopenharmony_ci return -1; 98853a5a1b3Sopenharmony_ci } 98953a5a1b3Sopenharmony_ci 99053a5a1b3Sopenharmony_ci if (((flags & PA_FLAG_SHMMASK) & PA_FLAG_SHMDATA) != 0) { 99153a5a1b3Sopenharmony_ci 99253a5a1b3Sopenharmony_ci if (length != sizeof(re->shm_info)) { 99353a5a1b3Sopenharmony_ci pa_log_warn("Received SHM memblock frame with invalid frame length."); 99453a5a1b3Sopenharmony_ci return -1; 99553a5a1b3Sopenharmony_ci } 99653a5a1b3Sopenharmony_ci 99753a5a1b3Sopenharmony_ci /* Frame is a memblock frame referencing an SHM memblock */ 99853a5a1b3Sopenharmony_ci re->data = re->shm_info; 99953a5a1b3Sopenharmony_ci 100053a5a1b3Sopenharmony_ci } else if ((flags & PA_FLAG_SHMMASK) == 0) { 100153a5a1b3Sopenharmony_ci 100253a5a1b3Sopenharmony_ci /* Frame is a memblock frame */ 100353a5a1b3Sopenharmony_ci 100453a5a1b3Sopenharmony_ci re->memblock = pa_memblock_new(p->mempool, length); 100553a5a1b3Sopenharmony_ci re->data = NULL; 100653a5a1b3Sopenharmony_ci } else { 100753a5a1b3Sopenharmony_ci 100853a5a1b3Sopenharmony_ci pa_log_warn("Received memblock frame with invalid flags value."); 100953a5a1b3Sopenharmony_ci return -1; 101053a5a1b3Sopenharmony_ci } 101153a5a1b3Sopenharmony_ci } 101253a5a1b3Sopenharmony_ci 101353a5a1b3Sopenharmony_ci } else if (re->index >= ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) + PA_PSTREAM_DESCRIPTOR_SIZE) { 101453a5a1b3Sopenharmony_ci /* Frame complete */ 101553a5a1b3Sopenharmony_ci 101653a5a1b3Sopenharmony_ci if (re->memblock) { 101753a5a1b3Sopenharmony_ci memblock_complete(p, re); 101853a5a1b3Sopenharmony_ci 101953a5a1b3Sopenharmony_ci /* This was a memblock frame. We can unref the memblock now */ 102053a5a1b3Sopenharmony_ci pa_memblock_unref(re->memblock); 102153a5a1b3Sopenharmony_ci 102253a5a1b3Sopenharmony_ci } else if (re->packet) { 102353a5a1b3Sopenharmony_ci 102453a5a1b3Sopenharmony_ci if (p->receive_packet_callback) 102553a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 102653a5a1b3Sopenharmony_ci p->receive_packet_callback(p, re->packet, &p->read_ancil_data, p->receive_packet_callback_userdata); 102753a5a1b3Sopenharmony_ci#else 102853a5a1b3Sopenharmony_ci p->receive_packet_callback(p, re->packet, NULL, p->receive_packet_callback_userdata); 102953a5a1b3Sopenharmony_ci#endif 103053a5a1b3Sopenharmony_ci 103153a5a1b3Sopenharmony_ci pa_packet_unref(re->packet); 103253a5a1b3Sopenharmony_ci } else { 103353a5a1b3Sopenharmony_ci pa_memblock *b = NULL; 103453a5a1b3Sopenharmony_ci uint32_t flags = ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS]); 103553a5a1b3Sopenharmony_ci uint32_t shm_id = ntohl(re->shm_info[PA_PSTREAM_SHM_SHMID]); 103653a5a1b3Sopenharmony_ci pa_mem_type_t type = (flags & PA_FLAG_SHMDATA_MEMFD_BLOCK) ? 103753a5a1b3Sopenharmony_ci PA_MEM_TYPE_SHARED_MEMFD : PA_MEM_TYPE_SHARED_POSIX; 103853a5a1b3Sopenharmony_ci 103953a5a1b3Sopenharmony_ci pa_assert(((flags & PA_FLAG_SHMMASK) & PA_FLAG_SHMDATA) != 0); 104053a5a1b3Sopenharmony_ci pa_assert(p->import); 104153a5a1b3Sopenharmony_ci 104253a5a1b3Sopenharmony_ci if (type == PA_MEM_TYPE_SHARED_MEMFD && p->use_memfd && 104353a5a1b3Sopenharmony_ci !pa_idxset_get_by_data(p->registered_memfd_ids, PA_UINT32_TO_PTR(shm_id), NULL)) { 104453a5a1b3Sopenharmony_ci 104553a5a1b3Sopenharmony_ci if (pa_log_ratelimit(PA_LOG_ERROR)) 104653a5a1b3Sopenharmony_ci pa_log("Ignoring received block reference with non-registered memfd ID = %u", shm_id); 104753a5a1b3Sopenharmony_ci 104853a5a1b3Sopenharmony_ci } else if (!(b = pa_memimport_get(p->import, 104953a5a1b3Sopenharmony_ci type, 105053a5a1b3Sopenharmony_ci ntohl(re->shm_info[PA_PSTREAM_SHM_BLOCKID]), 105153a5a1b3Sopenharmony_ci shm_id, 105253a5a1b3Sopenharmony_ci ntohl(re->shm_info[PA_PSTREAM_SHM_INDEX]), 105353a5a1b3Sopenharmony_ci ntohl(re->shm_info[PA_PSTREAM_SHM_LENGTH]), 105453a5a1b3Sopenharmony_ci !!(flags & PA_FLAG_SHMWRITABLE)))) { 105553a5a1b3Sopenharmony_ci 105653a5a1b3Sopenharmony_ci if (pa_log_ratelimit(PA_LOG_DEBUG)) 105753a5a1b3Sopenharmony_ci pa_log_debug("Failed to import memory block."); 105853a5a1b3Sopenharmony_ci } 105953a5a1b3Sopenharmony_ci 106053a5a1b3Sopenharmony_ci if (p->receive_memblock_callback) { 106153a5a1b3Sopenharmony_ci int64_t offset; 106253a5a1b3Sopenharmony_ci pa_memchunk chunk; 106353a5a1b3Sopenharmony_ci 106453a5a1b3Sopenharmony_ci chunk.memblock = b; 106553a5a1b3Sopenharmony_ci chunk.index = 0; 106653a5a1b3Sopenharmony_ci chunk.length = b ? pa_memblock_get_length(b) : ntohl(re->shm_info[PA_PSTREAM_SHM_LENGTH]); 106753a5a1b3Sopenharmony_ci 106853a5a1b3Sopenharmony_ci offset = (int64_t) ( 106953a5a1b3Sopenharmony_ci (((uint64_t) ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])) << 32) | 107053a5a1b3Sopenharmony_ci (((uint64_t) ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO])))); 107153a5a1b3Sopenharmony_ci 107253a5a1b3Sopenharmony_ci p->receive_memblock_callback( 107353a5a1b3Sopenharmony_ci p, 107453a5a1b3Sopenharmony_ci ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]), 107553a5a1b3Sopenharmony_ci offset, 107653a5a1b3Sopenharmony_ci ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS]) & PA_FLAG_SEEKMASK, 107753a5a1b3Sopenharmony_ci &chunk, 107853a5a1b3Sopenharmony_ci p->receive_memblock_callback_userdata); 107953a5a1b3Sopenharmony_ci } 108053a5a1b3Sopenharmony_ci 108153a5a1b3Sopenharmony_ci if (b) 108253a5a1b3Sopenharmony_ci pa_memblock_unref(b); 108353a5a1b3Sopenharmony_ci } 108453a5a1b3Sopenharmony_ci 108553a5a1b3Sopenharmony_ci goto frame_done; 108653a5a1b3Sopenharmony_ci } 108753a5a1b3Sopenharmony_ci 108853a5a1b3Sopenharmony_ci return 0; 108953a5a1b3Sopenharmony_ci 109053a5a1b3Sopenharmony_ciframe_done: 109153a5a1b3Sopenharmony_ci re->memblock = NULL; 109253a5a1b3Sopenharmony_ci re->packet = NULL; 109353a5a1b3Sopenharmony_ci re->index = 0; 109453a5a1b3Sopenharmony_ci re->data = NULL; 109553a5a1b3Sopenharmony_ci 109653a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 109753a5a1b3Sopenharmony_ci /* FIXME: Close received ancillary data fds if the pstream's 109853a5a1b3Sopenharmony_ci * receive_packet_callback did not do so. 109953a5a1b3Sopenharmony_ci * 110053a5a1b3Sopenharmony_ci * Malicious clients can attach fds to unknown commands, or attach them 110153a5a1b3Sopenharmony_ci * to commands that does not expect fds. By doing so, server will reach 110253a5a1b3Sopenharmony_ci * its open fd limit and future clients' SHM transfers will always fail. 110353a5a1b3Sopenharmony_ci */ 110453a5a1b3Sopenharmony_ci p->read_ancil_data.creds_valid = false; 110553a5a1b3Sopenharmony_ci p->read_ancil_data.nfd = 0; 110653a5a1b3Sopenharmony_ci#endif 110753a5a1b3Sopenharmony_ci 110853a5a1b3Sopenharmony_ci return 0; 110953a5a1b3Sopenharmony_ci 111053a5a1b3Sopenharmony_cifail: 111153a5a1b3Sopenharmony_ci if (release_memblock) 111253a5a1b3Sopenharmony_ci pa_memblock_release(release_memblock); 111353a5a1b3Sopenharmony_ci 111453a5a1b3Sopenharmony_ci return -1; 111553a5a1b3Sopenharmony_ci} 111653a5a1b3Sopenharmony_ci 111753a5a1b3Sopenharmony_civoid pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) { 111853a5a1b3Sopenharmony_ci pa_assert(p); 111953a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 112053a5a1b3Sopenharmony_ci 112153a5a1b3Sopenharmony_ci p->die_callback = cb; 112253a5a1b3Sopenharmony_ci p->die_callback_userdata = userdata; 112353a5a1b3Sopenharmony_ci} 112453a5a1b3Sopenharmony_ci 112553a5a1b3Sopenharmony_civoid pa_pstream_set_drain_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) { 112653a5a1b3Sopenharmony_ci pa_assert(p); 112753a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 112853a5a1b3Sopenharmony_ci 112953a5a1b3Sopenharmony_ci p->drain_callback = cb; 113053a5a1b3Sopenharmony_ci p->drain_callback_userdata = userdata; 113153a5a1b3Sopenharmony_ci} 113253a5a1b3Sopenharmony_ci 113353a5a1b3Sopenharmony_civoid pa_pstream_set_receive_packet_callback(pa_pstream *p, pa_pstream_packet_cb_t cb, void *userdata) { 113453a5a1b3Sopenharmony_ci pa_assert(p); 113553a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 113653a5a1b3Sopenharmony_ci 113753a5a1b3Sopenharmony_ci p->receive_packet_callback = cb; 113853a5a1b3Sopenharmony_ci p->receive_packet_callback_userdata = userdata; 113953a5a1b3Sopenharmony_ci} 114053a5a1b3Sopenharmony_ci 114153a5a1b3Sopenharmony_civoid pa_pstream_set_receive_memblock_callback(pa_pstream *p, pa_pstream_memblock_cb_t cb, void *userdata) { 114253a5a1b3Sopenharmony_ci pa_assert(p); 114353a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 114453a5a1b3Sopenharmony_ci 114553a5a1b3Sopenharmony_ci p->receive_memblock_callback = cb; 114653a5a1b3Sopenharmony_ci p->receive_memblock_callback_userdata = userdata; 114753a5a1b3Sopenharmony_ci} 114853a5a1b3Sopenharmony_ci 114953a5a1b3Sopenharmony_civoid pa_pstream_set_release_callback(pa_pstream *p, pa_pstream_block_id_cb_t cb, void *userdata) { 115053a5a1b3Sopenharmony_ci pa_assert(p); 115153a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 115253a5a1b3Sopenharmony_ci 115353a5a1b3Sopenharmony_ci p->release_callback = cb; 115453a5a1b3Sopenharmony_ci p->release_callback_userdata = userdata; 115553a5a1b3Sopenharmony_ci} 115653a5a1b3Sopenharmony_ci 115753a5a1b3Sopenharmony_civoid pa_pstream_set_revoke_callback(pa_pstream *p, pa_pstream_block_id_cb_t cb, void *userdata) { 115853a5a1b3Sopenharmony_ci pa_assert(p); 115953a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 116053a5a1b3Sopenharmony_ci 116153a5a1b3Sopenharmony_ci p->revoke_callback = cb; 116253a5a1b3Sopenharmony_ci p->revoke_callback_userdata = userdata; 116353a5a1b3Sopenharmony_ci} 116453a5a1b3Sopenharmony_ci 116553a5a1b3Sopenharmony_cibool pa_pstream_is_pending(pa_pstream *p) { 116653a5a1b3Sopenharmony_ci bool b; 116753a5a1b3Sopenharmony_ci 116853a5a1b3Sopenharmony_ci pa_assert(p); 116953a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 117053a5a1b3Sopenharmony_ci 117153a5a1b3Sopenharmony_ci if (p->dead) 117253a5a1b3Sopenharmony_ci b = false; 117353a5a1b3Sopenharmony_ci else 117453a5a1b3Sopenharmony_ci b = p->write.current || !pa_queue_isempty(p->send_queue); 117553a5a1b3Sopenharmony_ci 117653a5a1b3Sopenharmony_ci return b; 117753a5a1b3Sopenharmony_ci} 117853a5a1b3Sopenharmony_ci 117953a5a1b3Sopenharmony_civoid pa_pstream_unref(pa_pstream*p) { 118053a5a1b3Sopenharmony_ci pa_assert(p); 118153a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 118253a5a1b3Sopenharmony_ci 118353a5a1b3Sopenharmony_ci if (PA_REFCNT_DEC(p) <= 0) 118453a5a1b3Sopenharmony_ci pstream_free(p); 118553a5a1b3Sopenharmony_ci} 118653a5a1b3Sopenharmony_ci 118753a5a1b3Sopenharmony_cipa_pstream* pa_pstream_ref(pa_pstream*p) { 118853a5a1b3Sopenharmony_ci pa_assert(p); 118953a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 119053a5a1b3Sopenharmony_ci 119153a5a1b3Sopenharmony_ci PA_REFCNT_INC(p); 119253a5a1b3Sopenharmony_ci return p; 119353a5a1b3Sopenharmony_ci} 119453a5a1b3Sopenharmony_ci 119553a5a1b3Sopenharmony_civoid pa_pstream_unlink(pa_pstream *p) { 119653a5a1b3Sopenharmony_ci pa_assert(p); 119753a5a1b3Sopenharmony_ci 119853a5a1b3Sopenharmony_ci if (p->dead) 119953a5a1b3Sopenharmony_ci return; 120053a5a1b3Sopenharmony_ci 120153a5a1b3Sopenharmony_ci p->dead = true; 120253a5a1b3Sopenharmony_ci 120353a5a1b3Sopenharmony_ci while (p->srb || p->is_srbpending) /* In theory there could be one active and one pending */ 120453a5a1b3Sopenharmony_ci pa_pstream_set_srbchannel(p, NULL); 120553a5a1b3Sopenharmony_ci 120653a5a1b3Sopenharmony_ci if (p->import) { 120753a5a1b3Sopenharmony_ci pa_memimport_free(p->import); 120853a5a1b3Sopenharmony_ci p->import = NULL; 120953a5a1b3Sopenharmony_ci } 121053a5a1b3Sopenharmony_ci 121153a5a1b3Sopenharmony_ci if (p->export) { 121253a5a1b3Sopenharmony_ci pa_memexport_free(p->export); 121353a5a1b3Sopenharmony_ci p->export = NULL; 121453a5a1b3Sopenharmony_ci } 121553a5a1b3Sopenharmony_ci 121653a5a1b3Sopenharmony_ci if (p->io) { 121753a5a1b3Sopenharmony_ci pa_iochannel_free(p->io); 121853a5a1b3Sopenharmony_ci p->io = NULL; 121953a5a1b3Sopenharmony_ci } 122053a5a1b3Sopenharmony_ci 122153a5a1b3Sopenharmony_ci if (p->defer_event) { 122253a5a1b3Sopenharmony_ci p->mainloop->defer_free(p->defer_event); 122353a5a1b3Sopenharmony_ci p->defer_event = NULL; 122453a5a1b3Sopenharmony_ci } 122553a5a1b3Sopenharmony_ci 122653a5a1b3Sopenharmony_ci p->die_callback = NULL; 122753a5a1b3Sopenharmony_ci p->drain_callback = NULL; 122853a5a1b3Sopenharmony_ci p->receive_packet_callback = NULL; 122953a5a1b3Sopenharmony_ci p->receive_memblock_callback = NULL; 123053a5a1b3Sopenharmony_ci} 123153a5a1b3Sopenharmony_ci 123253a5a1b3Sopenharmony_civoid pa_pstream_enable_shm(pa_pstream *p, bool enable) { 123353a5a1b3Sopenharmony_ci pa_assert(p); 123453a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 123553a5a1b3Sopenharmony_ci 123653a5a1b3Sopenharmony_ci p->use_shm = enable; 123753a5a1b3Sopenharmony_ci 123853a5a1b3Sopenharmony_ci if (enable) { 123953a5a1b3Sopenharmony_ci 124053a5a1b3Sopenharmony_ci if (!p->export) 124153a5a1b3Sopenharmony_ci p->export = pa_memexport_new(p->mempool, memexport_revoke_cb, p); 124253a5a1b3Sopenharmony_ci 124353a5a1b3Sopenharmony_ci } else { 124453a5a1b3Sopenharmony_ci 124553a5a1b3Sopenharmony_ci if (p->export) { 124653a5a1b3Sopenharmony_ci pa_memexport_free(p->export); 124753a5a1b3Sopenharmony_ci p->export = NULL; 124853a5a1b3Sopenharmony_ci } 124953a5a1b3Sopenharmony_ci } 125053a5a1b3Sopenharmony_ci} 125153a5a1b3Sopenharmony_ci 125253a5a1b3Sopenharmony_civoid pa_pstream_enable_memfd(pa_pstream *p) { 125353a5a1b3Sopenharmony_ci pa_assert(p); 125453a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 125553a5a1b3Sopenharmony_ci pa_assert(p->use_shm); 125653a5a1b3Sopenharmony_ci 125753a5a1b3Sopenharmony_ci p->use_memfd = true; 125853a5a1b3Sopenharmony_ci 125953a5a1b3Sopenharmony_ci if (!p->registered_memfd_ids) { 126053a5a1b3Sopenharmony_ci p->registered_memfd_ids = pa_idxset_new(NULL, NULL); 126153a5a1b3Sopenharmony_ci } 126253a5a1b3Sopenharmony_ci} 126353a5a1b3Sopenharmony_ci 126453a5a1b3Sopenharmony_cibool pa_pstream_get_shm(pa_pstream *p) { 126553a5a1b3Sopenharmony_ci pa_assert(p); 126653a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 126753a5a1b3Sopenharmony_ci 126853a5a1b3Sopenharmony_ci return p->use_shm; 126953a5a1b3Sopenharmony_ci} 127053a5a1b3Sopenharmony_ci 127153a5a1b3Sopenharmony_cibool pa_pstream_get_memfd(pa_pstream *p) { 127253a5a1b3Sopenharmony_ci pa_assert(p); 127353a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0); 127453a5a1b3Sopenharmony_ci 127553a5a1b3Sopenharmony_ci return p->use_memfd; 127653a5a1b3Sopenharmony_ci} 127753a5a1b3Sopenharmony_ci 127853a5a1b3Sopenharmony_civoid pa_pstream_set_srbchannel(pa_pstream *p, pa_srbchannel *srb) { 127953a5a1b3Sopenharmony_ci pa_assert(p); 128053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) > 0 || srb == NULL); 128153a5a1b3Sopenharmony_ci 128253a5a1b3Sopenharmony_ci if (srb == p->srb) 128353a5a1b3Sopenharmony_ci return; 128453a5a1b3Sopenharmony_ci 128553a5a1b3Sopenharmony_ci /* We can't handle quick switches between srbchannels. */ 128653a5a1b3Sopenharmony_ci pa_assert(!p->is_srbpending); 128753a5a1b3Sopenharmony_ci 128853a5a1b3Sopenharmony_ci p->srbpending = srb; 128953a5a1b3Sopenharmony_ci p->is_srbpending = true; 129053a5a1b3Sopenharmony_ci 129153a5a1b3Sopenharmony_ci /* Switch immediately, if possible. */ 129253a5a1b3Sopenharmony_ci if (p->dead) 129353a5a1b3Sopenharmony_ci check_srbpending(p); 129453a5a1b3Sopenharmony_ci else 129553a5a1b3Sopenharmony_ci do_write(p); 129653a5a1b3Sopenharmony_ci} 1297