Implement read pipeline support in libssl
authorMatt Caswell <matt@openssl.org>
Tue, 12 Jan 2016 14:52:35 +0000 (14:52 +0000)
committerMatt Caswell <matt@openssl.org>
Mon, 7 Mar 2016 21:39:27 +0000 (21:39 +0000)
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: Tim Hudson <tjh@openssl.org>
ssl/record/rec_layer_d1.c
ssl/record/rec_layer_s3.c
ssl/record/record.h
ssl/record/record_locl.h
ssl/record/ssl3_record.c
ssl/ssl_lib.c

index cd033e008f1fbd2f8a540993ed9f3d4f9a3eec70..86b65854fcfa16ce9c256437d3ce28ba18037d5e 100644 (file)
@@ -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
index 3a232e5807f5bd8b5f53afbea81535e355b171c2..1aceed3aa57931d8d801b2819dd26e20eca40d8f 100644 (file)
 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;
-
-    /* get new packet if necessary */
-    if ((SSL3_RECORD_get_length(rr) == 0)
-            || (s->rlayer.rstate == SSL_ST_READ_BODY)) {
-        ret = ssl3_get_record(s);
-        if (ret <= 0)
-            return (ret);
-    }
+    rr = s->rlayer.rrec;
+    num_recs = RECORD_LAYER_get_numrpipes(&s->rlayer);
+
+    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))
-            n = SSL3_RECORD_get_length(rr);
-        else
-            n = (unsigned int)len;
-
-        memcpy(buf, &(rr->data[rr->off]), 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);
+        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 - 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);
+                }
             }
-        }
-        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]);
 }
index 6105dedd44cef435855c00774119a8d57e8006e5..bf3ffa3cfda41b0d29babc03ded8bfebe1abb11d 100644 (file)
@@ -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;
 
index f44cda16e5bebc69c7f774220d3ed862ae011382..8239549bebdf0e1b91437011654943face4edb21 100644 (file)
 
 #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)
 #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,
index ad19621b11349ab878e3d85e83d6bc9996a7e43c..33122626ec2114947fc5b47056cede73d4fdc206 100644 (file)
@@ -134,27 +134,44 @@ static const unsigned char ssl3_pad_2[48] = {
 /*
  * Clear the contents of an SSL3_RECORD but retain any memory allocated
  */
-void SSL3_RECORD_clear(SSL3_RECORD *r)
+void SSL3_RECORD_clear(SSL3_RECORD *r, unsigned int num_recs)
 {
-    unsigned char *comp = r->comp;
+    unsigned char *comp;
+    unsigned int i;
 
-    memset(r, 0, sizeof(*r));
-    r->comp = comp;
+    for (i = 0; i < num_recs; i++) {
+        comp = r[i].comp;
+
+        memset(&r[i], 0, sizeof(*r));
+        r[i].comp = comp;
+    }
 }
 
-void SSL3_RECORD_release(SSL3_RECORD *r)
+void SSL3_RECORD_release(SSL3_RECORD *r, unsigned int num_recs)
 {
-    OPENSSL_free(r->comp);
-    r->comp = NULL;
+    unsigned int i;
+
+    for (i = 0; i < num_recs; i++) {
+        OPENSSL_free(r[i].comp);
+        r[i].comp = NULL;
+    }
 }
 
-int SSL3_RECORD_setup(SSL3_RECORD *r)
+int SSL3_RECORD_setup(SSL3_RECORD *r, unsigned int num_recs)
 {
-    if (r->comp == NULL)
-        r->comp = (unsigned char *)
-            OPENSSL_malloc(SSL3_RT_MAX_ENCRYPTED_LENGTH);
-    if (r->comp == NULL)
-        return 0;
+    unsigned int i;
+
+    for (i = 0; i < num_recs; i++) {
+        if (r[i].comp == NULL)
+            r[i].comp = (unsigned char *)
+                OPENSSL_malloc(SSL3_RT_MAX_ENCRYPTED_LENGTH);
+        if (r[i].comp == NULL) {
+            if (i > 0)
+                SSL3_RECORD_release(r, i);
+            return 0;
+        }
+    }
+
     return 1;
 }
 
@@ -163,6 +180,46 @@ void SSL3_RECORD_set_seq_num(SSL3_RECORD *r, const unsigned char *seq_num)
     memcpy(r->seq_num, seq_num, SEQ_NUM_SIZE);
 }
 
