static int do_read(struct userdata *u) { pa_assert(u); if (!pa_iochannel_is_readable(u->io)) return 0; if (u->state == STATE_AUTH || u->state == STATE_LATENCY) { ssize_t r; if (!u->read_data) return 0; pa_assert(u->read_index < u->read_length); if ((r = pa_iochannel_read(u->io, (uint8_t*) u->read_data + u->read_index, u->read_length - u->read_index)) <= 0) { pa_log("read() failed: %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } u->read_index += (size_t) r; pa_assert(u->read_index <= u->read_length); if (u->read_index == u->read_length) return handle_response(u); } return 0; }
static int do_read(connection *c) { pa_memchunk chunk; ssize_t r; size_t l; void *p; size_t space = 0; connection_assert_ref(c); if (!c->sink_input || (l = (size_t) pa_atomic_load(&c->playback.missing)) <= 0) return 0; if (c->playback.current_memblock) { space = pa_memblock_get_length(c->playback.current_memblock) - c->playback.memblock_index; if (space <= 0) { pa_memblock_unref(c->playback.current_memblock); c->playback.current_memblock = NULL; } } if (!c->playback.current_memblock) { pa_assert_se(c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, (size_t) -1)); c->playback.memblock_index = 0; space = pa_memblock_get_length(c->playback.current_memblock); } if (l > space) l = space; p = pa_memblock_acquire(c->playback.current_memblock); r = pa_iochannel_read(c->io, (uint8_t*) p + c->playback.memblock_index, l); pa_memblock_release(c->playback.current_memblock); if (r <= 0) { if (r < 0 && (errno == EINTR || errno == EAGAIN)) return 0; pa_log_debug("read(): %s", r == 0 ? "EOF" : pa_cstrerror(errno)); return -1; } chunk.memblock = c->playback.current_memblock; chunk.index = c->playback.memblock_index; chunk.length = (size_t) r; c->playback.memblock_index += (size_t) r; pa_asyncmsgq_post(c->sink_input->sink->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, &chunk, NULL); pa_atomic_sub(&c->playback.missing, (int) r); return 0; }
ssize_t pa_iochannel_read_with_ancil_data(pa_iochannel*io, void*data, size_t l, pa_cmsg_ancil_data *ancil_data) { ssize_t r; struct msghdr mh; struct iovec iov; union { struct cmsghdr hdr; uint8_t data[CMSG_SPACE(sizeof(struct ucred)) + CMSG_SPACE(sizeof(int) * MAX_ANCIL_DATA_FDS)]; } cmsg; pa_assert(io); pa_assert(data); pa_assert(l); pa_assert(io->ifd >= 0); pa_assert(ancil_data); if (io->ifd_type > 0) { ancil_data->creds_valid = false; ancil_data->nfd = 0; return pa_iochannel_read(io, data, l); } iov.iov_base = data; iov.iov_len = l; pa_zero(mh); mh.msg_iov = &iov; mh.msg_iovlen = 1; mh.msg_control = &cmsg; mh.msg_controllen = sizeof(cmsg); if ((r = recvmsg(io->ifd, &mh, 0)) >= 0) { struct cmsghdr *cmh; ancil_data->creds_valid = false; ancil_data->nfd = 0; for (cmh = CMSG_FIRSTHDR(&mh); cmh; cmh = CMSG_NXTHDR(&mh, cmh)) { if (cmh->cmsg_level != SOL_SOCKET) continue; if (cmh->cmsg_type == SCM_CREDENTIALS) { struct ucred u; pa_assert(cmh->cmsg_len == CMSG_LEN(sizeof(struct ucred))); memcpy(&u, CMSG_DATA(cmh), sizeof(struct ucred)); ancil_data->creds.gid = u.gid; ancil_data->creds.uid = u.uid; ancil_data->creds_valid = true; } else if (cmh->cmsg_type == SCM_RIGHTS) { int nfd = (cmh->cmsg_len - CMSG_LEN(0)) / sizeof(int); if (nfd > MAX_ANCIL_DATA_FDS) { int i; pa_log("Trying to receive too many file descriptors!"); for (i = 0; i < nfd; i++) pa_close(((int*) CMSG_DATA(cmh))[i]); continue; } memcpy(ancil_data->fds, CMSG_DATA(cmh), nfd * sizeof(int)); ancil_data->nfd = nfd; ancil_data->close_fds_on_cleanup = true; } } io->readable = io->hungup = false; enable_events(io); } if (r == -1 && errno == ENOTSOCK) { io->ifd_type = 1; return pa_iochannel_read_with_ancil_data(io, data, l, ancil_data); } return r; }