]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-ssl-iostream: istream-openssl - Simplify i_stream_ssl_read().
authorStephan Bosch <stephan.bosch@open-xchange.com>
Sun, 27 Sep 2020 13:19:05 +0000 (15:19 +0200)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Thu, 30 Sep 2021 17:08:11 +0000 (17:08 +0000)
Avoid using a stack buffer. Just fill the stream to the maximum buffer size.

src/lib-ssl-iostream/istream-openssl.c

index 962d1b9053dee93d88683074d30c68b836538970..9b7944e09920e7a96b48952aa9c3841a7c2ee811 100644 (file)
@@ -33,8 +33,6 @@ static ssize_t i_stream_ssl_read_real(struct istream_private *stream)
 {
        struct ssl_istream *sstream = (struct ssl_istream *)stream;
        struct ssl_iostream *ssl_io = sstream->ssl_io;
-       unsigned char buffer[IO_BLOCK_SIZE];
-       size_t orig_max_buffer_size = stream->max_buffer_size;
        size_t size;
        ssize_t ret, total_ret;
 
@@ -64,42 +62,51 @@ static ssize_t i_stream_ssl_read_real(struct istream_private *stream)
                stream->istream.stream_errno = ssl_io->plain_stream_errno;
                return -1;
        }
-       if (!i_stream_try_alloc(stream, 1, &size))
-               return -2;
-
-       while ((ret = SSL_read(ssl_io->ssl,
-                              stream->w_buffer + stream->pos, size)) <= 0) {
-               /* failed to read anything */
-               ret = openssl_iostream_handle_error(ssl_io, ret,
-                       OPENSSL_IOSTREAM_SYNC_TYPE_CONTINUE_READ, "SSL_read");
+
+       total_ret = 0;
+       for (;;) {
+               int pending = SSL_pending(ssl_io->ssl);
+
+               /* Allocate buffer space if needed. */
+               i_assert(stream->buffer_size >= stream->pos);
+               size = stream->buffer_size - stream->pos;
+               if ((pending > 0 || size == 0) &&
+                   !i_stream_try_alloc(stream, I_MAX(pending, 1), &size)) {
+                       if (total_ret > 0)
+                               break;
+                       return -2;
+               }
+
+               ret = SSL_read(ssl_io->ssl, stream->w_buffer + stream->pos, size);
                if (ret <= 0) {
-                       if (ret == 0)
-                               return 0;
-                       if (ssl_io->last_error != NULL) {
-                               io_stream_set_error(&stream->iostream,
-                                                   "%s", ssl_io->last_error);
+                       /* failed to read anything */
+                       ret = openssl_iostream_handle_error(ssl_io, ret,
+                               (total_ret == 0 ?
+                                OPENSSL_IOSTREAM_SYNC_TYPE_CONTINUE_READ :
+                                OPENSSL_IOSTREAM_SYNC_TYPE_NONE), "SSL_read");
+                       if (ret <= 0) {
+                               if (ret == 0)
+                                       break;
+                               if (ssl_io->last_error != NULL) {
+                                       io_stream_set_error(&stream->iostream,
+                                                           "%s", ssl_io->last_error);
+                               }
+                               if (errno != EPIPE)
+                                       stream->istream.stream_errno = errno;
+                               stream->istream.eof = TRUE;
+                               sstream->seen_eof = TRUE;
+                               if (total_ret > 0)
+                                       break;
+                               return -1;
                        }
-                       if (errno != EPIPE)
-                               stream->istream.stream_errno = errno;
-                       stream->istream.eof = TRUE;
-                       sstream->seen_eof = TRUE;
-                       return -1;
+                       /* we did some BIO I/O, try reading again */
+                       continue;
                }
-               /* we did some BIO I/O, try reading again */
-       }
-       stream->pos += ret;
-       total_ret = ret;
-
-       /* now make sure that we read everything already buffered in OpenSSL
-          into the stream (without reading anything more). this makes I/O loop
-          behave similarly for ssl-istream as file-istream. */
-       stream->max_buffer_size = SIZE_MAX;
-       while ((ret = SSL_read(ssl_io->ssl, buffer, sizeof(buffer))) > 0) {
-               memcpy(i_stream_alloc(stream, ret), buffer, ret);
                stream->pos += ret;
                total_ret += ret;
        }
-       stream->max_buffer_size = orig_max_buffer_size;
+       if (SSL_pending(ssl_io->ssl) > 0)
+               i_stream_set_input_pending(ssl_io->ssl_input, TRUE);
        return total_ret;
 }