+
+/*
+ * Peeks ahead into "read_ahead" data to see if we have a whole record waiting
+ * for us in the buffer.
+ */
+static int have_whole_app_data_record_waiting(SSL *s)
+{
+    SSL3_BUFFER *rbuf;
+    int left, len;
+    unsigned char *p;
+
+    rbuf = RECORD_LAYER_get_rbuf(&s->rlayer);
+
+    p = SSL3_BUFFER_get_buf(rbuf);
+    if (p == NULL)
+        return 0;
+
+    left = SSL3_BUFFER_get_left(rbuf);
+
+    if (left < SSL3_RT_HEADER_LENGTH)
+        return 0;
+
+    p += SSL3_BUFFER_get_offset(rbuf);
+
+    /*
+     * We only check the type and record length, we will sanity check version
+     * etc later
+     */
+    if (*p != SSL3_RT_APPLICATION_DATA)
+        return 0;
+
+    p += 3;
+    n2s(p, len);
+
+    if (left < SSL3_RT_HEADER_LENGTH + len)
+        return 0;
+
+    return 1;
+}
+
 /*
  * MAX_EMPTY_RECORDS defines the number of consecutive, empty records that
  * will be processed per call to ssl3_get_record. Without this limit an
@@ -173,13 +230,16 @@ void SSL3_RECORD_set_seq_num(SSL3_RECORD *r, const unsigned char *seq_num)
 
 #define SSL2_RT_HEADER_LENGTH   2
 /*-
- * Call this to get a new input record.
+ * Call this to get new input records.
  * It will return <= 0 if more data is needed, normally due to an error
  * or non-blocking IO.
- * When it finishes, one packet has been decoded and can be found in
- * ssl->s3->rrec.type    - is the type of record
- * ssl->s3->rrec.data,   - data
- * ssl->s3->rrec.length, - number of bytes
+ * When it finishes, |numrpipes| records have been decoded. For each record 'i':
+ * rr[i].type    - is the type of record
+ * rr[i].data,   - data
+ * rr[i].length, - number of bytes
+ * Multiple records will only be returned if the record types are all
+ * SSL3_RT_APPLICATION_DATA. The number of records returned will always be <=
+ * |max_pipelines|
  */
 /* used only by ssl3_read_bytes */
 int ssl3_get_record(SSL *s)
@@ -187,177 +247,205 @@ int ssl3_get_record(SSL *s)
     int ssl_major, ssl_minor, al;
     int enc_err, n, i, ret = -1;
     SSL3_RECORD *rr;
+    SSL3_BUFFER *rbuf;
     SSL_SESSION *sess;
     unsigned char *p;
     unsigned char md[EVP_MAX_MD_SIZE];
     short version;
     unsigned mac_size;
-    unsigned empty_record_count = 0;
+    unsigned empty_record_count = 0, curr_empty = 0;
+    unsigned int num_recs = 0;
+    unsigned int max_recs;
+    unsigned int j;
 
     rr = RECORD_LAYER_get_rrec(&s->rlayer);
+    rbuf = RECORD_LAYER_get_rbuf(&s->rlayer);
+    max_recs = s->max_pipelines;
+    if (max_recs == 0)
+        max_recs = 1;
     sess = s->session;
 
  again:
