static void do_work(connection *c) { connection_assert_ref(c); if (c->dead) return; if (pa_iochannel_is_readable(c->io)) if (do_read(c) < 0) goto fail; if (!c->sink_input && pa_iochannel_is_hungup(c->io)) goto fail; if (pa_iochannel_is_writable(c->io)) if (do_write(c) < 0) goto fail; return; fail: if (c->sink_input) { /* If there is a sink input, we first drain what we already have read before shutting down the connection */ c->dead = TRUE; pa_iochannel_free(c->io); c->io = NULL; pa_asyncmsgq_post(c->sink_input->sink->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_DISABLE_PREBUF, NULL, 0, NULL, NULL); } else connection_unlink(c); }
static int do_write(struct userdata *u) { ssize_t r; pa_assert(u); if (!pa_iochannel_is_writable(u->io)) return 0; if (u->write_data) { pa_assert(u->write_index < u->write_length); if ((r = pa_iochannel_write(u->io, (uint8_t*) u->write_data + u->write_index, u->write_length - u->write_index)) <= 0) { pa_log("write() failed: %s", pa_cstrerror(errno)); return -1; } u->write_index += (size_t) r; pa_assert(u->write_index <= u->write_length); if (u->write_index == u->write_length) { pa_xfree(u->write_data); u->write_data = NULL; u->write_index = u->write_length = 0; } } if (!u->write_data && u->state == STATE_PREPARE) { int so_sndbuf = 0; socklen_t sl = sizeof(int); /* OK, we're done with sending all control data we need to, so * let's hand the socket over to the IO thread now */ pa_assert(u->fd < 0); u->fd = pa_iochannel_get_send_fd(u->io); pa_iochannel_set_noclose(u->io, TRUE); pa_iochannel_free(u->io); u->io = NULL; pa_make_tcp_socket_low_delay(u->fd); if (getsockopt(u->fd, SOL_SOCKET, SO_SNDBUF, &so_sndbuf, &sl) < 0) pa_log_warn("getsockopt(SO_SNDBUF) failed: %s", pa_cstrerror(errno)); else { pa_log_debug("SO_SNDBUF is %zu.", (size_t) so_sndbuf); pa_sink_set_max_request(u->sink, PA_MAX((size_t) so_sndbuf, u->block_size)); } pa_log_debug("Connection authenticated, handing fd to IO thread..."); pa_asyncmsgq_post(u->thread_mq.inq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_PASS_SOCKET, NULL, 0, NULL, NULL); u->state = STATE_RUNNING; } return 0; }