Move the pipelining code into the record layer
authorMatt Caswell <matt@openssl.org>
Fri, 9 Sep 2022 14:53:40 +0000 (15:53 +0100)
committerMatt Caswell <matt@openssl.org>
Fri, 23 Sep 2022 13:54:49 +0000 (14:54 +0100)
Reviewed-by: Hugo Landau <hlandau@openssl.org>
Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/19198)

ssl/record/methods/tls_common.c
ssl/record/rec_layer_s3.c

index 6e48bb3a7cf5f04b5c919ce4f4909911ed638d98..38bf142ba635fe8ea4b1c9aae3a560db18dd6f98 100644 (file)
@@ -1450,6 +1450,9 @@ static int tls_is_multiblock_capable(OSSL_RECORD_LAYER *rl, int type,
 size_t tls_get_max_records(OSSL_RECORD_LAYER *rl, int type, size_t len,
                            size_t maxfrag, size_t *preffrag)
 {
+    /* TODO(RECLAYER): Remove me */
+    SSL_CONNECTION *s = rl->cbarg;
+
     if (tls_is_multiblock_capable(rl, type, len, *preffrag)) {
         /* minimize address aliasing conflicts */
         if ((*preffrag & 0xfff) == 0)
@@ -1460,6 +1463,29 @@ size_t tls_get_max_records(OSSL_RECORD_LAYER *rl, int type, size_t len,
 
         return 4;
     }
+
+    /*
+     * TODO(RECLYAER): There is no test for the pipelining code. We should add
+     *                 one.
+     */
+    /*
+     * If we have a pipeline capable cipher, and we have been configured to use
+     * it, then return the preferred number of pipelines.
+     */
+    if (rl->max_pipelines > 0
+            && s->enc_write_ctx != NULL
+            && (EVP_CIPHER_get_flags(EVP_CIPHER_CTX_get0_cipher(s->enc_write_ctx))
+                & EVP_CIPH_FLAG_PIPELINE) != 0
+            && RLAYER_USE_EXPLICIT_IV(rl)) {
+        size_t pipes;
+
+        if (len == 0)
+            return 1;
+        pipes = ((len - 1) / *preffrag) + 1;
+
+        return (pipes < rl->max_pipelines) ? pipes : rl->max_pipelines;
+    }
+
     return 1;
 }
 
index 792b0716d8ca808d9e3543738b3aef9d70caf2d5..0318b07a9fb63dd3fdd37234cfecb5fef9ab2066 100644 (file)
@@ -292,35 +292,6 @@ int ssl3_write_bytes(SSL *ssl, int type, const void *buf_, size_t len,
     max_send_fragment = ssl_get_max_send_fragment(s);
     split_send_fragment = ssl_get_split_send_fragment(s);
 
-    /*
-     * Ask the record layer how it would like to split the amount of data that
-     * we have, and how many of those records it would like in one go.
-     */
-    maxpipes = s->rlayer.wrlmethod->get_max_records(s->rlayer.wrl, type, n,
-                                                    max_send_fragment,
-                                                    &split_send_fragment);
-    /*
-     * If max_pipelines is 0 then this means "undefined" and we default to
-     * whatever the record layer wants to do. Otherwise we use the smallest
-     * value from the number requested by the record layer, and max number
-     * configured by the user.
-     */
-    if (s->max_pipelines > 0 && maxpipes > s->max_pipelines)
-        maxpipes = s->max_pipelines;
-
-    if (maxpipes > SSL_MAX_PIPELINES)
-        maxpipes = SSL_MAX_PIPELINES;
-
-
-#if 0
-    /* TODO(RECLAYER): FIX ME */
-    if (maxpipes == 0
-        || s->enc_write_ctx == NULL
-        || (EVP_CIPHER_get_flags(EVP_CIPHER_CTX_get0_cipher(s->enc_write_ctx))
-            & EVP_CIPH_FLAG_PIPELINE) == 0
-        || !SSL_USE_EXPLICIT_IV(s))
-        maxpipes = 1;
-#endif
     if (max_send_fragment == 0
             || split_send_fragment == 0
             || split_send_fragment > max_send_fragment) {
@@ -346,39 +317,56 @@ int ssl3_write_bytes(SSL *ssl, int type, const void *buf_, size_t len,
 
     for (;;) {
         size_t tmppipelen, remain;
-        size_t numpipes, j, lensofar = 0;
+        size_t j, lensofar = 0;
 
-        if (n == 0)
-            numpipes = 1;
-        else
-            numpipes = ((n - 1) / split_send_fragment) + 1;
-        if (numpipes > maxpipes)
-            numpipes = maxpipes;
+        /*
+        * Ask the record layer how it would like to split the amount of data
+        * that we have, and how many of those records it would like in one go.
+        */
+        maxpipes = s->rlayer.wrlmethod->get_max_records(s->rlayer.wrl, type, n,
+                                                        max_send_fragment,
+                                                        &split_send_fragment);
+        /*
+        * If max_pipelines is 0 then this means "undefined" and we default to
+        * whatever the record layer wants to do. Otherwise we use the smallest
+        * value from the number requested by the record layer, and max number
+        * configured by the user.
+        */
+        if (s->max_pipelines > 0 && maxpipes > s->max_pipelines)
+            maxpipes = s->max_pipelines;
+
+        if (maxpipes > SSL_MAX_PIPELINES)
+            maxpipes = SSL_MAX_PIPELINES;
+
+        if (split_send_fragment > max_send_fragment) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            return -1;
+        }
 
-        if (n / numpipes >= split_send_fragment) {
+        if (n / maxpipes >= split_send_fragment) {
             /*
              * We have enough data to completely fill all available
              * pipelines
              */
-            for (j = 0; j < numpipes; j++) {
+            for (j = 0; j < maxpipes; j++) {
                 tmpls[j].type = type;
                 tmpls[j].version = recversion;
                 tmpls[j].buf = &(buf[tot]) + (j * split_send_fragment);
                 tmpls[j].buflen = split_send_fragment;
             }
             /* Remember how much data we are going to be sending */
-            s->rlayer.wpend_tot = numpipes * split_send_fragment;
+            s->rlayer.wpend_tot = maxpipes * split_send_fragment;
         } else {
             /* We can partially fill all available pipelines */
-            tmppipelen = n / numpipes;
-            remain = n % numpipes;
+            tmppipelen = n / maxpipes;
+            remain = n % maxpipes;
             /*
              * If there is a remainder we add an extra byte to the first few
              * pipelines
              */
             if (remain > 0)
                 tmppipelen++;
-            for (j = 0; j < numpipes; j++) {
+            for (j = 0; j < maxpipes; j++) {
                 tmpls[j].type = type;
                 tmpls[j].version = recversion;
                 tmpls[j].buf = &(buf[tot]) + lensofar;
@@ -392,7 +380,7 @@ int ssl3_write_bytes(SSL *ssl, int type, const void *buf_, size_t len,
         }
 
         i = HANDLE_RLAYER_WRITE_RETURN(s,
-            s->rlayer.wrlmethod->write_records(s->rlayer.wrl, tmpls, numpipes));
+            s->rlayer.wrlmethod->write_records(s->rlayer.wrl, tmpls, maxpipes));
         if (i <= 0) {
             /* SSLfatal() already called if appropriate */
             s->rlayer.wnum = tot;