-    /* check if we have the header */
-    if ((RECORD_LAYER_get_rstate(&s->rlayer) != SSL_ST_READ_BODY) ||
-        (RECORD_LAYER_get_packet_length(&s->rlayer) < SSL3_RT_HEADER_LENGTH)) {
-        n = ssl3_read_n(s, SSL3_RT_HEADER_LENGTH,
-            SSL3_BUFFER_get_len(&s->rlayer.rbuf), 0);
-        if (n <= 0)
-            return (n);         /* error or non-blocking */
-        RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_BODY);
+    do {
+        /* check if we have the header */
+        if ((RECORD_LAYER_get_rstate(&s->rlayer) != SSL_ST_READ_BODY) ||
+            (RECORD_LAYER_get_packet_length(&s->rlayer)
+             < SSL3_RT_HEADER_LENGTH)) {
+            n = ssl3_read_n(s, SSL3_RT_HEADER_LENGTH,
+                SSL3_BUFFER_get_len(rbuf), 0, num_recs == 0 ? 1 : 0);
+            if (n <= 0)
+                return (n);         /* error or non-blocking */
+            RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_BODY);
+
+            p = RECORD_LAYER_get_packet(&s->rlayer);
 
-        p = RECORD_LAYER_get_packet(&s->rlayer);
-
-        /*
-         * Check whether this is a regular record or an SSLv2 style record. The
-         * latter is only used in an initial ClientHello for old clients. We
-         * check s->read_hash and s->enc_read_ctx to ensure this does not apply
-         * during renegotiation
-         */
-        if (s->first_packet && s->server && !s->read_hash && !s->enc_read_ctx
-                && (p[0] & 0x80) && (p[2] == SSL2_MT_CLIENT_HELLO)) {
-            /* SSLv2 style record */
-            rr->type = SSL3_RT_HANDSHAKE;
-            rr->rec_version = SSL2_VERSION;
-
-            rr->length = ((p[0] & 0x7f) << 8) | p[1];
-
-            if (rr->length > SSL3_BUFFER_get_len(&s->rlayer.rbuf)
-                                    - SSL2_RT_HEADER_LENGTH) {
-                al = SSL_AD_RECORD_OVERFLOW;
-                SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_PACKET_LENGTH_TOO_LONG);
-                goto f_err;
-            }
+            /*
+             * Check whether this is a regular record or an SSLv2 style record.
+             * The latter is only used in an initial ClientHello for old
+             * clients. We check s->read_hash and s->enc_read_ctx to ensure this
+             * does not apply during renegotiation
+             */
+            if (s->first_packet && s->server && !s->read_hash
+                    && !s->enc_read_ctx
+                    && (p[0] & 0x80) && (p[2] == SSL2_MT_CLIENT_HELLO)) {
+                /* SSLv2 style record */
+                rr[num_recs].type = SSL3_RT_HANDSHAKE;
+                rr[num_recs].rec_version = SSL2_VERSION;
+
+                rr[num_recs].length = ((p[0] & 0x7f) << 8) | p[1];
+
+                if (rr[num_recs].length > SSL3_BUFFER_get_len(&rbuf[num_recs])
+                                 - SSL2_RT_HEADER_LENGTH) {
+                    al = SSL_AD_RECORD_OVERFLOW;
+                    SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_PACKET_LENGTH_TOO_LONG);
+                    goto f_err;
+                }
 
-            if (rr->length < MIN_SSL2_RECORD_LEN) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_LENGTH_TOO_SHORT);
-                goto f_err;
-            }
-        } else {
-            /* SSLv3+ style record */
-            if (s->msg_callback)
-                s->msg_callback(0, 0, SSL3_RT_HEADER, p, 5, s,
-                                s->msg_callback_arg);
-
-            /* Pull apart the header into the SSL3_RECORD */
-            rr->type = *(p++);
-            ssl_major = *(p++);
-            ssl_minor = *(p++);
-            version = (ssl_major << 8) | ssl_minor;
-            rr->rec_version = version;
-            n2s(p, rr->length);
-
-            /* Lets check version */
-            if (!s->first_packet && version != s->version) {
-                SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_WRONG_VERSION_NUMBER);
-                if ((s->version & 0xFF00) == (version & 0xFF00)
-                    && !s->enc_write_ctx && !s->write_hash) {
-                    if (rr->type == SSL3_RT_ALERT) {
+                if (rr[num_recs].length < MIN_SSL2_RECORD_LEN) {
+                    al = SSL_AD_HANDSHAKE_FAILURE;
+                    SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_LENGTH_TOO_SHORT);
+                    goto f_err;
+                }
+            } else {
+                /* SSLv3+ style record */
+                if (s->msg_callback)
+                    s->msg_callback(0, 0, SSL3_RT_HEADER, p, 5, s,
+                                    s->msg_callback_arg);
+
+                /* Pull apart the header into the SSL3_RECORD */
+                rr[num_recs].type = *(p++);
+                ssl_major = *(p++);
+                ssl_minor = *(p++);
+                version = (ssl_major << 8) | ssl_minor;
+                rr[num_recs].rec_version = version;
+                n2s(p, rr[num_recs].length);
+
+                /* Lets check version */
+                if (!s->first_packet && version != s->version) {
+                    SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_WRONG_VERSION_NUMBER);
+                    if ((s->version & 0xFF00) == (version & 0xFF00)
+                        && !s->enc_write_ctx && !s->write_hash) {
+                        if (rr->type == SSL3_RT_ALERT) {
+                            /*
+                             * The record is using an incorrect version number,
+                             * but what we've got appears to be an alert. We
+                             * haven't read the body yet to check whether its a
+                             * fatal or not - but chances are it is. We probably
+                             * shouldn't send a fatal alert back. We'll just
+                             * end.
+                             */
+                             goto err;
+                        }
                         /*
-                         * The record is using an incorrect version number, but
-                         * what we've got appears to be an alert. We haven't
-                         * read the body yet to check whether its a fatal or
-                         * not - but chances are it is. We probably shouldn't
-                         * send a fatal alert back. We'll just end.
+                         * Send back error using their minor version number :-)
                          */
-                         goto err;
+                        s->version = (unsigned short)version;
                     }
-                    /*
-                     * Send back error using their minor version number :-)
-                     */
-                    s->version = (unsigned short)version;
+                    al = SSL_AD_PROTOCOL_VERSION;
+                    goto f_err;
                 }
-                al = SSL_AD_PROTOCOL_VERSION;
-                goto f_err;
-            }
 
