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;
}
Exemple #3
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;
}