summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authoravi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-06 14:52:59 +0000
committeravi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-06 14:52:59 +0000
commitd50dc06dea8fe7313b9cad9310dc6c5b7fe9852f (patch)
tree78d10b96d7257fd4745c47e6651626c336f06920 /net
parent77d34185cb7b5c11a4a0a9bc0e9b74b76e95f338 (diff)
downloadchromium_src-d50dc06dea8fe7313b9cad9310dc6c5b7fe9852f.zip
chromium_src-d50dc06dea8fe7313b9cad9310dc6c5b7fe9852f.tar.gz
chromium_src-d50dc06dea8fe7313b9cad9310dc6c5b7fe9852f.tar.bz2
Improve Mac SSL code:
- Ensure that when OnTransportWriteComplete calls back to SSLWriteCallback, SSLWriteCallback doesn't think that a write is in progress (it _was_, but now it's complete and has to be done again). - Remove all the "slop" variables; they're not needed now that we have independent IOBuffers to call back to our transport. BUG=http://crbug.com/21268 TEST=as in bug Review URL: http://codereview.chromium.org/371008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@31227 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/socket/ssl_client_socket_mac.cc137
-rw-r--r--net/socket/ssl_client_socket_mac.h11
2 files changed, 27 insertions, 121 deletions
diff --git a/net/socket/ssl_client_socket_mac.cc b/net/socket/ssl_client_socket_mac.cc
index 1e9a96c..95538fa 100644
--- a/net/socket/ssl_client_socket_mac.cc
+++ b/net/socket/ssl_client_socket_mac.cc
@@ -318,9 +318,7 @@ SSLClientSocketMac::SSLClientSocketMac(ClientSocket* transport_socket,
completed_handshake_(false),
handshake_interrupted_(false),
ssl_context_(NULL),
- pending_send_error_(OK),
- recv_buffer_head_slop_(0),
- recv_buffer_tail_slop_(0) {
+ pending_send_error_(OK) {
}
SSLClientSocketMac::~SSLClientSocketMac() {
@@ -601,10 +599,9 @@ void SSLClientSocketMac::OnHandshakeIOComplete(int result) {
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;
+ recv_buffer_.insert(recv_buffer_.end(),
+ read_io_buf_->data(),
+ read_io_buf_->data() + result);
}
read_io_buf_ = NULL;
@@ -629,12 +626,15 @@ void SSLClientSocketMac::OnTransportReadComplete(int result) {
}
void SSLClientSocketMac::OnTransportWriteComplete(int result) {
+ write_io_buf_ = NULL;
+
if (result < 0) {
pending_send_error_ = result;
return;
}
+
send_buffer_.erase(send_buffer_.begin(),
- send_buffer_.begin() + result);
+ send_buffer_.begin() + result);
if (!send_buffer_.empty())
SSLWriteCallback(this, NULL, NULL);
@@ -797,77 +797,6 @@ int SSLClientSocketMac::DoPayloadWrite() {
return NetErrorFromOSStatus(status);
}
-// Handling the reading from the network is one of those things that should be
-// simpler than it is. Ideally, we'd have some kind of ring buffer. For now, a
-// std::vector<char> will have to do.
-//
-// The need for a buffer at all comes from the difference between an
-// asynchronous connection (which is what we have) and a non-blocking connection
-// (which is what we fake for Secure Transport). When Secure Transport calls us
-// to read data, we call our underlying transport, which will likely tell us
-// that it'll do a callback. When that happens, we need to tell Secure Transport
-// that we've "blocked". When the callback happens, we have a chunk of data that
-// we need to feed to Secure Transport, but it's not interested. It'll ask for
-// it again when we call it again, so we need to hold on to the data.
-//
-// Why keep our own buffer? Well, when we execute a read and the underlying
-// transport says that it'll do a callback, it keeps the pointer to the
-// buffer. We can't pass it the buffer that Secure Transport gave us to fill, as
-// we can't guarantee its lifetime.
-//
-// The basic idea, then, is this: we have a buffer filled with the data that
-// we've read from the network but haven't given to Secure Transport
-// yet. Whenever we read from the network the first thing we do is ensure we
-// have enough room in the buffer for the read. We enlarge the buffer to be big
-// enough to hold both our existing data and the new data, and then we mark the
-// extra space at the end as "tail slop." Slop is just space at the ends of the
-// buffer that's going to be used for data but isn't (yet). A diagram:
-//
-// +--------------------------------------+--------------------------------+
-// | existing good data ~~~~~~~~~~~~~~~~~ | tail slop area ~~~~~~~~~~~~~~~ |
-// +--------------------------------------+--------------------------------+
-//
-// 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 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.
-//
-// The idea is still pretty simple. We enlarge the tail slop, call our
-// underlying network, get data, shrink the slop area to match, copy requested
-// data back into our caller's buffer, and delete the data from the head of the
-// vector.
-//
-// Except for a nasty little problem. Asynchronous I/O calls keep the buffer
-// pointer.
-//
-// This leads to the following scenario: we have a few bytes of good data in our
-// buffer. But our caller requests more than that. We oblige by enlarging the
-// tail slop, and calling our underlying provider, but the provider says that
-// it'll call us back later. So we shrug our shoulders, copy what we do have
-// into our caller's buffer and...
-//
-// Wait. We can't delete the data from the head of our vector. That would
-// invalidate the pointer that we just gave to our provider. So instead, in that
-// case we keep track of where the good data starts by keeping a "head slop"
-// value, which just notes what data we've already sent and that is useless to
-// us but that we can't delete because we have I/O in flight depending on us
-// leaving the buffer alone.
-//
-// I hear what you're saying. "We need to use a ring buffer!" You write it,
-// then, and I'll use it. Here are the features it needs. First, it needs to be
-// able to have contiguous segments of arbitrary length attached to it to create
-// read buffers. Second, each of those segments must have a "used" length
-// indicator, so if it was half-filled by a previous data read, but the next
-// data read is for more than there's space left, a new segment can be created
-// for the new read without leaving an internal gap.
-//
-// Get to it.
-//
-// (sigh) Who am I kidding? TODO(avi): write the aforementioned ring buffer
-
// static
OSStatus SSLClientSocketMac::SSLReadCallback(SSLConnectionRef connection,
void* data,
@@ -878,56 +807,35 @@ OSStatus SSLClientSocketMac::SSLReadCallback(SSLConnectionRef connection,
const_cast<SSLClientSocketMac*>(
static_cast<const SSLClientSocketMac*>(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->read_io_buf_) {
+ // We have I/O in flight; promise we'll get back to them and use the
+ // existing callback to do so.
*data_length = 0;
return errSSLWouldBlock;
}
- // Start with what's in the buffer
-
- size_t total_read = us->recv_buffer_.size() - us->recv_buffer_head_slop_ -
- us->recv_buffer_tail_slop_;
-
- // Resize the buffer if needed
-
- if (us->recv_buffer_.size() - us->recv_buffer_head_slop_ < *data_length) {
- us->recv_buffer_.resize(us->recv_buffer_head_slop_ + *data_length);
- us->recv_buffer_tail_slop_ = *data_length - total_read;
- }
+ size_t total_read = us->recv_buffer_.size();
int rv = 1; // any old value to spin the loop below
while (rv > 0 && total_read < *data_length) {
- char* buffer = &us->recv_buffer_[us->recv_buffer_head_slop_ + total_read];
us->read_io_buf_ = new IOBuffer(*data_length - total_read);
rv = us->transport_->Read(us->read_io_buf_,
*data_length - total_read,
&us->transport_read_callback_);
if (rv >= 0) {
- memcpy(buffer, us->read_io_buf_->data(), rv);
+ us->recv_buffer_.insert(us->recv_buffer_.end(),
+ us->read_io_buf_->data(),
+ us->read_io_buf_->data() + rv);
us->read_io_buf_ = NULL;
total_read += rv;
- us->recv_buffer_tail_slop_ -= rv;
}
}
*data_length = total_read;
if (total_read) {
- memcpy(data, &us->recv_buffer_[us->recv_buffer_head_slop_], total_read);
- if (rv == ERR_IO_PENDING) {
- // We have I/O in flight which is going to land in our buffer. We can't
- // shuffle things around, so we need to just fiddle with pointers.
- us->recv_buffer_head_slop_ += total_read;
- } else {
- us->recv_buffer_.erase(us->recv_buffer_.begin(),
- us->recv_buffer_.begin() +
- total_read +
- us->recv_buffer_head_slop_);
- us->recv_buffer_head_slop_ = 0;
- }
+ memcpy(data, &us->recv_buffer_[0], total_read);
+ us->recv_buffer_.clear();
}
if (rv != ERR_IO_PENDING)
@@ -955,14 +863,12 @@ OSStatus SSLClientSocketMac::SSLWriteCallback(SSLConnectionRef connection,
return status;
}
- bool send_pending = !us->send_buffer_.empty();
-
if (data)
us->send_buffer_.insert(us->send_buffer_.end(),
static_cast<const char*>(data),
static_cast<const char*>(data) + *data_length);
- if (send_pending) {
+ if (us->write_io_buf_) {
// If we have I/O in flight, just add the data to the end of the buffer and
// return to our caller. The existing callback will trigger the write of the
// new data when it sees that data remains in the buffer after removing the
@@ -972,18 +878,21 @@ OSStatus SSLClientSocketMac::SSLWriteCallback(SSLConnectionRef connection,
int rv;
do {
- scoped_refptr<IOBuffer> buffer = new IOBuffer(us->send_buffer_.size());
- memcpy(buffer->data(), &us->send_buffer_[0], us->send_buffer_.size());
- rv = us->transport_->Write(buffer,
+ us->write_io_buf_ = new IOBuffer(us->send_buffer_.size());
+ memcpy(us->write_io_buf_->data(), &us->send_buffer_[0],
+ us->send_buffer_.size());
+ rv = us->transport_->Write(us->write_io_buf_,
us->send_buffer_.size(),
&us->transport_write_callback_);
if (rv > 0) {
us->send_buffer_.erase(us->send_buffer_.begin(),
us->send_buffer_.begin() + rv);
+ us->write_io_buf_ = NULL;
}
} while (rv > 0 && !us->send_buffer_.empty());
if (rv < 0 && rv != ERR_IO_PENDING) {
+ us->write_io_buf_ = NULL;
return OSStatusFromNetError(rv);
}
diff --git a/net/socket/ssl_client_socket_mac.h b/net/socket/ssl_client_socket_mac.h
index c99ef8b..a520abc 100644
--- a/net/socket/ssl_client_socket_mac.h
+++ b/net/socket/ssl_client_socket_mac.h
@@ -114,18 +114,15 @@ class SSLClientSocketMac : public SSLClientSocket {
bool handshake_interrupted_;
SSLContextRef ssl_context_;
- // These are buffers for holding data during I/O. The "slop" is the amount of
- // space at the ends of the receive buffer that are allocated for holding data
- // but don't (yet).
+ // These buffers hold data retrieved from/sent to the underlying transport
+ // before it's fed to the SSL engine.
std::vector<char> send_buffer_;
int pending_send_error_;
std::vector<char> recv_buffer_;
- int recv_buffer_head_slop_;
- int recv_buffer_tail_slop_;
- // This buffer holds data for Read() operations on the underlying transport
- // (ClientSocket::Read()).
+ // These are the IOBuffers used for operations on the underlying transport.
scoped_refptr<IOBuffer> read_io_buf_;
+ scoped_refptr<IOBuffer> write_io_buf_;
scoped_refptr<LoadLog> load_log_;
};