-            if ((version >> 8) != SSL3_VERSION_MAJOR) {
-                if (s->first_packet) {
-                    /* Go back to start of packet, look at the five bytes
-                     * that we have. */
-                    p = RECORD_LAYER_get_packet(&s->rlayer);
-                    if (strncmp((char *)p, "GET ", 4) == 0 ||
-                        strncmp((char *)p, "POST ", 5) == 0 ||
-                        strncmp((char *)p, "HEAD ", 5) == 0 ||
-                        strncmp((char *)p, "PUT ", 4) == 0) {
-                        SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_HTTP_REQUEST);
-                        goto err;
-                    } else if (strncmp((char *)p, "CONNE", 5) == 0) {
-                        SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_HTTPS_PROXY_REQUEST);
-                        goto err;
+                if ((version >> 8) != SSL3_VERSION_MAJOR) {
+                    if (s->first_packet) {
+                        /* Go back to start of packet, look at the five bytes
+                         * that we have. */
+                        p = RECORD_LAYER_get_packet(&s->rlayer);
+                        if (strncmp((char *)p, "GET ", 4) == 0 ||
+                            strncmp((char *)p, "POST ", 5) == 0 ||
+                            strncmp((char *)p, "HEAD ", 5) == 0 ||
+                            strncmp((char *)p, "PUT ", 4) == 0) {
+                            SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_HTTP_REQUEST);
+                            goto err;
+                        } else if (strncmp((char *)p, "CONNE", 5) == 0) {
+                            SSLerr(SSL_F_SSL3_GET_RECORD,
+                                   SSL_R_HTTPS_PROXY_REQUEST);
+                            goto err;
+                        }
                     }
+                    SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_WRONG_VERSION_NUMBER);
+                    goto err;
                 }
-                SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_WRONG_VERSION_NUMBER);
-                goto err;
-            }
 
-            if (rr->length >
-                    SSL3_BUFFER_get_len(&s->rlayer.rbuf)
-                    - SSL3_RT_HEADER_LENGTH) {
-                al = SSL_AD_RECORD_OVERFLOW;
-                SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_PACKET_LENGTH_TOO_LONG);
-                goto f_err;
+                if (rr[num_recs].length >
+                        SSL3_BUFFER_get_len(rbuf) - SSL3_RT_HEADER_LENGTH) {
+                    al = SSL_AD_RECORD_OVERFLOW;
+                    SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_PACKET_LENGTH_TOO_LONG);
+                    goto f_err;
+                }
             }
+
+            /* now s->rlayer.rstate == SSL_ST_READ_BODY */
         }
 
