Chromium Code Reviews| Index: net/socket/ssl_client_socket_mac.cc |
| diff --git a/net/socket/ssl_client_socket_mac.cc b/net/socket/ssl_client_socket_mac.cc |
| index 9eef7273a349259eb824aaa02398e6ef52e01a29..60561045a282aaf40213c8f496233e510622db3c 100644 |
| --- a/net/socket/ssl_client_socket_mac.cc |
| +++ b/net/socket/ssl_client_socket_mac.cc |
| @@ -68,12 +68,12 @@ |
| // So, like in any good relationship, we're forced to lie. Whenever Secure |
| // Transport asks for data to be written, we take it all and lie about it always |
| // being written. We spin in a loop (see SSLWriteCallback() and |
| -// OnWriteComplete()) independent of the main state machine writing the data to |
| -// the network, and get the data out. The main consequence of this independence |
| -// from the state machine is that we require a full-duplex transport underneath |
| -// us since we can't use it to keep our reading and writing |
| -// straight. Fortunately, the NSS implementation also has this issue to deal |
| -// with, so we share the same Libevent-based full-duplex TCP socket. |
| +// OnTransportWriteComplete()) independent of the main state machine writing |
| +// the data to he network, and get the data out. The main consequence of this |
| +// independence from the state machine is that we require a full-duplex |
| +// transport underneath us since we can't use it to keep our reading and |
| +// writing straight. Fortunately, the NSS implementation also has this issue |
| +// to deal with, so we share the same Libevent-based full-duplex TCP socket. |
| // |
| // A side comment on return values might be in order. Those who haven't taken |
| // the time to read the documentation (ahem, header comments) in our various |
| @@ -297,14 +297,20 @@ X509Certificate* GetServerCert(SSLContextRef ssl_context) { |
| SSLClientSocketMac::SSLClientSocketMac(ClientSocket* transport_socket, |
| const std::string& hostname, |
| const SSLConfig& ssl_config) |
| - : io_callback_(this, &SSLClientSocketMac::OnIOComplete), |
| - write_callback_(this, &SSLClientSocketMac::OnWriteComplete), |
| + : handshake_io_callback_(this, &SSLClientSocketMac::OnHandshakeIOComplete), |
| + transport_read_callback_(this, |
| + &SSLClientSocketMac::OnTransportReadComplete), |
| + transport_write_callback_(this, |
| + &SSLClientSocketMac::OnTransportWriteComplete), |
| transport_(transport_socket), |
| hostname_(hostname), |
| ssl_config_(ssl_config), |
| - user_callback_(NULL), |
| - next_state_(STATE_NONE), |
| - next_io_state_(STATE_NONE), |
| + user_connect_callback_(NULL), |
| + user_read_callback_(NULL), |
| + user_write_callback_(NULL), |
| + user_read_buf_len_(0), |
| + user_write_buf_len_(0), |
| + next_handshake_state_(STATE_NONE), |
| completed_handshake_(false), |
| handshake_interrupted_(false), |
| ssl_context_(NULL), |
| @@ -319,8 +325,8 @@ SSLClientSocketMac::~SSLClientSocketMac() { |
| int SSLClientSocketMac::Connect(CompletionCallback* callback) { |
| DCHECK(transport_.get()); |
| - DCHECK(next_state_ == STATE_NONE); |
| - DCHECK(!user_callback_); |
| + DCHECK(next_handshake_state_ == STATE_NONE); |
| + DCHECK(!user_connect_callback_); |
| OSStatus status = noErr; |
| @@ -415,10 +421,10 @@ int SSLClientSocketMac::Connect(CompletionCallback* callback) { |
| } |
| } |
| - next_state_ = STATE_HANDSHAKE_START; |
| - int rv = DoLoop(OK); |
| + next_handshake_state_ = STATE_HANDSHAKE_START; |
| + int rv = DoHandshakeLoop(OK); |
| if (rv == ERR_IO_PENDING) |
| - user_callback_ = callback; |
| + user_connect_callback_ = callback; |
| return rv; |
| } |
| @@ -460,19 +466,18 @@ bool SSLClientSocketMac::IsConnectedAndIdle() const { |
| int SSLClientSocketMac::Read(IOBuffer* buf, int buf_len, |
| CompletionCallback* callback) { |
| DCHECK(completed_handshake_); |
| - DCHECK(next_state_ == STATE_NONE); |
| - DCHECK(!user_callback_); |
| - DCHECK(!user_buf_); |
| + DCHECK(!user_read_callback_); |
| + DCHECK(!user_read_buf_); |
| - user_buf_ = buf; |
| - user_buf_len_ = buf_len; |
| + user_read_buf_ = buf; |
| + user_read_buf_len_ = buf_len; |
| - next_state_ = STATE_PAYLOAD_READ; |
| - int rv = DoLoop(OK); |
| + int rv = DoPayloadRead(); |
| if (rv == ERR_IO_PENDING) { |
| - user_callback_ = callback; |
| + user_read_callback_ = callback; |
| } else { |
| - user_buf_ = NULL; |
| + user_read_buf_ = NULL; |
| + user_read_buf_len_ = 0; |
| } |
| return rv; |
| } |
| @@ -480,19 +485,18 @@ int SSLClientSocketMac::Read(IOBuffer* buf, int buf_len, |
| int SSLClientSocketMac::Write(IOBuffer* buf, int buf_len, |
| CompletionCallback* callback) { |
| DCHECK(completed_handshake_); |
| - DCHECK(next_state_ == STATE_NONE); |
| - DCHECK(!user_callback_); |
| - DCHECK(!user_buf_); |
| + DCHECK(!user_write_callback_); |
| + DCHECK(!user_write_buf_); |
| - user_buf_ = buf; |
| - user_buf_len_ = buf_len; |
| + user_write_buf_ = buf; |
| + user_write_buf_len_ = buf_len; |
| - next_state_ = STATE_PAYLOAD_WRITE; |
| - int rv = DoLoop(OK); |
| + int rv = DoPayloadWrite(); |
| if (rv == ERR_IO_PENDING) { |
| - user_callback_ = callback; |
| + user_write_callback_ = callback; |
| } else { |
| - user_buf_ = NULL; |
| + user_write_buf_ = NULL; |
| + user_write_buf_len_ = 0; |
| } |
| return rv; |
| } |
| @@ -528,40 +532,97 @@ void SSLClientSocketMac::GetSSLCertRequestInfo( |
| // TODO(wtc): implement this. |
| } |
| -void SSLClientSocketMac::DoCallback(int rv) { |
| +void SSLClientSocketMac::DoConnectCallback(int rv) { |
| DCHECK(rv != ERR_IO_PENDING); |
| - DCHECK(user_callback_); |
| + DCHECK(user_connect_callback_); |
| + DCHECK(next_handshake_state_ == STATE_NONE); |
| - // since Run may result in Read being called, clear user_callback_ up front. |
| - CompletionCallback* c = user_callback_; |
| - user_callback_ = NULL; |
| - user_buf_ = NULL; |
| + CompletionCallback* c = user_connect_callback_; |
| + user_connect_callback_ = NULL; |
| + c->Run(rv > OK ? OK : rv); |
| +} |
| + |
| +void SSLClientSocketMac::DoReadCallback(int rv) { |
| + DCHECK(rv != ERR_IO_PENDING); |
| + DCHECK(user_read_callback_); |
| + |
| + // Since Run may result in Read being called, clear user_read_callback_ up |
| + // front. |
| + CompletionCallback* c = user_read_callback_; |
| + user_read_callback_ = NULL; |
| + user_read_buf_ = NULL; |
| + user_read_buf_len_ = 0; |
| + c->Run(rv); |
| +} |
| + |
| +void SSLClientSocketMac::DoWriteCallback(int rv) { |
| + DCHECK(rv != ERR_IO_PENDING); |
| + DCHECK(user_write_callback_); |
| + |
| + // Since Run may result in Write being called, clear user_write_callback_ up |
| + // front. |
| + CompletionCallback* c = user_write_callback_; |
| + user_write_callback_ = NULL; |
| + user_write_buf_ = NULL; |
| + user_write_buf_len_ = 0; |
| c->Run(rv); |
| } |
| -void SSLClientSocketMac::OnIOComplete(int result) { |
| - if (next_io_state_ != STATE_NONE) { |
| - State next_state = next_state_; |
| - next_state_ = next_io_state_; |
| - next_io_state_ = STATE_NONE; |
| - result = DoLoop(result); |
| - next_state_ = next_state; |
| +void SSLClientSocketMac::OnHandshakeIOComplete(int result) { |
| + DCHECK(next_handshake_state_ != STATE_NONE); |
| + int rv = DoHandshakeLoop(result); |
| + if (rv != ERR_IO_PENDING) |
| + DoConnectCallback(rv); |
| +} |
| + |
| +void SSLClientSocketMac::OnTransportReadComplete(int result) { |
| + if (result > 0) { |
| + char* buffer = |
| + &recv_buffer_[recv_buffer_.size() - recv_buffer_tail_slop_]; |
| + memcpy(buffer, read_io_buf_->data(), result); |
| + recv_buffer_tail_slop_ -= result; |
| + } |
| + read_io_buf_ = NULL; |
| + |
| + if (next_handshake_state_ != STATE_NONE) { |
| + int rv = DoHandshakeLoop(result); |
| + if (rv != ERR_IO_PENDING) |
| + DoConnectCallback(rv); |
| + return; |
| } |
| - if (next_state_ != STATE_NONE) { |
| - int rv = DoLoop(result); |
| + if (user_read_buf_) { |
| + if (result < 0) { |
| + DoReadCallback(result); |
| + return; |
| + } |
| + int rv = DoPayloadRead(); |
| if (rv != ERR_IO_PENDING) |
| - DoCallback(rv); |
| + DoReadCallback(rv); |
| + } |
| +} |
| + |
| +void SSLClientSocketMac::OnTransportWriteComplete(int result) { |
| + if (result < 0) { |
| + pending_send_error_ = result; |
| + return; |
| } |
| + send_buffer_.erase(send_buffer_.begin(), |
| + send_buffer_.begin() + result); |
| + if (!send_buffer_.empty()) |
| + SSLWriteCallback(this, NULL, NULL); |
| + |
| + // Since SSLWriteCallback() lies to return noErr even if transport_->Write() |
| + // returns ERR_IO_PENDING, we don't need to any callbacks here. |
|
wtc
2009/10/22 22:06:44
Nit: add "call" or "do" after "need to".
|
| } |
| // This is the main loop driving the state machine. Most calls coming from the |
| // outside just set up a few variables and jump into here. |
| -int SSLClientSocketMac::DoLoop(int last_io_result) { |
| - DCHECK(next_state_ != STATE_NONE); |
| +int SSLClientSocketMac::DoHandshakeLoop(int last_io_result) { |
| + DCHECK(next_handshake_state_ != STATE_NONE); |
| int rv = last_io_result; |
| do { |
| - State state = next_state_; |
| - next_state_ = STATE_NONE; |
| + State state = next_handshake_state_; |
| + next_handshake_state_ = STATE_NONE; |
| switch (state) { |
| case STATE_HANDSHAKE_START: |
| // Do the SSL/TLS handshake, up to the server certificate message. |
| @@ -579,32 +640,19 @@ int SSLClientSocketMac::DoLoop(int last_io_result) { |
| // Do the SSL/TLS handshake, after the server certificate message. |
| rv = DoHandshakeFinish(); |
| break; |
| - case STATE_READ_COMPLETE: |
| - // A read off the network is complete; do the paperwork. |
| - rv = DoReadComplete(rv); |
| - break; |
| - case STATE_PAYLOAD_READ: |
| - // Do a read of data from the network. |
| - rv = DoPayloadRead(); |
| - break; |
| - case STATE_PAYLOAD_WRITE: |
| - // Do a write of data to the network. |
| - rv = DoPayloadWrite(); |
| - break; |
| default: |
| rv = ERR_UNEXPECTED; |
| NOTREACHED() << "unexpected state"; |
| break; |
| } |
| - } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); |
| + } while (rv != ERR_IO_PENDING && next_handshake_state_ != STATE_NONE); |
| return rv; |
| } |
| int SSLClientSocketMac::DoHandshakeStart() { |
| OSStatus status = SSLHandshake(ssl_context_); |
| - |
| if (status == errSSLWouldBlock) |
| - next_state_ = STATE_HANDSHAKE_START; |
| + next_handshake_state_ = STATE_HANDSHAKE_START; |
| server_cert_ = GetServerCert(ssl_context_); |
| @@ -616,7 +664,7 @@ int SSLClientSocketMac::DoHandshakeStart() { |
| // so that we have the certificate status (valid, expired but overridden |
| // by the user, EV, etc.) available. Eliminate this step once we have |
| // a certificate validation result cache. |
| - next_state_ = STATE_VERIFY_CERT; |
| + next_handshake_state_ = STATE_VERIFY_CERT; |
| if (status == errSSLServerAuthCompletedFlag) { |
| // Override errSSLServerAuthCompletedFlag as it's not actually an error, |
| // but rather an indication that we're only half way through the |
| @@ -630,7 +678,7 @@ int SSLClientSocketMac::DoHandshakeStart() { |
| } |
| int SSLClientSocketMac::DoVerifyCert() { |
| - next_state_ = STATE_VERIFY_CERT_COMPLETE; |
| + next_handshake_state_ = STATE_VERIFY_CERT_COMPLETE; |
| if (!server_cert_) |
| return ERR_UNEXPECTED; |
| @@ -642,7 +690,8 @@ int SSLClientSocketMac::DoVerifyCert() { |
| flags |= X509Certificate::VERIFY_EV_CERT; |
| verifier_.reset(new CertVerifier); |
| return verifier_->Verify(server_cert_, hostname_, flags, |
| - &server_cert_verify_result_, &io_callback_); |
| + &server_cert_verify_result_, |
| + &handshake_io_callback_); |
| } |
| int SSLClientSocketMac::DoVerifyCertComplete(int result) { |
| @@ -657,12 +706,12 @@ int SSLClientSocketMac::DoVerifyCertComplete(int result) { |
| // in a non-resumed session) occurs in two steps. Continue on to the second |
| // step if the certificate is OK. |
| if (result == OK) |
| - next_state_ = STATE_HANDSHAKE_FINISH; |
| + next_handshake_state_ = STATE_HANDSHAKE_FINISH; |
| } else { |
| // If the session was resumed or session resumption was disabled, we're |
| // done with the handshake. |
| completed_handshake_ = true; |
| - DCHECK(next_state_ == STATE_NONE); |
| + DCHECK(next_handshake_state_ == STATE_NONE); |
| } |
| return result; |
| @@ -672,47 +721,21 @@ int SSLClientSocketMac::DoHandshakeFinish() { |
| OSStatus status = SSLHandshake(ssl_context_); |
| if (status == errSSLWouldBlock) |
| - next_state_ = STATE_HANDSHAKE_FINISH; |
| + next_handshake_state_ = STATE_HANDSHAKE_FINISH; |
| - if (status == noErr) |
| + if (status == noErr) { |
| completed_handshake_ = true; |
| - |
| - return NetErrorFromOSStatus(status); |
| -} |
| - |
| -int SSLClientSocketMac::DoReadComplete(int result) { |
| - if (result < 0) { |
| - read_io_buf_ = NULL; |
| - return result; |
| + DCHECK(next_handshake_state_ == STATE_NONE); |
| } |
| - char* buffer = &recv_buffer_[recv_buffer_.size() - recv_buffer_tail_slop_]; |
| - memcpy(buffer, read_io_buf_->data(), result); |
| - read_io_buf_ = NULL; |
| - |
| - recv_buffer_tail_slop_ -= result; |
| - |
| - return result; |
| -} |
| - |
| -void SSLClientSocketMac::OnWriteComplete(int result) { |
| - if (result < 0) { |
| - pending_send_error_ = result; |
| - return; |
| - } |
| - |
| - send_buffer_.erase(send_buffer_.begin(), |
| - send_buffer_.begin() + result); |
| - |
| - if (!send_buffer_.empty()) |
| - SSLWriteCallback(this, NULL, NULL); |
| + return NetErrorFromOSStatus(status); |
| } |
| int SSLClientSocketMac::DoPayloadRead() { |
| size_t processed = 0; |
| OSStatus status = SSLRead(ssl_context_, |
| - user_buf_->data(), |
| - user_buf_len_, |
| + user_read_buf_->data(), |
| + user_read_buf_len_, |
| &processed); |
| // There's a subtle difference here in semantics of the "would block" errors. |
| @@ -731,17 +754,14 @@ int SSLClientSocketMac::DoPayloadRead() { |
| return OK; |
| } |
| - if (status == errSSLWouldBlock) |
| - next_state_ = STATE_PAYLOAD_READ; |
| - |
| return NetErrorFromOSStatus(status); |
| } |
| int SSLClientSocketMac::DoPayloadWrite() { |
| size_t processed = 0; |
| OSStatus status = SSLWrite(ssl_context_, |
| - user_buf_->data(), |
| - user_buf_len_, |
| + user_write_buf_->data(), |
| + user_write_buf_len_, |
| &processed); |
| if (processed > 0) |
| @@ -783,8 +803,8 @@ int SSLClientSocketMac::DoPayloadWrite() { |
| // When executing a read, we pass a pointer to the beginning of the tail slop |
| // area (guaranteed to be contiguous space because it's a vector, unlike, say, a |
| // deque (sigh)) and the size of the tail slop. When we get data (either here in |
| -// SSLReadCallback() or above in DoReadComplete()) we subtract the number of |
| -// bytes received from the tail slop value. That moves those bytes |
| +// SSLReadCallback() or above in OnTransportReadComplete()) we subtract the |
| +// number of bytes received from the tail slop value. That moves those bytes |
| // (conceptually, not physically) from the tail slop area to the area containing |
| // real data. |
| // |
| @@ -834,7 +854,7 @@ OSStatus SSLClientSocketMac::SSLReadCallback(SSLConnectionRef connection, |
| // If we have I/O in flight, promise we'll get back to them and use the |
| // existing callback to do so |
| - if (us->next_io_state_ == STATE_READ_COMPLETE) { |
| + if (us->read_io_buf_) { |
| *data_length = 0; |
| return errSSLWouldBlock; |
| } |
| @@ -857,7 +877,7 @@ OSStatus SSLClientSocketMac::SSLReadCallback(SSLConnectionRef connection, |
| us->read_io_buf_ = new IOBuffer(*data_length - total_read); |
| rv = us->transport_->Read(us->read_io_buf_, |
| *data_length - total_read, |
| - &us->io_callback_); |
| + &us->transport_read_callback_); |
| if (rv >= 0) { |
| memcpy(buffer, us->read_io_buf_->data(), rv); |
| @@ -883,11 +903,8 @@ OSStatus SSLClientSocketMac::SSLReadCallback(SSLConnectionRef connection, |
| } |
| } |
| - if (rv == ERR_IO_PENDING) { |
| - us->next_io_state_ = STATE_READ_COMPLETE; |
| - } else { |
| + if (rv != ERR_IO_PENDING) |
| us->read_io_buf_ = NULL; |
| - } |
| if (rv < 0) |
| return OSStatusFromNetError(rv); |
| @@ -932,7 +949,7 @@ OSStatus SSLClientSocketMac::SSLWriteCallback(SSLConnectionRef connection, |
| memcpy(buffer->data(), &us->send_buffer_[0], us->send_buffer_.size()); |
| rv = us->transport_->Write(buffer, |
| us->send_buffer_.size(), |
| - &us->write_callback_); |
| + &us->transport_write_callback_); |
| if (rv > 0) { |
| us->send_buffer_.erase(us->send_buffer_.begin(), |
| us->send_buffer_.begin() + rv); |