153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  Copyright 2004-2006 Lennart Poettering
553a5a1b3Sopenharmony_ci
653a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
753a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as published
853a5a1b3Sopenharmony_ci  by the Free Software Foundation; either version 2.1 of the License,
953a5a1b3Sopenharmony_ci  or (at your option) any later version.
1053a5a1b3Sopenharmony_ci
1153a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1253a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1353a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1453a5a1b3Sopenharmony_ci  General Public License for more details.
1553a5a1b3Sopenharmony_ci
1653a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public License
1753a5a1b3Sopenharmony_ci  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1853a5a1b3Sopenharmony_ci***/
1953a5a1b3Sopenharmony_ci
2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2153a5a1b3Sopenharmony_ci#include <config.h>
2253a5a1b3Sopenharmony_ci#endif
2353a5a1b3Sopenharmony_ci
2453a5a1b3Sopenharmony_ci#include <errno.h>
2553a5a1b3Sopenharmony_ci#include <stdio.h>
2653a5a1b3Sopenharmony_ci#include <stdlib.h>
2753a5a1b3Sopenharmony_ci#include <string.h>
2853a5a1b3Sopenharmony_ci
2953a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h>
3053a5a1b3Sopenharmony_ci
3153a5a1b3Sopenharmony_ci#include <pulsecore/socket.h>
3253a5a1b3Sopenharmony_ci#include <pulsecore/core-error.h>
3353a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h>
3453a5a1b3Sopenharmony_ci#include <pulsecore/log.h>
3553a5a1b3Sopenharmony_ci#include <pulsecore/macro.h>
3653a5a1b3Sopenharmony_ci#include <pulsecore/refcnt.h>
3753a5a1b3Sopenharmony_ci
3853a5a1b3Sopenharmony_ci#include "ioline.h"
3953a5a1b3Sopenharmony_ci
4053a5a1b3Sopenharmony_ci#define BUFFER_LIMIT (64*1024)
4153a5a1b3Sopenharmony_ci#define READ_SIZE (1024)
4253a5a1b3Sopenharmony_ci
4353a5a1b3Sopenharmony_cistruct pa_ioline {
4453a5a1b3Sopenharmony_ci    PA_REFCNT_DECLARE;
4553a5a1b3Sopenharmony_ci
4653a5a1b3Sopenharmony_ci    pa_iochannel *io;
4753a5a1b3Sopenharmony_ci    pa_defer_event *defer_event;
4853a5a1b3Sopenharmony_ci    pa_mainloop_api *mainloop;
4953a5a1b3Sopenharmony_ci
5053a5a1b3Sopenharmony_ci    char *wbuf;
5153a5a1b3Sopenharmony_ci    size_t wbuf_length, wbuf_index, wbuf_valid_length;
5253a5a1b3Sopenharmony_ci
5353a5a1b3Sopenharmony_ci    char *rbuf;
5453a5a1b3Sopenharmony_ci    size_t rbuf_length, rbuf_index, rbuf_valid_length;
5553a5a1b3Sopenharmony_ci
5653a5a1b3Sopenharmony_ci    pa_ioline_cb_t callback;
5753a5a1b3Sopenharmony_ci    void *userdata;
5853a5a1b3Sopenharmony_ci
5953a5a1b3Sopenharmony_ci    pa_ioline_drain_cb_t drain_callback;
6053a5a1b3Sopenharmony_ci    void *drain_userdata;
6153a5a1b3Sopenharmony_ci
6253a5a1b3Sopenharmony_ci    bool dead:1;
6353a5a1b3Sopenharmony_ci    bool defer_close:1;
6453a5a1b3Sopenharmony_ci};
6553a5a1b3Sopenharmony_ci
6653a5a1b3Sopenharmony_cistatic void io_callback(pa_iochannel*io, void *userdata);
6753a5a1b3Sopenharmony_cistatic void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata);
6853a5a1b3Sopenharmony_ci
6953a5a1b3Sopenharmony_cipa_ioline* pa_ioline_new(pa_iochannel *io) {
7053a5a1b3Sopenharmony_ci    pa_ioline *l;
7153a5a1b3Sopenharmony_ci    pa_assert(io);
7253a5a1b3Sopenharmony_ci
7353a5a1b3Sopenharmony_ci    l = pa_xnew(pa_ioline, 1);
7453a5a1b3Sopenharmony_ci    PA_REFCNT_INIT(l);
7553a5a1b3Sopenharmony_ci    l->io = io;
7653a5a1b3Sopenharmony_ci
7753a5a1b3Sopenharmony_ci    l->wbuf = NULL;
7853a5a1b3Sopenharmony_ci    l->wbuf_length = l->wbuf_index = l->wbuf_valid_length = 0;
7953a5a1b3Sopenharmony_ci
8053a5a1b3Sopenharmony_ci    l->rbuf = NULL;
8153a5a1b3Sopenharmony_ci    l->rbuf_length = l->rbuf_index = l->rbuf_valid_length = 0;
8253a5a1b3Sopenharmony_ci
8353a5a1b3Sopenharmony_ci    l->callback = NULL;
8453a5a1b3Sopenharmony_ci    l->userdata = NULL;
8553a5a1b3Sopenharmony_ci
8653a5a1b3Sopenharmony_ci    l->drain_callback = NULL;
8753a5a1b3Sopenharmony_ci    l->drain_userdata = NULL;
8853a5a1b3Sopenharmony_ci
8953a5a1b3Sopenharmony_ci    l->mainloop = pa_iochannel_get_mainloop_api(io);
9053a5a1b3Sopenharmony_ci
9153a5a1b3Sopenharmony_ci    l->defer_event = l->mainloop->defer_new(l->mainloop, defer_callback, l);
9253a5a1b3Sopenharmony_ci    l->mainloop->defer_enable(l->defer_event, 0);
9353a5a1b3Sopenharmony_ci
9453a5a1b3Sopenharmony_ci    l->dead = false;
9553a5a1b3Sopenharmony_ci    l->defer_close = false;
9653a5a1b3Sopenharmony_ci
9753a5a1b3Sopenharmony_ci    pa_iochannel_set_callback(io, io_callback, l);
9853a5a1b3Sopenharmony_ci
9953a5a1b3Sopenharmony_ci    return l;
10053a5a1b3Sopenharmony_ci}
10153a5a1b3Sopenharmony_ci
10253a5a1b3Sopenharmony_cistatic void ioline_free(pa_ioline *l) {
10353a5a1b3Sopenharmony_ci    pa_assert(l);
10453a5a1b3Sopenharmony_ci
10553a5a1b3Sopenharmony_ci    if (l->io)
10653a5a1b3Sopenharmony_ci        pa_iochannel_free(l->io);
10753a5a1b3Sopenharmony_ci
10853a5a1b3Sopenharmony_ci    if (l->defer_event)
10953a5a1b3Sopenharmony_ci        l->mainloop->defer_free(l->defer_event);
11053a5a1b3Sopenharmony_ci
11153a5a1b3Sopenharmony_ci    pa_xfree(l->wbuf);
11253a5a1b3Sopenharmony_ci    pa_xfree(l->rbuf);
11353a5a1b3Sopenharmony_ci    pa_xfree(l);
11453a5a1b3Sopenharmony_ci}
11553a5a1b3Sopenharmony_ci
11653a5a1b3Sopenharmony_civoid pa_ioline_unref(pa_ioline *l) {
11753a5a1b3Sopenharmony_ci    pa_assert(l);
11853a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(l) >= 1);
11953a5a1b3Sopenharmony_ci
12053a5a1b3Sopenharmony_ci    if (PA_REFCNT_DEC(l) <= 0)
12153a5a1b3Sopenharmony_ci        ioline_free(l);
12253a5a1b3Sopenharmony_ci}
12353a5a1b3Sopenharmony_ci
12453a5a1b3Sopenharmony_cipa_ioline* pa_ioline_ref(pa_ioline *l) {
12553a5a1b3Sopenharmony_ci    pa_assert(l);
12653a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(l) >= 1);
12753a5a1b3Sopenharmony_ci
12853a5a1b3Sopenharmony_ci    PA_REFCNT_INC(l);
12953a5a1b3Sopenharmony_ci    return l;
13053a5a1b3Sopenharmony_ci}
13153a5a1b3Sopenharmony_ci
13253a5a1b3Sopenharmony_civoid pa_ioline_close(pa_ioline *l) {
13353a5a1b3Sopenharmony_ci    pa_assert(l);
13453a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(l) >= 1);
13553a5a1b3Sopenharmony_ci
13653a5a1b3Sopenharmony_ci    l->dead = true;
13753a5a1b3Sopenharmony_ci
13853a5a1b3Sopenharmony_ci    if (l->io) {
13953a5a1b3Sopenharmony_ci        pa_iochannel_free(l->io);
14053a5a1b3Sopenharmony_ci        l->io = NULL;
14153a5a1b3Sopenharmony_ci    }
14253a5a1b3Sopenharmony_ci
14353a5a1b3Sopenharmony_ci    if (l->defer_event) {
14453a5a1b3Sopenharmony_ci        l->mainloop->defer_free(l->defer_event);
14553a5a1b3Sopenharmony_ci        l->defer_event = NULL;
14653a5a1b3Sopenharmony_ci    }
14753a5a1b3Sopenharmony_ci
14853a5a1b3Sopenharmony_ci    if (l->callback)
14953a5a1b3Sopenharmony_ci        l->callback = NULL;
15053a5a1b3Sopenharmony_ci}
15153a5a1b3Sopenharmony_ci
15253a5a1b3Sopenharmony_civoid pa_ioline_puts(pa_ioline *l, const char *c) {
15353a5a1b3Sopenharmony_ci    size_t len;
15453a5a1b3Sopenharmony_ci
15553a5a1b3Sopenharmony_ci    pa_assert(l);
15653a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(l) >= 1);
15753a5a1b3Sopenharmony_ci    pa_assert(c);
15853a5a1b3Sopenharmony_ci
15953a5a1b3Sopenharmony_ci    if (l->dead)
16053a5a1b3Sopenharmony_ci        return;
16153a5a1b3Sopenharmony_ci
16253a5a1b3Sopenharmony_ci    len = strlen(c);
16353a5a1b3Sopenharmony_ci    if (len > BUFFER_LIMIT - l->wbuf_valid_length)
16453a5a1b3Sopenharmony_ci        len = BUFFER_LIMIT - l->wbuf_valid_length;
16553a5a1b3Sopenharmony_ci
16653a5a1b3Sopenharmony_ci    if (len) {
16753a5a1b3Sopenharmony_ci        pa_assert(l->wbuf_length >= l->wbuf_valid_length);
16853a5a1b3Sopenharmony_ci
16953a5a1b3Sopenharmony_ci        /* In case the allocated buffer is too small, enlarge it. */
17053a5a1b3Sopenharmony_ci        if (l->wbuf_valid_length + len > l->wbuf_length) {
17153a5a1b3Sopenharmony_ci            size_t n = l->wbuf_valid_length+len;
17253a5a1b3Sopenharmony_ci            char *new = pa_xnew(char, (unsigned) n);
17353a5a1b3Sopenharmony_ci
17453a5a1b3Sopenharmony_ci            if (l->wbuf) {
17553a5a1b3Sopenharmony_ci                memcpy(new, l->wbuf+l->wbuf_index, l->wbuf_valid_length);
17653a5a1b3Sopenharmony_ci                pa_xfree(l->wbuf);
17753a5a1b3Sopenharmony_ci            }
17853a5a1b3Sopenharmony_ci
17953a5a1b3Sopenharmony_ci            l->wbuf = new;
18053a5a1b3Sopenharmony_ci            l->wbuf_length = n;
18153a5a1b3Sopenharmony_ci            l->wbuf_index = 0;
18253a5a1b3Sopenharmony_ci        } else if (l->wbuf_index + l->wbuf_valid_length + len > l->wbuf_length) {
18353a5a1b3Sopenharmony_ci
18453a5a1b3Sopenharmony_ci            /* In case the allocated buffer fits, but the current index is too far from the start, move it to the front. */
18553a5a1b3Sopenharmony_ci            memmove(l->wbuf, l->wbuf+l->wbuf_index, l->wbuf_valid_length);
18653a5a1b3Sopenharmony_ci            l->wbuf_index = 0;
18753a5a1b3Sopenharmony_ci        }
18853a5a1b3Sopenharmony_ci
18953a5a1b3Sopenharmony_ci        pa_assert(l->wbuf_index + l->wbuf_valid_length + len <= l->wbuf_length);
19053a5a1b3Sopenharmony_ci
19153a5a1b3Sopenharmony_ci        /* Append the new string */
19253a5a1b3Sopenharmony_ci        memcpy(l->wbuf + l->wbuf_index + l->wbuf_valid_length, c, len);
19353a5a1b3Sopenharmony_ci        l->wbuf_valid_length += len;
19453a5a1b3Sopenharmony_ci
19553a5a1b3Sopenharmony_ci        l->mainloop->defer_enable(l->defer_event, 1);
19653a5a1b3Sopenharmony_ci    }
19753a5a1b3Sopenharmony_ci}
19853a5a1b3Sopenharmony_ci
19953a5a1b3Sopenharmony_civoid pa_ioline_set_callback(pa_ioline*l, pa_ioline_cb_t callback, void *userdata) {
20053a5a1b3Sopenharmony_ci    pa_assert(l);
20153a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(l) >= 1);
20253a5a1b3Sopenharmony_ci
20353a5a1b3Sopenharmony_ci    if (l->dead)
20453a5a1b3Sopenharmony_ci        return;
20553a5a1b3Sopenharmony_ci
20653a5a1b3Sopenharmony_ci    l->callback = callback;
20753a5a1b3Sopenharmony_ci    l->userdata = userdata;
20853a5a1b3Sopenharmony_ci}
20953a5a1b3Sopenharmony_ci
21053a5a1b3Sopenharmony_civoid pa_ioline_set_drain_callback(pa_ioline*l, pa_ioline_drain_cb_t callback, void *userdata) {
21153a5a1b3Sopenharmony_ci    pa_assert(l);
21253a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(l) >= 1);
21353a5a1b3Sopenharmony_ci
21453a5a1b3Sopenharmony_ci    if (l->dead)
21553a5a1b3Sopenharmony_ci        return;
21653a5a1b3Sopenharmony_ci
21753a5a1b3Sopenharmony_ci    l->drain_callback = callback;
21853a5a1b3Sopenharmony_ci    l->drain_userdata = userdata;
21953a5a1b3Sopenharmony_ci}
22053a5a1b3Sopenharmony_ci
22153a5a1b3Sopenharmony_cistatic void failure(pa_ioline *l, bool process_leftover) {
22253a5a1b3Sopenharmony_ci    pa_assert(l);
22353a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(l) >= 1);
22453a5a1b3Sopenharmony_ci    pa_assert(!l->dead);
22553a5a1b3Sopenharmony_ci
22653a5a1b3Sopenharmony_ci    if (process_leftover && l->rbuf_valid_length > 0) {
22753a5a1b3Sopenharmony_ci        /* Pass the last missing bit to the client */
22853a5a1b3Sopenharmony_ci
22953a5a1b3Sopenharmony_ci        if (l->callback) {
23053a5a1b3Sopenharmony_ci            char *p = pa_xstrndup(l->rbuf+l->rbuf_index, l->rbuf_valid_length);
23153a5a1b3Sopenharmony_ci            l->callback(l, p, l->userdata);
23253a5a1b3Sopenharmony_ci            pa_xfree(p);
23353a5a1b3Sopenharmony_ci        }
23453a5a1b3Sopenharmony_ci    }
23553a5a1b3Sopenharmony_ci
23653a5a1b3Sopenharmony_ci    if (l->callback) {
23753a5a1b3Sopenharmony_ci        l->callback(l, NULL, l->userdata);
23853a5a1b3Sopenharmony_ci        l->callback = NULL;
23953a5a1b3Sopenharmony_ci    }
24053a5a1b3Sopenharmony_ci
24153a5a1b3Sopenharmony_ci    pa_ioline_close(l);
24253a5a1b3Sopenharmony_ci}
24353a5a1b3Sopenharmony_ci
24453a5a1b3Sopenharmony_cistatic void scan_for_lines(pa_ioline *l, size_t skip) {
24553a5a1b3Sopenharmony_ci    pa_assert(l);
24653a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(l) >= 1);
24753a5a1b3Sopenharmony_ci    pa_assert(skip < l->rbuf_valid_length);
24853a5a1b3Sopenharmony_ci
24953a5a1b3Sopenharmony_ci    while (!l->dead && l->rbuf_valid_length > skip) {
25053a5a1b3Sopenharmony_ci        char *e, *p;
25153a5a1b3Sopenharmony_ci        size_t m;
25253a5a1b3Sopenharmony_ci
25353a5a1b3Sopenharmony_ci        if (!(e = memchr(l->rbuf + l->rbuf_index + skip, '\n', l->rbuf_valid_length - skip)))
25453a5a1b3Sopenharmony_ci            break;
25553a5a1b3Sopenharmony_ci
25653a5a1b3Sopenharmony_ci        *e = 0;
25753a5a1b3Sopenharmony_ci
25853a5a1b3Sopenharmony_ci        p = l->rbuf + l->rbuf_index;
25953a5a1b3Sopenharmony_ci        m = strlen(p);
26053a5a1b3Sopenharmony_ci
26153a5a1b3Sopenharmony_ci        l->rbuf_index += m+1;
26253a5a1b3Sopenharmony_ci        l->rbuf_valid_length -= m+1;
26353a5a1b3Sopenharmony_ci
26453a5a1b3Sopenharmony_ci        /* A shortcut for the next time */
26553a5a1b3Sopenharmony_ci        if (l->rbuf_valid_length == 0)
26653a5a1b3Sopenharmony_ci            l->rbuf_index = 0;
26753a5a1b3Sopenharmony_ci
26853a5a1b3Sopenharmony_ci        if (l->callback)
26953a5a1b3Sopenharmony_ci            l->callback(l, pa_strip_nl(p), l->userdata);
27053a5a1b3Sopenharmony_ci
27153a5a1b3Sopenharmony_ci        skip = 0;
27253a5a1b3Sopenharmony_ci    }
27353a5a1b3Sopenharmony_ci
27453a5a1b3Sopenharmony_ci    /* If the buffer became too large and still no newline was found, drop it. */
27553a5a1b3Sopenharmony_ci    if (l->rbuf_valid_length >= BUFFER_LIMIT)
27653a5a1b3Sopenharmony_ci        l->rbuf_index = l->rbuf_valid_length = 0;
27753a5a1b3Sopenharmony_ci}
27853a5a1b3Sopenharmony_ci
27953a5a1b3Sopenharmony_cistatic int do_write(pa_ioline *l);
28053a5a1b3Sopenharmony_ci
28153a5a1b3Sopenharmony_cistatic int do_read(pa_ioline *l) {
28253a5a1b3Sopenharmony_ci    pa_assert(l);
28353a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(l) >= 1);
28453a5a1b3Sopenharmony_ci
28553a5a1b3Sopenharmony_ci    while (l->io && !l->dead && pa_iochannel_is_readable(l->io)) {
28653a5a1b3Sopenharmony_ci        ssize_t r;
28753a5a1b3Sopenharmony_ci        size_t len;
28853a5a1b3Sopenharmony_ci
28953a5a1b3Sopenharmony_ci        len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length;
29053a5a1b3Sopenharmony_ci
29153a5a1b3Sopenharmony_ci        /* Check if we have to enlarge the read buffer */
29253a5a1b3Sopenharmony_ci        if (len < READ_SIZE) {
29353a5a1b3Sopenharmony_ci            size_t n = l->rbuf_valid_length+READ_SIZE;
29453a5a1b3Sopenharmony_ci
29553a5a1b3Sopenharmony_ci            if (n >= BUFFER_LIMIT)
29653a5a1b3Sopenharmony_ci                n = BUFFER_LIMIT;
29753a5a1b3Sopenharmony_ci
29853a5a1b3Sopenharmony_ci            if (l->rbuf_length >= n) {
29953a5a1b3Sopenharmony_ci                /* The current buffer is large enough, let's just move the data to the front */
30053a5a1b3Sopenharmony_ci                if (l->rbuf_valid_length)
30153a5a1b3Sopenharmony_ci                    memmove(l->rbuf, l->rbuf+l->rbuf_index, l->rbuf_valid_length);
30253a5a1b3Sopenharmony_ci            } else {
30353a5a1b3Sopenharmony_ci                /* Enlarge the buffer */
30453a5a1b3Sopenharmony_ci                char *new = pa_xnew(char, (unsigned) n);
30553a5a1b3Sopenharmony_ci                if (l->rbuf_valid_length)
30653a5a1b3Sopenharmony_ci                    memcpy(new, l->rbuf+l->rbuf_index, l->rbuf_valid_length);
30753a5a1b3Sopenharmony_ci                pa_xfree(l->rbuf);
30853a5a1b3Sopenharmony_ci                l->rbuf = new;
30953a5a1b3Sopenharmony_ci                l->rbuf_length = n;
31053a5a1b3Sopenharmony_ci            }
31153a5a1b3Sopenharmony_ci
31253a5a1b3Sopenharmony_ci            l->rbuf_index = 0;
31353a5a1b3Sopenharmony_ci        }
31453a5a1b3Sopenharmony_ci
31553a5a1b3Sopenharmony_ci        len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length;
31653a5a1b3Sopenharmony_ci
31753a5a1b3Sopenharmony_ci        pa_assert(len >= READ_SIZE);
31853a5a1b3Sopenharmony_ci
31953a5a1b3Sopenharmony_ci        /* Read some data */
32053a5a1b3Sopenharmony_ci        if ((r = pa_iochannel_read(l->io, l->rbuf+l->rbuf_index+l->rbuf_valid_length, len)) <= 0) {
32153a5a1b3Sopenharmony_ci
32253a5a1b3Sopenharmony_ci            if (r < 0 && errno == EAGAIN)
32353a5a1b3Sopenharmony_ci                return 0;
32453a5a1b3Sopenharmony_ci
32553a5a1b3Sopenharmony_ci            if (r < 0 && errno != ECONNRESET) {
32653a5a1b3Sopenharmony_ci                pa_log("read(): %s", pa_cstrerror(errno));
32753a5a1b3Sopenharmony_ci                failure(l, false);
32853a5a1b3Sopenharmony_ci            } else
32953a5a1b3Sopenharmony_ci                failure(l, true);
33053a5a1b3Sopenharmony_ci
33153a5a1b3Sopenharmony_ci            return -1;
33253a5a1b3Sopenharmony_ci        }
33353a5a1b3Sopenharmony_ci
33453a5a1b3Sopenharmony_ci        l->rbuf_valid_length += (size_t) r;
33553a5a1b3Sopenharmony_ci
33653a5a1b3Sopenharmony_ci        /* Look if a line has been terminated in the newly read data */
33753a5a1b3Sopenharmony_ci        scan_for_lines(l, l->rbuf_valid_length - (size_t) r);
33853a5a1b3Sopenharmony_ci    }
33953a5a1b3Sopenharmony_ci
34053a5a1b3Sopenharmony_ci    return 0;
34153a5a1b3Sopenharmony_ci}
34253a5a1b3Sopenharmony_ci
34353a5a1b3Sopenharmony_ci/* Try to flush the buffer */
34453a5a1b3Sopenharmony_cistatic int do_write(pa_ioline *l) {
34553a5a1b3Sopenharmony_ci    ssize_t r;
34653a5a1b3Sopenharmony_ci
34753a5a1b3Sopenharmony_ci    pa_assert(l);
34853a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(l) >= 1);
34953a5a1b3Sopenharmony_ci
35053a5a1b3Sopenharmony_ci    while (l->io && !l->dead && pa_iochannel_is_writable(l->io) && l->wbuf_valid_length > 0) {
35153a5a1b3Sopenharmony_ci
35253a5a1b3Sopenharmony_ci        if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) < 0) {
35353a5a1b3Sopenharmony_ci
35453a5a1b3Sopenharmony_ci            if (errno != EPIPE)
35553a5a1b3Sopenharmony_ci                pa_log("write(): %s", pa_cstrerror(errno));
35653a5a1b3Sopenharmony_ci
35753a5a1b3Sopenharmony_ci            failure(l, false);
35853a5a1b3Sopenharmony_ci
35953a5a1b3Sopenharmony_ci            return -1;
36053a5a1b3Sopenharmony_ci        }
36153a5a1b3Sopenharmony_ci
36253a5a1b3Sopenharmony_ci        l->wbuf_index += (size_t) r;
36353a5a1b3Sopenharmony_ci        l->wbuf_valid_length -= (size_t) r;
36453a5a1b3Sopenharmony_ci
36553a5a1b3Sopenharmony_ci        /* A shortcut for the next time */
36653a5a1b3Sopenharmony_ci        if (l->wbuf_valid_length == 0)
36753a5a1b3Sopenharmony_ci            l->wbuf_index = 0;
36853a5a1b3Sopenharmony_ci    }
36953a5a1b3Sopenharmony_ci
37053a5a1b3Sopenharmony_ci    if (l->wbuf_valid_length <= 0 && l->drain_callback)
37153a5a1b3Sopenharmony_ci        l->drain_callback(l, l->drain_userdata);
37253a5a1b3Sopenharmony_ci
37353a5a1b3Sopenharmony_ci    return 0;
37453a5a1b3Sopenharmony_ci}
37553a5a1b3Sopenharmony_ci
37653a5a1b3Sopenharmony_ci/* Try to flush read/write data */
37753a5a1b3Sopenharmony_cistatic void do_work(pa_ioline *l) {
37853a5a1b3Sopenharmony_ci    pa_assert(l);
37953a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(l) >= 1);
38053a5a1b3Sopenharmony_ci
38153a5a1b3Sopenharmony_ci    pa_ioline_ref(l);
38253a5a1b3Sopenharmony_ci
38353a5a1b3Sopenharmony_ci    l->mainloop->defer_enable(l->defer_event, 0);
38453a5a1b3Sopenharmony_ci
38553a5a1b3Sopenharmony_ci    if (!l->dead)
38653a5a1b3Sopenharmony_ci        do_read(l);
38753a5a1b3Sopenharmony_ci
38853a5a1b3Sopenharmony_ci    if (!l->dead)
38953a5a1b3Sopenharmony_ci        do_write(l);
39053a5a1b3Sopenharmony_ci
39153a5a1b3Sopenharmony_ci    if (l->defer_close && !l->wbuf_valid_length)
39253a5a1b3Sopenharmony_ci        failure(l, true);
39353a5a1b3Sopenharmony_ci
39453a5a1b3Sopenharmony_ci    pa_ioline_unref(l);
39553a5a1b3Sopenharmony_ci}
39653a5a1b3Sopenharmony_ci
39753a5a1b3Sopenharmony_cistatic void io_callback(pa_iochannel*io, void *userdata) {
39853a5a1b3Sopenharmony_ci    pa_ioline *l = userdata;
39953a5a1b3Sopenharmony_ci
40053a5a1b3Sopenharmony_ci    pa_assert(io);
40153a5a1b3Sopenharmony_ci    pa_assert(l);
40253a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(l) >= 1);
40353a5a1b3Sopenharmony_ci
40453a5a1b3Sopenharmony_ci    do_work(l);
40553a5a1b3Sopenharmony_ci}
40653a5a1b3Sopenharmony_ci
40753a5a1b3Sopenharmony_cistatic void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata) {
40853a5a1b3Sopenharmony_ci    pa_ioline *l = userdata;
40953a5a1b3Sopenharmony_ci
41053a5a1b3Sopenharmony_ci    pa_assert(l);
41153a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(l) >= 1);
41253a5a1b3Sopenharmony_ci    pa_assert(l->mainloop == m);
41353a5a1b3Sopenharmony_ci    pa_assert(l->defer_event == e);
41453a5a1b3Sopenharmony_ci
41553a5a1b3Sopenharmony_ci    do_work(l);
41653a5a1b3Sopenharmony_ci}
41753a5a1b3Sopenharmony_ci
41853a5a1b3Sopenharmony_civoid pa_ioline_defer_close(pa_ioline *l) {
41953a5a1b3Sopenharmony_ci    pa_assert(l);
42053a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(l) >= 1);
42153a5a1b3Sopenharmony_ci
42253a5a1b3Sopenharmony_ci    l->defer_close = true;
42353a5a1b3Sopenharmony_ci
42453a5a1b3Sopenharmony_ci    if (!l->wbuf_valid_length)
42553a5a1b3Sopenharmony_ci        l->mainloop->defer_enable(l->defer_event, 1);
42653a5a1b3Sopenharmony_ci}
42753a5a1b3Sopenharmony_ci
42853a5a1b3Sopenharmony_civoid pa_ioline_printf(pa_ioline *l, const char *format, ...) {
42953a5a1b3Sopenharmony_ci    char *t;
43053a5a1b3Sopenharmony_ci    va_list ap;
43153a5a1b3Sopenharmony_ci
43253a5a1b3Sopenharmony_ci    pa_assert(l);
43353a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(l) >= 1);
43453a5a1b3Sopenharmony_ci
43553a5a1b3Sopenharmony_ci    va_start(ap, format);
43653a5a1b3Sopenharmony_ci    t = pa_vsprintf_malloc(format, ap);
43753a5a1b3Sopenharmony_ci    va_end(ap);
43853a5a1b3Sopenharmony_ci
43953a5a1b3Sopenharmony_ci    pa_ioline_puts(l, t);
44053a5a1b3Sopenharmony_ci    pa_xfree(t);
44153a5a1b3Sopenharmony_ci}
44253a5a1b3Sopenharmony_ci
44353a5a1b3Sopenharmony_cipa_iochannel* pa_ioline_detach_iochannel(pa_ioline *l) {
44453a5a1b3Sopenharmony_ci    pa_iochannel *r;
44553a5a1b3Sopenharmony_ci
44653a5a1b3Sopenharmony_ci    pa_assert(l);
44753a5a1b3Sopenharmony_ci
44853a5a1b3Sopenharmony_ci    if (!l->io)
44953a5a1b3Sopenharmony_ci        return NULL;
45053a5a1b3Sopenharmony_ci
45153a5a1b3Sopenharmony_ci    r = l->io;
45253a5a1b3Sopenharmony_ci    l->io = NULL;
45353a5a1b3Sopenharmony_ci
45453a5a1b3Sopenharmony_ci    pa_iochannel_set_callback(r, NULL, NULL);
45553a5a1b3Sopenharmony_ci
45653a5a1b3Sopenharmony_ci    return r;
45753a5a1b3Sopenharmony_ci}
45853a5a1b3Sopenharmony_ci
45953a5a1b3Sopenharmony_cibool pa_ioline_is_drained(pa_ioline *l) {
46053a5a1b3Sopenharmony_ci    pa_assert(l);
46153a5a1b3Sopenharmony_ci
46253a5a1b3Sopenharmony_ci    return l->wbuf_valid_length <= 0;
46353a5a1b3Sopenharmony_ci}
464