static apr_status_t serf_copy_read_iovec()

in buckets/copy_buckets.c [170:265]


static apr_status_t serf_copy_read_iovec(serf_bucket_t *bucket,
                                         apr_size_t requested,
                                         int vecs_size,
                                         struct iovec *vecs,
                                         int *vecs_used)
{
    copy_context_t *ctx = bucket->data;
    apr_status_t status;
    apr_size_t total;
    apr_size_t fetched;
    int i;

    /* If somebody really wants to call us for 1 iovec, call the function
       that already implements the copying for this */
    if (vecs_size == 1) {
        const char *data;
        apr_size_t len;

        *vecs_used = 1;

        status = serf_copy_read(bucket, requested, &data, &len);

        vecs[0].iov_base = (void*)data;
        vecs[0].iov_len = len;
        *vecs_used = 1;

        return status;
    }

    status = serf_bucket_read_iovec(ctx->wrapped, requested,
                                    vecs_size, vecs, vecs_used);

    /* There are four possible results:

       EOF: if the wrapped bucket is done, then we must be done, too. it is
            quite possible we'll return less than MIN_SIZE, but with EOF, there
            is no way we'll be able to return that.
       EAGAIN: we cannot possibly read more (right now), so return. whatever
               was read, it is all we have, whether we met MIN_SIZE or not.
       error: any other error will prevent us from further work; return it.
       SUCCESS: we read a portion, and the bucket says we can read more.

       For all but SUCCESS, we simply return the status. We're done now.  */
    if (status)
        return status;

    /* How much was read on this pass?  */
    for (total = 0, i = *vecs_used; i-- > 0; )
        total += vecs[i].iov_len;

    /* The IOVEC holds at least MIN_SIZE data, so we're good. Or, it
       holds precisely the amount requested, so we shouldn't try to
       gather/accumulate more data.  */
    if (total >= ctx->min_size || total == requested)
        return APR_SUCCESS;
    /* TOTAL < REQUESTED. TOTAL < MIN_SIZE. We should try and fetch more.  */

    /* Copy what we have into our buffer. Then continue reading to get at
       least MIN_SIZE or REQUESTED bytes of data.  */
    if (! ctx->hold_buf)
        ctx->hold_buf = serf_bucket_mem_alloc(bucket->allocator,
                                              ctx->min_size);

    /* ### copy into HOLD_BUF. then read/append some more.  */
    fetched = total;
    serf__copy_iovec(ctx->hold_buf, NULL, vecs, *vecs_used);

    /* ### point vecs[0] at HOLD_BUF.  */
    vecs[0].iov_base = ctx->hold_buf;
    vecs[0].iov_len = fetched;

    while (TRUE) {
        int v_used;

        status = serf_bucket_read_iovec(ctx->wrapped, requested - fetched,
                                      vecs_size - 1, &vecs[1], &v_used);

        if (SERF_BUCKET_READ_ERROR(status)) {
            *vecs_used = 1;
            return APR_EAGAIN;
        }

        for (i = 1; i <= v_used; i++)
            total += vecs[i].iov_len;

        if (status || total >= ctx->min_size || total == requested) {
            *vecs_used = v_used + 1;
            return status;
        }

        serf__copy_iovec(ctx->hold_buf + fetched, NULL, &vecs[1], v_used);

        fetched += total;
        vecs[0].iov_len = fetched;
    }
}