-        /* now s->rlayer.rstate == SSL_ST_READ_BODY */
-    }
+        /*
+         * s->rlayer.rstate == SSL_ST_READ_BODY, get and decode the data.
+         * Calculate how much more data we need to read for the rest of the
+         * record
+         */
+        if (rr[num_recs].rec_version == SSL2_VERSION) {
+            i = rr[num_recs].length + SSL2_RT_HEADER_LENGTH
+                - SSL3_RT_HEADER_LENGTH;
+        } else {
+            i = rr[num_recs].length;
+        }
+        if (i > 0) {
+            /* now s->packet_length == SSL3_RT_HEADER_LENGTH */
 
-    /*
-     * s->rlayer.rstate == SSL_ST_READ_BODY, get and decode the data.
-     * Calculate how much more data we need to read for the rest of the record
-     */
-    if (rr->rec_version == SSL2_VERSION) {
-        i = rr->length + SSL2_RT_HEADER_LENGTH - SSL3_RT_HEADER_LENGTH;
-    } else {
-        i = rr->length;
-    }
-    if (i > 0) {
-        /* now s->packet_length == SSL3_RT_HEADER_LENGTH */
+            n = ssl3_read_n(s, i, i, 1, 0);
+            if (n <= 0)
+                return (n);         /* error or non-blocking io */
+        }
 
-        n = ssl3_read_n(s, i, i, 1);
-        if (n <= 0)
-            return (n);         /* error or non-blocking io */
-    }
+        /* set state for later operations */
+        RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_HEADER);
 
-    /* set state for later operations */
-    RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_HEADER);
+        /*
+         * At this point, s->packet_length == SSL3_RT_HEADER_LENGTH + rr->length,
+         * or s->packet_length == SSL2_RT_HEADER_LENGTH + rr->length
+         * and we have that many bytes in s->packet
+         */
+        if(rr[num_recs].rec_version == SSL2_VERSION) {
+            rr[num_recs].input =
+                &(RECORD_LAYER_get_packet(&s->rlayer)[SSL2_RT_HEADER_LENGTH]);
+        } else {
+            rr[num_recs].input =
+                &(RECORD_LAYER_get_packet(&s->rlayer)[SSL3_RT_HEADER_LENGTH]);
+        }
 
-    /*
-     * At this point, s->packet_length == SSL3_RT_HEADER_LENGTH + rr->length,
-     * or s->packet_length == SSL2_RT_HEADER_LENGTH + rr->length
-     * and we have that many bytes in s->packet
-     */
-    if(rr->rec_version == SSL2_VERSION) {
-        rr->input = &(RECORD_LAYER_get_packet(&s->rlayer)[SSL2_RT_HEADER_LENGTH]);
-    } else {
-        rr->input = &(RECORD_LAYER_get_packet(&s->rlayer)[SSL3_RT_HEADER_LENGTH]);
-    }
+        /*
+         * ok, we can now read from 's->packet' data into 'rr' rr->input points
+         * at rr->length bytes, which need to be copied into rr->data by either
+         * the decryption or by the decompression When the data is 'copied' into
+         * the rr->data buffer, rr->input will be pointed at the new buffer
+         */
 
-    /*
-     * ok, we can now read from 's->packet' data into 'rr' rr->input points
-     * at rr->length bytes, which need to be copied into rr->data by either
-     * the decryption or by the decompression When the data is 'copied' into
-     * the rr->data buffer, rr->input will be pointed at the new buffer
-     */
+        /*
+         * We now have - encrypted [ MAC [ compressed [ plain ] ] ] rr->length
+         * bytes of encrypted compressed stuff.
+         */
 
-    /*
-     * We now have - encrypted [ MAC [ compressed [ plain ] ] ] rr->length
-     * bytes of encrypted compressed stuff.
-     */
+        /* check is not needed I believe */
+        if (rr[num_recs].length > SSL3_RT_MAX_ENCRYPTED_LENGTH) {
+            al = SSL_AD_RECORD_OVERFLOW;
+            SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
+            goto f_err;
+        }
+
+        /* decrypt in place in 'rr->input' */
+        rr[num_recs].data = rr[num_recs].input;
+        rr[num_recs].orig_len = rr[num_recs].length;
+        num_recs++;
+
+        /* we have pulled in a full packet so zero things */
+        RECORD_LAYER_reset_packet_length(&s->rlayer);
+    } while (num_recs < max_recs && rr->type == SSL3_RT_APPLICATION_DATA
+             && SSL_USE_EXPLICIT_IV(s)
+             && s->enc_read_ctx != NULL
+             && (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(s->enc_read_ctx))
+                & EVP_CIPH_FLAG_PIPELINE)
+             && have_whole_app_data_record_waiting(s));
 
-    /* check is not needed I believe */
-    if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) {
-        al = SSL_AD_RECORD_OVERFLOW;
-        SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
-        goto f_err;
-    }
 
