{
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;
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;
}