Index: net/socket/ssl_client_socket_nss.cc |
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc |
index 92f6c37f4ef564aeb959f6e16ef969674a432b63..ccdb7084e8f00f40c6fce5b52ceacac07781e4f5 100644 |
--- a/net/socket/ssl_client_socket_nss.cc |
+++ b/net/socket/ssl_client_socket_nss.cc |
@@ -571,9 +571,9 @@ int MapNSSClientHandshakeError(PRErrorCode err) { |
// |-------------------------------V |
// BufferRecvComplete() |
// | |
-// PostOrRunCallback() |
+// DoReadCallback() |
// V-------------------------------| |
-// PostOrRunCallback() |
+// UpdateReadStatus() |
Ryan Sleevi
2013/01/07 18:59:04
NACK on this. The intention of PostOrRunCallback i
Takashi Toyoshima
2013/01/08 06:25:39
Oh, I miss the case of single-threaded model and m
|
// V---------------------| |
// (Read Callback) |
// |
@@ -637,6 +637,10 @@ class SSLClientSocketNSS::Core : public base::RefCountedThreadSafe<Core> { |
int Read(IOBuffer* buf, int buf_len, const CompletionCallback& callback); |
int Write(IOBuffer* buf, int buf_len, const CompletionCallback& callback); |
+ // Called on the network task runner. |
+ bool HasPendingAsyncOperation(); |
+ bool HasUnhandledData(); |
+ |
private: |
friend class base::RefCountedThreadSafe<Core>; |
~Core(); |
@@ -735,6 +739,10 @@ class SSLClientSocketNSS::Core : public base::RefCountedThreadSafe<Core> { |
void DoConnectCallback(int result); |
void DoReadCallback(int result); |
void DoWriteCallback(int result); |
+ void UpdateNSSStatus(int amount_in_read_buffer, |
+ bool operation_is_read, |
+ const CompletionCallback& callback, |
+ int rv); |
// Client channel ID handler. |
static SECStatus ClientChannelIDHandler( |
@@ -812,6 +820,11 @@ class SSLClientSocketNSS::Core : public base::RefCountedThreadSafe<Core> { |
ServerBoundCertService* server_bound_cert_service_; |
ServerBoundCertService::RequestHandle domain_bound_cert_request_handle_; |
+ // The information about NSS task runner status. |
+ int unhandled_buffer_size_; |
+ bool waiting_read_; |
+ bool waiting_write_; |
+ |
//////////////////////////////////////////////////////////////////////////// |
// Members that are ONLY accessed on the NSS task runner: |
//////////////////////////////////////////////////////////////////////////// |
@@ -892,6 +905,9 @@ SSLClientSocketNSS::Core::Core( |
weak_net_log_factory_(net_log), |
server_bound_cert_service_(server_bound_cert_service), |
domain_bound_cert_request_handle_(NULL), |
+ unhandled_buffer_size_(0), |
+ waiting_read_(false), |
+ waiting_write_(false), |
host_and_port_(host_and_port), |
ssl_config_(ssl_config), |
nss_fd_(NULL), |
@@ -1104,9 +1120,11 @@ int SSLClientSocketNSS::Core::Read(IOBuffer* buf, int buf_len, |
DCHECK(user_connect_callback_.is_null()); |
DCHECK(!user_read_buf_); |
DCHECK(nss_bufs_); |
+ DCHECK(!waiting_read_); |
user_read_buf_ = buf; |
user_read_buf_len_ = buf_len; |
+ waiting_read_ = true; |
int rv = DoReadLoop(OK); |
if (rv == ERR_IO_PENDING) { |
@@ -1114,6 +1132,7 @@ int SSLClientSocketNSS::Core::Read(IOBuffer* buf, int buf_len, |
} else { |
user_read_buf_ = NULL; |
user_read_buf_len_ = 0; |
+ waiting_read_ = false; |
if (!OnNetworkTaskRunner()) { |
PostOrRunCallback(FROM_HERE, base::Bind(callback, rv)); |
@@ -1146,9 +1165,11 @@ int SSLClientSocketNSS::Core::Write(IOBuffer* buf, int buf_len, |
DCHECK(user_connect_callback_.is_null()); |
DCHECK(!user_write_buf_); |
DCHECK(nss_bufs_); |
+ DCHECK(!waiting_write_); |
user_write_buf_ = buf; |
user_write_buf_len_ = buf_len; |
+ waiting_write_ = true; |
int rv = DoWriteLoop(OK); |
if (rv == ERR_IO_PENDING) { |
@@ -1156,6 +1177,7 @@ int SSLClientSocketNSS::Core::Write(IOBuffer* buf, int buf_len, |
} else { |
user_write_buf_ = NULL; |
user_write_buf_len_ = 0; |
+ waiting_write_ = false; |
if (!OnNetworkTaskRunner()) { |
PostOrRunCallback(FROM_HERE, base::Bind(callback, rv)); |
@@ -1166,6 +1188,16 @@ int SSLClientSocketNSS::Core::Write(IOBuffer* buf, int buf_len, |
return rv; |
} |
+bool SSLClientSocketNSS::Core::HasPendingAsyncOperation() { |
+ DCHECK(OnNetworkTaskRunner()); |
+ return waiting_read_ || waiting_write_; |
+} |
+ |
+bool SSLClientSocketNSS::Core::HasUnhandledData() { |
+ DCHECK(OnNetworkTaskRunner()); |
+ return unhandled_buffer_size_ != 0; |
+} |
+ |
bool SSLClientSocketNSS::Core::OnNSSTaskRunner() const { |
return nss_task_runner_->RunsTasksOnCurrentThread(); |
} |
@@ -2257,10 +2289,19 @@ void SSLClientSocketNSS::Core::DoReadCallback(int rv) { |
user_read_buf_ = NULL; |
user_read_buf_len_ = 0; |
- base::Closure c = base::Bind( |
- base::ResetAndReturn(&user_read_callback_), |
- rv); |
- PostOrRunCallback(FROM_HERE, c); |
+ char* buf; |
+ int amount_in_read_buffer = memio_GetReadParams(nss_bufs_, &buf); |
+ CompletionCallback cb = base::ResetAndReturn(&user_read_callback_); |
+ // Curry the |amount_int_read_buffer| and |cb| back to the network task |
+ // runner. |
+ network_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&Core::UpdateNSSStatus, |
+ this, |
+ amount_in_read_buffer, |
+ true, // Operation is read. |
+ cb, |
+ rv)); |
Ryan Sleevi
2013/01/07 18:59:04
NACK: See above comments re: PostOrRunCallback. Yo
Takashi Toyoshima
2013/01/08 06:25:39
Done.
|
} |
void SSLClientSocketNSS::Core::DoWriteCallback(int rv) { |
@@ -2272,10 +2313,39 @@ void SSLClientSocketNSS::Core::DoWriteCallback(int rv) { |
// up front. |
user_write_buf_ = NULL; |
user_write_buf_len_ = 0; |
- base::Closure c = base::Bind( |
- base::ResetAndReturn(&user_write_callback_), |
- rv); |
- PostOrRunCallback(FROM_HERE, c); |
+ char* buf; |
+ // Update buffer status because DoWriteLoop called DoTransportIO which may |
+ // perform read operations. |
+ int amount_in_read_buffer = memio_GetReadParams(nss_bufs_, &buf); |
+ CompletionCallback cb = base::ResetAndReturn(&user_write_callback_); |
+ // Curry the |cb| back to the network task runner. |
+ network_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&Core::UpdateNSSStatus, |
+ this, |
+ amount_in_read_buffer, |
+ false, // Operation is not read, but write. |
+ cb, |
+ rv)); |
Ryan Sleevi
2013/01/07 18:59:04
Also here
Takashi Toyoshima
2013/01/08 06:25:39
Done.
|
+} |
+ |
+void SSLClientSocketNSS::Core::UpdateNSSStatus( |
+ int amount_in_read_buffer, |
+ bool operation_is_read, |
+ const CompletionCallback& callback, |
+ int rv) { |
Ryan Sleevi
2013/01/07 18:59:04
If you're going to post a callback, you should pos
Takashi Toyoshima
2013/01/08 06:25:39
Done.
|
+ DCHECK(OnNetworkTaskRunner()); |
+ DCHECK_NE(ERR_IO_PENDING, rv); |
+ DCHECK(!callback.is_null()); |
+ DCHECK((operation_is_read && waiting_read_) || |
+ (!operation_is_read && waiting_write_)); |
+ |
+ unhandled_buffer_size_ = amount_in_read_buffer; |
+ if (operation_is_read) |
+ waiting_read_ = false; |
+ else |
+ waiting_write_ = false; |
+ PostOrRunCallback(FROM_HERE, base::Bind(callback, rv)); |
Ryan Sleevi
2013/01/07 18:59:04
At this point, you're guaranteed to be OnNetworkTa
Takashi Toyoshima
2013/01/08 06:25:39
Done.
|
} |
SECStatus SSLClientSocketNSS::Core::ClientChannelIDHandler( |
@@ -2898,7 +2968,17 @@ bool SSLClientSocketNSS::IsConnected() const { |
// closed by the server when we send a request anyway, a false positive in |
// exchange for simpler code is a good trade-off. |
EnterFunction(""); |
- bool ret = completed_handshake_ && transport_->socket()->IsConnected(); |
+ bool ret; |
+ |
+ if (!completed_handshake_) |
+ ret = false; |
+ else if (core_->HasPendingAsyncOperation()) |
+ ret = true; |
+ else if (core_->HasUnhandledData()) |
+ ret = true; |
+ else |
+ ret = transport_->socket()->IsConnected(); |
+ |
LeaveFunction(""); |
return ret; |
} |
@@ -2913,7 +2993,17 @@ bool SSLClientSocketNSS::IsConnectedAndIdle() const { |
// transport_->socket()->IsConnectedAndIdle() returns the desired false |
// when we receive close_notify. |
EnterFunction(""); |
- bool ret = completed_handshake_ && transport_->socket()->IsConnectedAndIdle(); |
+ bool ret; |
+ |
+ if (!completed_handshake_) |
+ ret = false; |
+ else if (core_->HasPendingAsyncOperation()) |
+ ret = true; // This is probably wrong, but mirrors TCP. |
+ else if (core_->HasUnhandledData()) |
+ ret = false; |
+ else |
+ ret = transport_->socket()->IsConnectedAndIdle(); |
+ |
LeaveFunction(""); |
return ret; |
} |