-    /* decrypt in place in 'rr->input' */
-    rr->data = rr->input;
-    rr->orig_len = rr->length;
     /*
      * If in encrypt-then-mac mode calculate mac from encrypted record. All
      * the details below are public so no timing details can leak.
@@ -366,23 +454,25 @@ int ssl3_get_record(SSL *s)
         unsigned char *mac;
         mac_size = EVP_MD_CTX_size(s->read_hash);
         OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE);
-        if (rr->length < mac_size) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_LENGTH_TOO_SHORT);
-            goto f_err;
-        }
-        rr->length -= mac_size;
-        mac = rr->data + rr->length;
-        i = s->method->ssl3_enc->mac(s, rr, md, 0 /* not send */ );
-        if (i < 0 || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0) {
-            al = SSL_AD_BAD_RECORD_MAC;
-            SSLerr(SSL_F_SSL3_GET_RECORD,
-                   SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
-            goto f_err;
+        for (j = 0; j < num_recs; j++) {
+            if (rr[j].length < mac_size) {
+                al = SSL_AD_DECODE_ERROR;
+                SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_LENGTH_TOO_SHORT);
+                goto f_err;
+            }
+            rr[j].length -= mac_size;
+            mac = rr[j].data + rr[j].length;
+            i = s->method->ssl3_enc->mac(s, &rr[j], md, 0 /* not send */ );
+            if (i < 0 || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0) {
+                al = SSL_AD_BAD_RECORD_MAC;
+                SSLerr(SSL_F_SSL3_GET_RECORD,
+                       SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
+                goto f_err;
+            }
         }
     }
 
-    enc_err = s->method->ssl3_enc->enc(s, rr, 1, 0);
+    enc_err = s->method->ssl3_enc->enc(s, rr, num_recs, 0);
     /*-
      * enc_err is:
      *    0: (in non-constant time) if the record is publically invalid.
@@ -411,50 +501,53 @@ int ssl3_get_record(SSL *s)
         /* s->read_hash != NULL => mac_size != -1 */
         unsigned char *mac = NULL;
         unsigned char mac_tmp[EVP_MAX_MD_SIZE];
+
         mac_size = EVP_MD_CTX_size(s->read_hash);
         OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE);
 
-        /*
-         * orig_len is the length of the record before any padding was
-         * removed. This is public information, as is the MAC in use,
-         * therefore we can safely process the record in a different amount
-         * of time if it's too short to possibly contain a MAC.
-         */
-        if (rr->orig_len < mac_size ||
-            /* CBC records must have a padding length byte too. */
-            (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
-             rr->orig_len < mac_size + 1)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_LENGTH_TOO_SHORT);
-            goto f_err;
-        }
-
-        if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE) {
-            /*
-             * We update the length so that the TLS header bytes can be
-             * constructed correctly but we need to extract the MAC in
-             * constant time from within the record, without leaking the
-             * contents of the padding bytes.
-             */
-            mac = mac_tmp;
-            ssl3_cbc_copy_mac(mac_tmp, rr, mac_size);
-            rr->length -= mac_size;
-        } else {
+        for (j=0; j < num_recs; j++) {
             /*
-             * In this case there's no padding, so |rec->orig_len| equals
-             * |rec->length| and we checked that there's enough bytes for
-             * |mac_size| above.
+             * orig_len is the length of the record before any padding was
+             * removed. This is public information, as is the MAC in use,
+             * therefore we can safely process the record in a different amount
+             * of time if it's too short to possibly contain a MAC.
              */
-            rr->length -= mac_size;
-            mac = &rr->data[rr->length];
-        }
+            if (rr[j].orig_len < mac_size ||
+                /* CBC records must have a padding length byte too. */
+                (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
+                 rr[j].orig_len < mac_size + 1)) {
+                al = SSL_AD_DECODE_ERROR;
+                SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_LENGTH_TOO_SHORT);
+                goto f_err;
+            }
 
