From: Stephan Bosch Date: Sun, 27 Sep 2020 13:19:05 +0000 (+0200) Subject: lib-ssl-iostream: istream-openssl - Simplify i_stream_ssl_read(). X-Git-Tag: 2.3.18~289 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=00df102e564af22fb467b0f45c35ac1def955e18;p=thirdparty%2Fdovecot%2Fcore.git lib-ssl-iostream: istream-openssl - Simplify i_stream_ssl_read(). Avoid using a stack buffer. Just fill the stream to the maximum buffer size. --- diff --git a/src/lib-ssl-iostream/istream-openssl.c b/src/lib-ssl-iostream/istream-openssl.c index 962d1b9053..9b7944e099 100644 --- a/src/lib-ssl-iostream/istream-openssl.c +++ b/src/lib-ssl-iostream/istream-openssl.c @@ -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; }