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