-        i = s->method->ssl3_enc->mac(s, rr, md, 0 /* not send */ );
-        if (i < 0 || mac == NULL
-            || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0)
-            enc_err = -1;
-        if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH + mac_size)
-            enc_err = -1;
+            if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE) {
+                /*
+                 * We update the length so that the TLS header bytes can be
+                 * constructed correctly but we need to extract the MAC in
+                 * constant time from within the record, without leaking the
+                 * contents of the padding bytes.
+                 */
+                mac = mac_tmp;
+                ssl3_cbc_copy_mac(mac_tmp, &rr[j], mac_size);
+                rr[j].length -= mac_size;
+            } else {
+                /*
+                 * In this case there's no padding, so |rec->orig_len| equals
+                 * |rec->length| and we checked that there's enough bytes for
+                 * |mac_size| above.
+                 */
+                rr[j].length -= mac_size;
+                mac = &rr[j].data[rr[j].length];
+            }
+
+            i = s->method->ssl3_enc->mac(s, &rr[j], md, 0 /* not send */ );
+            if (i < 0 || mac == NULL
+                || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0)
+                enc_err = -1;
+            if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH + mac_size)
+                enc_err = -1;
+        }
     }
 
     if (enc_err < 0) {
@@ -471,65 +564,68 @@ int ssl3_get_record(SSL *s)
         goto f_err;
     }
 
-    /* r->length is now just compressed */
-    if (s->expand != NULL) {
-        if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH) {
-            al = SSL_AD_RECORD_OVERFLOW;
-            SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_COMPRESSED_LENGTH_TOO_LONG);
-            goto f_err;
+    for (j = 0; j < num_recs; j++) {
+        /* rr[j].length is now just compressed */
+        if (s->expand != NULL) {
+            if (rr[j].length > SSL3_RT_MAX_COMPRESSED_LENGTH) {
+                al = SSL_AD_RECORD_OVERFLOW;
+                SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_COMPRESSED_LENGTH_TOO_LONG);
+                goto f_err;
+            }
+            if (!ssl3_do_uncompress(s, &rr[j])) {
+                al = SSL_AD_DECOMPRESSION_FAILURE;
+                SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_BAD_DECOMPRESSION);
+                goto f_err;
+            }
         }
-        if (!ssl3_do_uncompress(s)) {
-            al = SSL_AD_DECOMPRESSION_FAILURE;
-            SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_BAD_DECOMPRESSION);
+
+        if (rr[j].length > SSL3_RT_MAX_PLAIN_LENGTH) {
+            al = SSL_AD_RECORD_OVERFLOW;
+            SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_DATA_LENGTH_TOO_LONG);
             goto f_err;
         }
-    }
-
-    if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH) {
-        al = SSL_AD_RECORD_OVERFLOW;
-        SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_DATA_LENGTH_TOO_LONG);
-        goto f_err;
-    }
-
-    rr->off = 0;
-    /*-
-     * So at this point the following is true
-     * ssl->s3->rrec.type   is the type of record
-     * ssl->s3->rrec.length == number of bytes in record
-     * ssl->s3->rrec.off    == offset to first valid byte
-     * ssl->s3->rrec.data   == where to take bytes from, increment
-     *                         after use :-).
-     */
 
-    /* we have pulled in a full packet so zero things */
-    RECORD_LAYER_reset_packet_length(&s->rlayer);
+        rr[j].off = 0;
+        /*-
+         * So at this point the following is true
+         * rr[j].type   is the type of record
+         * rr[j].length == number of bytes in record
+         * rr[j].off    == offset to first valid byte
+         * rr[j].data   == where to take bytes from, increment after use :-).
+         */
 
-    /* just read a 0 length packet */
-    if (rr->length == 0) {
-        empty_record_count++;
-        if (empty_record_count > MAX_EMPTY_RECORDS) {
-            al = SSL_AD_UNEXPECTED_MESSAGE;
-            SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_RECORD_TOO_SMALL);
-            goto f_err;
+        /* just read a 0 length packet */
+        if (rr[j].length == 0) {
+            curr_empty++;
+            empty_record_count++;
+            if (empty_record_count > MAX_EMPTY_RECORDS) {
+                al = SSL_AD_UNEXPECTED_MESSAGE;
+                SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_RECORD_TOO_SMALL);
+                goto f_err;
+            }
         }
+    }
+    if (curr_empty == num_recs) {
+        /* We have no data - do it all again */
+        num_recs = 0;
+        curr_empty = 0;
         goto again;
     }
 
-    return (1);
+    RECORD_LAYER_set_numrpipes(&s->rlayer, num_recs);
+    return 1;
 
  f_err:
     ssl3_send_alert(s, SSL3_AL_FATAL, al);
  err:
-    return (ret);
+    return ret;
 }
 
