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