Commit 94777c9c authored by Matt Caswell's avatar Matt Caswell
Browse files

Implement read pipeline support in libssl



Read pipelining is controlled in a slightly different way than with write
pipelining. While reading we are constrained by the number of records that
the peer (and the network) can provide to us in one go. The more records
we can get in one go the more opportunity we have to parallelise the
processing.

There are two parameters that affect this:
* The number of pipelines that we are willing to process in one go. This is
controlled by max_pipelines (as for write pipelining)
* The size of our read buffer. A subsequent commit will provide an API for
adjusting the size of the buffer.

Another requirement for this to work is that "read_ahead" must be set. The
read_ahead parameter will attempt to read as much data into our read buffer
as the network can provide. Without this set, data is read into the read
buffer on demand. Setting the max_pipelines parameter to a value greater
than 1 will automatically also turn read_ahead on.

Finally, the read pipelining as currently implemented will only parallelise
the processing of application data records. This would only make a
difference for renegotiation so is unlikely to have a significant impact.

Reviewed-by: default avatarTim Hudson <tjh@openssl.org>
parent 2f2c9caa
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -355,7 +355,7 @@ int dtls1_process_buffered_records(SSL *s)
            if (!dtls1_process_record(s))
                return (0);
            if (dtls1_buffer_record(s, &(s->rlayer.d->processed_rcds),
                SSL3_RECORD_get_seq_num(&s->rlayer.rrec)) < 0)
                SSL3_RECORD_get_seq_num(s->rlayer.rrec)) < 0)
                return -1;
        }
    }
@@ -464,7 +464,7 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
     * s->s3->rrec.off,     - offset into 'data' for next read
     * s->s3->rrec.length,  - number of bytes.
     */
    rr = &s->rlayer.rrec;
    rr = s->rlayer.rrec;

    /*
     * We are not handshaking and have no data yet, so process data buffered
+93 −46
Original line number Diff line number Diff line
@@ -135,8 +135,8 @@
void RECORD_LAYER_init(RECORD_LAYER *rl, SSL *s)
{
    rl->s = s;
    SSL3_RECORD_clear(&rl->rrec);
    SSL3_RECORD_clear(&rl->wrec);
    SSL3_RECORD_clear(rl->rrec, SSL_MAX_PIPELINES);
    SSL3_RECORD_clear(&rl->wrec, 1);
}

void RECORD_LAYER_clear(RECORD_LAYER *rl)
@@ -166,8 +166,8 @@ void RECORD_LAYER_clear(RECORD_LAYER *rl)
    for(pipes = 0; pipes < rl->numwpipes; pipes++)
        SSL3_BUFFER_clear(&rl->wbuf[pipes]);
    rl->numwpipes = 0;
    SSL3_RECORD_clear(&rl->rrec);
    SSL3_RECORD_clear(&rl->wrec);
    SSL3_RECORD_clear(rl->rrec, SSL_MAX_PIPELINES);
    SSL3_RECORD_clear(&rl->wrec, 1);

    RECORD_LAYER_reset_read_sequence(rl);
    RECORD_LAYER_reset_write_sequence(rl);
@@ -182,7 +182,8 @@ void RECORD_LAYER_release(RECORD_LAYER *rl)
        ssl3_release_read_buffer(rl->s);
    if (rl->numwpipes > 0)
        ssl3_release_write_buffer(rl->s);
    SSL3_RECORD_release(&rl->rrec);
    /* TODO: Check why there is no release of wrec here?? */
    SSL3_RECORD_release(rl->rrec, SSL_MAX_PIPELINES);
}

int RECORD_LAYER_read_pending(RECORD_LAYER *rl)
@@ -224,16 +225,25 @@ void RECORD_LAYER_reset_write_sequence(RECORD_LAYER *rl)