-int ssl3_do_uncompress(SSL *ssl)
+int ssl3_do_uncompress(SSL *ssl, SSL3_RECORD *rr)
 {
 #ifndef OPENSSL_NO_COMP
     int i;
-    SSL3_RECORD *rr;
 
-    rr = RECORD_LAYER_get_rrec(&ssl->rlayer);
     i = COMP_expand_block(ssl->expand, rr->comp,
                           SSL3_RT_MAX_PLAIN_LENGTH, rr->data,
                           (int)rr->length);
@@ -827,11 +923,19 @@ int tls1_enc(SSL *s, SSL3_RECORD *recs, unsigned int numpipes, int send)
         if (!SSL_USE_ETM(s) && EVP_MD_CTX_md(s->read_hash) != NULL)
             mac_size = EVP_MD_CTX_size(s->read_hash);
         if ((bs != 1) && !send) {
-            /* TODO: We only support writing for pipelining at the moment */
-            ret = tls1_cbc_remove_padding(s, recs, bs, mac_size);
+            int tmpret;
+            for (ctr = 0; ctr < numpipes; ctr++) {
+                tmpret = tls1_cbc_remove_padding(s, &recs[ctr], bs, mac_size);
+                if (tmpret == -1)
+                    return -1;
+                ret &= tmpret;
+            }
+        }
+        if (pad && !send) {
+            for (ctr = 0; ctr < numpipes; ctr++) {
+                recs[ctr].length -= pad;
+            }
         }
-        if (pad && !send)
-            recs[0].length -= pad;
     }
     return ret;
 }
@@ -1388,7 +1492,7 @@ int dtls1_process_record(SSL *s)
                    SSL_R_COMPRESSED_LENGTH_TOO_LONG);
             goto f_err;
         }
-        if (!ssl3_do_uncompress(s)) {
+        if (!ssl3_do_uncompress(s, rr)) {
             al = SSL_AD_DECOMPRESSION_FAILURE;
             SSLerr(SSL_F_DTLS1_PROCESS_RECORD, SSL_R_BAD_DECOMPRESSION);
             goto f_err;
@@ -1469,7 +1573,7 @@ int dtls1_get_record(SSL *s)
     if ((RECORD_LAYER_get_rstate(&s->rlayer) != SSL_ST_READ_BODY) ||
         (RECORD_LAYER_get_packet_length(&s->rlayer) < DTLS1_RT_HEADER_LENGTH)) {
         n = ssl3_read_n(s, DTLS1_RT_HEADER_LENGTH,
-            SSL3_BUFFER_get_len(&s->rlayer.rbuf), 0);
+            SSL3_BUFFER_get_len(&s->rlayer.rbuf), 0, 1);
         /* read timeout is handled by dtls1_read_bytes */
         if (n <= 0)
             return (n);         /* error or non-blocking */
@@ -1535,7 +1639,7 @@ int dtls1_get_record(SSL *s)
         RECORD_LAYER_get_packet_length(&s->rlayer) - DTLS1_RT_HEADER_LENGTH) {
         /* now s->packet_length == DTLS1_RT_HEADER_LENGTH */
         i = rr->length;
-        n = ssl3_read_n(s, i, i, 1);
+        n = ssl3_read_n(s, i, i, 1, 1);
         /* this packet contained a partial record, dump it */
         if (n != i) {
             rr->length = 0;
index f27f6ff34c7dd6176380cca3dc51f35d5416aa1f..92734ea937288b29f61824cf7a0d605ef7c4e6d0 100644 (file)
@@ -672,6 +672,8 @@ SSL *SSL_new(SSL_CTX *ctx)
     s->max_send_fragment = ctx->max_send_fragment;
     s->split_send_fragment = ctx->split_send_fragment;
     s->max_pipelines = ctx->max_pipelines;
+    if (s->max_pipelines > 1)
+        RECORD_LAYER_set_read_ahead(&s->rlayer, 1);
 
     CRYPTO_add(&ctx->references, 1, CRYPTO_LOCK_SSL_CTX);
     s->ctx = ctx;
@@ -1694,6 +1696,8 @@ long SSL_ctrl(SSL *s, int cmd, long larg, void *parg)
         if (larg < 1 || larg > SSL_MAX_PIPELINES)
             return 0;
         s->max_pipelines = larg;
+        if (larg > 1)
+            RECORD_LAYER_set_read_ahead(&s->rlayer, 1);
     case SSL_CTRL_GET_RI_SUPPORT:
         if (s->s3)
             return s->s3->send_connection_binding;