Exemplo n.º 1
0
/**
 * Does a non-blocking read and either reads in the amount you requested
 * with "need" or less so you can try again.  It sets out_len to what is
 * available (<= need) so you can decide after that.  You can keep attempting
 * to read more and more (up to buf->len) and you'll get the same start point
 * each time.
 *
 * Once you're done with the data you've been trying to read, you use IOBuf_read_commit
 * to commit the "need" amount and then start doing new reads.
 *
 * Internally this works like a "half open ring buffer" and it tries to greedily
 * read as much as possible without blocking or copying.
 *
 * To just get as much as possible, use the IOBuf_read_some macro.
 */
char *IOBuf_read(IOBuf *buf, int need, int *out_len)
{
    int rc = 0;
    assert(buf->cur + buf->avail <= buf->len && 
            "Buffer math off, cur+avail can't be more than > len.");
    assert(buf->cur >= 0 && "Buffer cur can't be < 0");
    assert(buf->avail >= 0 && "Buffer avail can't be < 0");
    assert(need <= buf->len && "Request for more than possible in the buffer.");

    if(IOBuf_closed(buf)) {
        if(buf->avail > 0) {
            *out_len = buf->avail;
        } else {
            *out_len = 0;
            return NULL;
        }
    } else if(buf->avail < need) {
        if(buf->cur > 0 && IOBuf_compact_needed(buf, need)) {
            IOBuf_compact(buf);
        }
        rc = buf->recv(buf, IOBuf_read_point(buf), IOBuf_remaining(buf));

        if(rc <= 0) {
            debug("Socket was closed, will return only what's available: %d", buf->avail);
            buf->closed = 1;
        } else {
            buf->avail = buf->avail + rc;
        }

        if(buf->avail < need) {
            // less than expected
            *out_len = buf->avail;
        } else {
            // more than expected
            *out_len = need;
        }
    } else if(buf->avail >= need) {
        *out_len = need;
    } else {
        sentinel("Invalid branch processing buffer, Tell Zed.");
    }

    return IOBuf_start(buf);

error:
    return NULL;
}
Exemplo n.º 2
0
char *test_IOBuf_read_operations() 
{
    char *data = NULL;
    int avail = 0;
    Connection *conn = fake_conn("/dev/zero", O_RDONLY);
    mu_assert(conn != NULL, "Failed to make fake /dev/zero connection.");
    IOBuf *buf = conn->iob;

    IOBuf_resize(buf, 31);
    mu_assert(buf->len == 31, "Wrong size after resize.");

    data = IOBuf_start(buf);
    avail = IOBuf_avail(buf);
    mu_assert(data != NULL, "Didn't get a data response on begin.");
    mu_assert(data == buf->buf, "Begin on fresh iobuf should be at the beginning.");
    mu_assert(avail == 0, "Should not have anything available yet.");

    data = IOBuf_read(buf, 10, &avail);
    mu_assert(data != NULL, "Should get something always.");
    mu_assert(data == IOBuf_start(buf), "First read should work from start.");
    mu_assert(data == buf->buf, "First read should be at start of internal buf.");
    mu_assert(avail == 10, "Should get 10 bytes.");

    // check compacting
    mu_assert(!IOBuf_compact_needed(buf, 10), "Should not need compacting for 10.");
    mu_assert(IOBuf_compact_needed(buf, 100), "SHOULD need compacting for 100.");

    mu_assert(IOBuf_read_commit(buf, 10) != -1, "Failed to commit.");

    data = IOBuf_start(buf);
    avail = IOBuf_avail(buf);
    mu_assert(data != NULL, "Didn't get a data response on begin.");
    mu_assert(data != buf->buf, "Later reads should not be at the start.");
    mu_assert(avail == 21, "Should have 21 bytes available in the buf already.");

    data = IOBuf_read(buf, 10, &avail);
    mu_assert(data != NULL, "Should get something always.");
    mu_assert(avail == 10, "Should get 10 bytes.");

    mu_assert(IOBuf_read_commit(buf, 10) != -1, "Finaly commit failed.");


    data = IOBuf_start(buf);
    avail = IOBuf_avail(buf);
    mu_assert(data != NULL, "Didn't get a data response on begin.");
    mu_assert(data != buf->buf, "Later reads should not be at the start.");
    mu_assert(avail == 11, "Should have 11 bytes available in the buf already.");

    // now test two reads, one that fits one that doesn't then commit
    // remember this doesn't *return* anything, just a pointer to the start
    data = IOBuf_read(buf, 5, &avail);
    mu_assert(data != NULL, "Should get something always.");
    mu_assert(avail == 5, "Should get 10 bytes.");

    // ok we didn't want 5 we want 20, so this will cause a compact
    data = IOBuf_read(buf, 20, &avail);
    mu_assert(data != NULL, "Should get something always.");
    mu_assert(avail == 20, "Should get 10 bytes.");

    mu_assert(IOBuf_read_commit(buf, 21) != -1, "Final commit failed.");
    debug("We've got %d avail after the last read.", buf->avail);
    mu_assert(buf->avail == 10, "Should have 11 still in the queue.");

    data = IOBuf_read_all(buf, 30, 1);
    mu_assert(data != NULL, "Failed to read all.");
    mu_assert(buf->avail == 1, "Should have 1 in the queue.");

    data = IOBuf_read_some(buf, &avail);
    mu_assert(data != NULL, "Failed to read some.");
    mu_assert(buf->avail == 31, "Should be full.");
    mu_assert(avail == 31, "And we should get the full amount.");

    fake_conn_close(conn);
    return NULL;
}