Index: src/tls/OFOpenSSLTLSStream.m ================================================================== --- src/tls/OFOpenSSLTLSStream.m +++ src/tls/OFOpenSSLTLSStream.m @@ -106,26 +106,10 @@ size_t bytesRead; if (!_handshakeDone) @throw [OFNotOpenException exceptionWithObject: self]; - if (BIO_ctrl_pending(_readBIO) < 1) { - @try { - size_t tmp = [_underlyingStream - readIntoBuffer: _buffer - length: bufferSize]; - - OFEnsure(tmp <= INT_MAX); - /* Writing to a memory BIO must never fail. */ - OFEnsure(BIO_write(_readBIO, _buffer, (int)tmp) == - (int)tmp); - } @catch (OFReadFailedException *e) { - if (e.errNo != EWOULDBLOCK && e.errNo != EAGAIN) - @throw e; - } - } - ret = SSL_read_ex(_SSL, buffer, length, &bytesRead); while (BIO_ctrl_pending(_writeBIO) > 0) { int tmp = BIO_read(_writeBIO, _buffer, bufferSize); @@ -133,30 +117,52 @@ [_underlyingStream writeBuffer: _buffer length: tmp]; [_underlyingStream flushWriteBuffer]; } - if (ret != 1) { - /* - * The underlying stream might have had data ready, but not - * enough for OpenSSL to return decrypted data. This means the - * caller might have observed the TLS stream for reading, got a - * ready signal and read - and expects the read to succeed, not - * to fail with EWOULDBLOCK, as it was signaled ready. - * Therefore, return 0, as we could read 0 decrypted bytes, but - * cleared the ready signal of the underlying stream. - */ + if (ret == 1) + return bytesRead; + + if (SSL_get_error(_SSL, ret) == SSL_ERROR_WANT_READ) { + if (BIO_ctrl_pending(_readBIO) < 1) { + @try { + size_t tmp = [_underlyingStream + readIntoBuffer: _buffer + length: bufferSize]; + + OFEnsure(tmp <= INT_MAX); + /* Writing to a memory BIO must never fail. */ + OFEnsure(BIO_write(_readBIO, _buffer, + (int)tmp) == (int)tmp); + } @catch (OFReadFailedException *e) { + if (e.errNo == EWOULDBLOCK || e.errNo != EAGAIN) + return 0; + } + } + + ret = SSL_read_ex(_SSL, buffer, length, &bytesRead); + + while (BIO_ctrl_pending(_writeBIO) > 0) { + int tmp = BIO_read(_writeBIO, _buffer, bufferSize); + + OFEnsure(tmp >= 0); + + [_underlyingStream writeBuffer: _buffer length: tmp]; + [_underlyingStream flushWriteBuffer]; + } + + if (ret == 1) + return bytesRead; + if (SSL_get_error(_SSL, ret) == SSL_ERROR_WANT_READ) return 0; - - /* FIXME: Translate error to errNo */ - @throw [OFReadFailedException exceptionWithObject: self - requestedLength: length - errNo: 0]; } - return bytesRead; + /* FIXME: Translate error to errNo */ + @throw [OFReadFailedException exceptionWithObject: self + requestedLength: length + errNo: 0]; } - (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length { int ret;