int RECORD_LAYER_setup_comp_buffer(RECORD_LAYER *rl)
{
    return SSL3_RECORD_setup(&(rl)->rrec);
    return SSL3_RECORD_setup((rl)->rrec, SSL_MAX_PIPELINES);
}

int ssl3_pending(const SSL *s)
{
    unsigned int i;
    int num = 0;

    if (s->rlayer.rstate == SSL_ST_READ_BODY)
        return 0;

    return (SSL3_RECORD_get_type(&s->rlayer.rrec) == SSL3_RT_APPLICATION_DATA)
           ? SSL3_RECORD_get_length(&s->rlayer.rrec) : 0;
    for (i = 0; i < RECORD_LAYER_get_numrpipes(&s->rlayer); i++) {
        if (SSL3_RECORD_get_type(&s->rlayer.rrec[i])
                != SSL3_RT_APPLICATION_DATA)
            return 0;
        num += SSL3_RECORD_get_length(&s->rlayer.rrec[i]);
    }

    return num;
}

const char *SSL_rstate_string_long(const SSL *s)
@@ -278,7 +288,7 @@ const char *SSL_rstate_string(const SSL *s)
    return (str);
}

int ssl3_read_n(SSL *s, int n, int max, int extend)
int ssl3_read_n(SSL *s, int n, int max, int extend, int clearold)
{
    /*
     * If extend == 0, obtain new n-byte packet; if extend == 1, increase
@@ -286,6 +296,8 @@ int ssl3_read_n(SSL *s, int n, int max, int extend)
     * s->s3->rbuf.buf specified by s->packet and s->packet_length. (If
     * s->rlayer.read_ahead is set, 'max' bytes may be stored in rbuf [plus
     * s->packet_length bytes if extend == 1].)
     * if clearold == 1, move the packet to the start of the buffer; if
     * clearold == 0 then leave any old packets where they were
     */
    int i, len, left;
    size_t align = 0;
@@ -362,7 +374,7 @@ int ssl3_read_n(SSL *s, int n, int max, int extend)
     * Move any available bytes to front of buffer: 'len' bytes already
     * pointed to by 'packet', 'left' extra ones at the end
     */
    if (s->rlayer.packet != pkt) {     /* len > 0 */
    if (s->rlayer.packet != pkt && clearold == 1) {     /* len > 0 */
        memmove(pkt, s->rlayer.packet, len + left);
        s->rlayer.packet = pkt;
        rb->offset = len + align;
@@ -1071,11 +1083,14 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
                    int len, int peek)
{
    int al, i, j, ret;
    unsigned int n;
    unsigned int n, curr_rec, num_recs, read_bytes;
    SSL3_RECORD *rr;
    SSL3_BUFFER *rbuf;
    void (*cb) (const SSL *ssl, int type2, int val) = NULL;

    if (!SSL3_BUFFER_is_initialised(&s->rlayer.rbuf)) {
    rbuf = &s->rlayer.rbuf;

    if (!SSL3_BUFFER_is_initialised(rbuf)) {
        /* Not initialized yet */
        if (!ssl3_setup_read_buffer(s))
            return (-1);
@@ -1132,20 +1147,40 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
    s->rwstate = SSL_NOTHING;

    /*-
     * s->s3->rrec.type         - is the type of record
     * s->s3->rrec.data,    - data
     * s->s3->rrec.off,     - offset into 'data' for next read
     * s->s3->rrec.length,  - number of bytes.
     * For each record 'i' up to |num_recs]
     * rr[i].type     - is the type of record
     * rr[i].data,    - data
     * rr[i].off,     - offset into 'data' for next read
     * rr[i].length,  - number of bytes.
     */
    rr = &s->rlayer.rrec;
    rr = s->rlayer.rrec;
    num_recs = RECORD_LAYER_get_numrpipes(&s->rlayer);

    /* get new packet if necessary */
    if ((SSL3_RECORD_get_length(rr) == 0)
            || (s->rlayer.rstate == SSL_ST_READ_BODY)) {
    do {
        /* get new records if necessary */
        if (num_recs == 0) {
            ret = ssl3_get_record(s);
            if (ret <= 0)
                return (ret);
            num_recs = RECORD_LAYER_get_numrpipes(&s->rlayer);
            if (num_recs == 0) {
                /* Shouldn't happen */
                al = SSL_AD_INTERNAL_ERROR;
                SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR);
                goto f_err;
            }
        }
        /* Skip over any records we have already used or are zero in length */
        for (curr_rec = 0;
             curr_rec < num_recs && SSL3_RECORD_get_length(&rr[curr_rec]) == 0;
             curr_rec++);
        if (curr_rec == num_recs) {
            RECORD_LAYER_set_numrpipes(&s->rlayer, 0);
            num_recs = 0;
            curr_rec = 0;
        }
    } while (num_recs == 0);
    rr = &rr[curr_rec];

    /* we now have a packet which can be read and processed */

@@ -1200,24 +1235,36 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
        if (len <= 0)
            return (len);

        if ((unsigned int)len > SSL3_RECORD_get_length(rr))
        read_bytes = 0;
        do {
            if ((unsigned int)len - read_bytes > SSL3_RECORD_get_length(rr))
                n = SSL3_RECORD_get_length(rr);
            else
            n = (unsigned int)len;
                n = (unsigned int)len - read_bytes;

            memcpy(buf, &(rr->data[rr->off]), n);
            buf += n;
            if (!peek) {
                SSL3_RECORD_add_length(rr, -n);
                SSL3_RECORD_add_off(rr, n);
                if (SSL3_RECORD_get_length(rr) == 0) {
                    s->rlayer.rstate = SSL_ST_READ_HEADER;
                    SSL3_RECORD_set_off(rr, 0);
                if (s->mode & SSL_MODE_RELEASE_BUFFERS
                    && SSL3_BUFFER_get_left(&s->rlayer.rbuf) == 0)
                    ssl3_release_read_buffer(s);
                }
            }
        return (n);
            if (SSL3_RECORD_get_length(rr) == 0
                || (peek && n == SSL3_RECORD_get_length(rr))) {
                curr_rec++;
                rr++;
            }
            read_bytes += n;
        } while (type == SSL3_RT_APPLICATION_DATA && curr_rec < num_recs
                 && read_bytes < (unsigned int)len);
        if (!peek && curr_rec == num_recs
                && (s->mode & SSL_MODE_RELEASE_BUFFERS)
                && SSL3_BUFFER_get_left(rbuf) == 0)
            ssl3_release_read_buffer(s);
        return read_bytes;
    }

    /*
@@ -1339,7 +1386,7 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
                }

                if (!(s->mode & SSL_MODE_AUTO_RETRY)) {
                    if (SSL3_BUFFER_get_left(&s->rlayer.rbuf) == 0) {
                    if (SSL3_BUFFER_get_left(rbuf) == 0) {
                        /* no read-ahead left? */
                        BIO *bio;
                        /*
@@ -1477,7 +1524,7 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
        }

        if (!(s->mode & SSL_MODE_AUTO_RETRY)) {
            if (SSL3_BUFFER_get_left(&s->rlayer.rbuf) == 0) {
            if (SSL3_BUFFER_get_left(rbuf) == 0) {
                /* no read-ahead left? */
                BIO *bio;
                /*
@@ -1561,7 +1608,7 @@ void ssl3_record_sequence_update(unsigned char *seq)
 */
int RECORD_LAYER_is_sslv2_record(RECORD_LAYER *rl)
{
    return SSL3_RECORD_is_sslv2_record(&rl->rrec);
    return SSL3_RECORD_is_sslv2_record(&rl->rrec[0]);
}

/*
@@ -1569,5 +1616,5 @@ int RECORD_LAYER_is_sslv2_record(RECORD_LAYER *rl)
 */
unsigned int RECORD_LAYER_get_rrec_length(RECORD_LAYER *rl)
{
    return SSL3_RECORD_get_length(&rl->rrec);
    return SSL3_RECORD_get_length(&rl->rrec[0]);
}
+4 −1
Original line number Diff line number Diff line
@@ -253,13 +253,16 @@ typedef struct record_layer_st {
    /* where we are when reading */
    int rstate;

    /* How many pipelines can be used to read data */
    unsigned int numrpipes;
    /* How many pipelines can be used to write data */
    unsigned int numwpipes;
    /* read IO goes into here */
    SSL3_BUFFER rbuf;
    /* write IO goes into here */
    SSL3_BUFFER wbuf[SSL_MAX_PIPELINES];
    /* each decoded record goes in here */
    SSL3_RECORD rrec;
    SSL3_RECORD rrec[SSL_MAX_PIPELINES];
    /* goes out from here */
    SSL3_RECORD wrec;

+8 −6
Original line number Diff line number Diff line
@@ -120,7 +120,7 @@

#define RECORD_LAYER_get_rbuf(rl)               (&(rl)->rbuf)
#define RECORD_LAYER_get_wbuf(rl)               ((rl)->wbuf)
#define RECORD_LAYER_get_rrec(rl)               (&(rl)->rrec)
#define RECORD_LAYER_get_rrec(rl)               ((rl)->rrec)
#define RECORD_LAYER_get_wrec(rl)               (&(rl)->wrec)
#define RECORD_LAYER_set_packet(rl, p)          ((rl)->packet = (p))
#define RECORD_LAYER_reset_packet_length(rl)    ((rl)->packet_length = 0)
@@ -128,9 +128,11 @@
#define RECORD_LAYER_set_rstate(rl, st)         ((rl)->rstate = (st))
#define RECORD_LAYER_get_read_sequence(rl)      ((rl)->read_sequence)
#define RECORD_LAYER_get_write_sequence(rl)     ((rl)->write_sequence)
#define RECORD_LAYER_get_numrpipes(rl)          ((rl)->numrpipes)
#define RECORD_LAYER_set_numrpipes(rl, n)       ((rl)->numrpipes = (n))
#define DTLS_RECORD_LAYER_get_r_epoch(rl)       ((rl)->d->r_epoch)

__owur int ssl3_read_n(SSL *s, int n, int max, int extend);
__owur int ssl3_read_n(SSL *s, int n, int max, int extend, int clearold);

void RECORD_LAYER_set_write_sequence(RECORD_LAYER *rl, const unsigned char *ws);
DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr,
@@ -189,13 +191,13 @@ int ssl3_release_write_buffer(SSL *s);
#define SSL3_RECORD_is_sslv2_record(r) \
            ((r)->rec_version == SSL2_VERSION)

void SSL3_RECORD_clear(SSL3_RECORD *r);
void SSL3_RECORD_release(SSL3_RECORD *r);
int SSL3_RECORD_setup(SSL3_RECORD *r);
void SSL3_RECORD_clear(SSL3_RECORD *r, unsigned int num_recs);
void SSL3_RECORD_release(SSL3_RECORD *r, unsigned int num_recs);
int SSL3_RECORD_setup(SSL3_RECORD *r, unsigned int num_recs);
void SSL3_RECORD_set_seq_num(SSL3_RECORD *r, const unsigned char *seq_num);
int ssl3_get_record(SSL *s);
__owur int ssl3_do_compress(SSL *ssl, SSL3_RECORD *wr);
__owur int ssl3_do_uncompress(SSL *ssl);
__owur int ssl3_do_uncompress(SSL *ssl, SSL3_RECORD *rr);
void ssl3_cbc_copy_mac(unsigned char *out,
                       const SSL3_RECORD *rec, unsigned md_size);
__owur int ssl3_cbc_remove_padding(SSL3_RECORD *rec,
+361 −257

File changed.

Preview size limit exceeded, changes collapsed.

Loading