Index: net/socket/ssl_client_socket_openssl.cc |
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc |
index c78a9742bf8324c3cc1d8e138c7e04589b89e4f7..f599fbb5428eed7859be87e8c925273c6dda2299 100644 |
--- a/net/socket/ssl_client_socket_openssl.cc |
+++ b/net/socket/ssl_client_socket_openssl.cc |
@@ -68,6 +68,9 @@ const int kNoPendingReadResult = 1; |
// the server supports NPN, choosing "http/1.1" is the best answer. |
const char kDefaultSupportedNPNProtocol[] = "http/1.1"; |
+// Default size of the internal BoringSSL buffers. |
+const int KDefaultOpenSSLBufferSize = 17 * 1024; |
+ |
void FreeX509Stack(STACK_OF(X509)* ptr) { |
sk_X509_pop_free(ptr, X509_free); |
} |
@@ -728,9 +731,19 @@ int SSLClientSocketOpenSSL::Init() { |
trying_cached_session_ = context->session_cache()->SetSSLSessionWithKey( |
ssl_, GetSessionCacheKey()); |
+ send_buffer_ = new GrowableIOBuffer(); |
+ send_buffer_->SetCapacity(KDefaultOpenSSLBufferSize); |
+ recv_buffer_ = new GrowableIOBuffer(); |
+ recv_buffer_->SetCapacity(KDefaultOpenSSLBufferSize); |
+ |
BIO* ssl_bio = NULL; |
- // 0 => use default buffer sizes. |
- if (!BIO_new_bio_pair(&ssl_bio, 0, &transport_bio_, 0)) |
+ |
+ // SSLClientSocketOpenSSL retains ownership of the BIO buffers. |
+ if (!BIO_new_bio_pair_external_buf( |
+ &ssl_bio, send_buffer_->capacity(), |
+ reinterpret_cast<uint8_t*>(send_buffer_->data()), &transport_bio_, |
+ recv_buffer_->capacity(), |
+ reinterpret_cast<uint8_t*>(recv_buffer_->data()))) |
return ERR_UNEXPECTED; |
DCHECK(ssl_bio); |
DCHECK(transport_bio_); |
@@ -1530,20 +1543,20 @@ int SSLClientSocketOpenSSL::BufferSend(void) { |
if (transport_send_busy_) |
return ERR_IO_PENDING; |
- if (!send_buffer_.get()) { |
- // Get a fresh send buffer out of the send BIO. |
- size_t max_read = BIO_pending(transport_bio_); |
- if (!max_read) |
- return 0; // Nothing pending in the OpenSSL write BIO. |
- send_buffer_ = new DrainableIOBuffer(new IOBuffer(max_read), max_read); |
- int read_bytes = BIO_read(transport_bio_, send_buffer_->data(), max_read); |
- DCHECK_GT(read_bytes, 0); |
- CHECK_EQ(static_cast<int>(max_read), read_bytes); |
- } |
+ size_t buffer_read_offset; |
+ uint8_t* read_buf; |
+ size_t max_read; |
+ int status = BIO_zero_copy_get_read_buf(transport_bio_, &read_buf, |
+ &buffer_read_offset, &max_read); |
+ DCHECK_EQ(status, 1); // Should never fail. |
+ if (!max_read) |
+ return 0; // Nothing pending in the OpenSSL write BIO. |
+ CHECK_EQ(read_buf, reinterpret_cast<uint8_t*>(send_buffer_->StartOfBuffer())); |
+ CHECK_LT(buffer_read_offset, static_cast<size_t>(send_buffer_->capacity())); |
+ send_buffer_->set_offset(buffer_read_offset); |
int rv = transport_->socket()->Write( |
- send_buffer_.get(), |
- send_buffer_->BytesRemaining(), |
+ send_buffer_.get(), max_read, |
base::Bind(&SSLClientSocketOpenSSL::BufferSendComplete, |
base::Unretained(this))); |
if (rv == ERR_IO_PENDING) { |
@@ -1576,11 +1589,21 @@ int SSLClientSocketOpenSSL::BufferRecv(void) { |
// fill |transport_bio_| is issued. As long as an SSL client socket cannot |
// be gracefully shutdown (via SSL close alerts) and re-used for non-SSL |
// traffic, this over-subscribed Read()ing will not cause issues. |
- size_t max_write = BIO_ctrl_get_write_guarantee(transport_bio_); |
+ |
+ size_t buffer_write_offset; |
+ uint8_t* write_buf; |
+ size_t max_write; |
+ int status = BIO_zero_copy_get_write_buf(transport_bio_, &write_buf, |
+ &buffer_write_offset, &max_write); |
+ DCHECK_EQ(status, 1); // Should never fail. |
if (!max_write) |
return ERR_IO_PENDING; |
- recv_buffer_ = new IOBuffer(max_write); |
+ CHECK_EQ(write_buf, |
+ reinterpret_cast<uint8_t*>(recv_buffer_->StartOfBuffer())); |
+ CHECK_LT(buffer_write_offset, static_cast<size_t>(recv_buffer_->capacity())); |
+ |
+ recv_buffer_->set_offset(buffer_write_offset); |
int rv = transport_->socket()->Read( |
recv_buffer_.get(), |
max_write, |
@@ -1595,7 +1618,6 @@ int SSLClientSocketOpenSSL::BufferRecv(void) { |
} |
void SSLClientSocketOpenSSL::BufferSendComplete(int result) { |
- transport_send_busy_ = false; |
TransportWriteComplete(result); |
OnSendComplete(result); |
} |
@@ -1607,18 +1629,18 @@ void SSLClientSocketOpenSSL::BufferRecvComplete(int result) { |
void SSLClientSocketOpenSSL::TransportWriteComplete(int result) { |
DCHECK(ERR_IO_PENDING != result); |
+ int bytes_written = 0; |
if (result < 0) { |
// Record the error. Save it to be reported in a future read or write on |
// transport_bio_'s peer. |
transport_write_error_ = result; |
- send_buffer_ = NULL; |
} else { |
- DCHECK(send_buffer_.get()); |
- send_buffer_->DidConsume(result); |
- DCHECK_GE(send_buffer_->BytesRemaining(), 0); |
- if (send_buffer_->BytesRemaining() <= 0) |
- send_buffer_ = NULL; |
+ bytes_written = result; |
} |
+ DCHECK_GE(send_buffer_->RemainingCapacity(), bytes_written); |
+ int ret = BIO_zero_copy_get_read_buf_done(transport_bio_, bytes_written); |
+ DCHECK_EQ(1, ret); |
+ transport_send_busy_ = false; |
} |
int SSLClientSocketOpenSSL::TransportReadComplete(int result) { |
@@ -1627,18 +1649,18 @@ int SSLClientSocketOpenSSL::TransportReadComplete(int result) { |
// does not report success. |
if (result == 0) |
result = ERR_CONNECTION_CLOSED; |
+ int bytes_read = 0; |
if (result < 0) { |
DVLOG(1) << "TransportReadComplete result " << result; |
// Received an error. Save it to be reported in a future read on |
// transport_bio_'s peer. |
transport_read_error_ = result; |
} else { |
- DCHECK(recv_buffer_.get()); |
- int ret = BIO_write(transport_bio_, recv_buffer_->data(), result); |
- // A write into a memory BIO should always succeed. |
- DCHECK_EQ(result, ret); |
+ bytes_read = result; |
} |
- recv_buffer_ = NULL; |
+ DCHECK_GE(recv_buffer_->RemainingCapacity(), bytes_read); |
+ int ret = BIO_zero_copy_get_write_buf_done(transport_bio_, bytes_read); |
+ DCHECK_EQ(1, ret); |
transport_recv_busy_ = false; |
return result; |
} |