diff options
author | mbelshe@google.com <mbelshe@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-11 22:04:22 +0000 |
---|---|---|
committer | mbelshe@google.com <mbelshe@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-11 22:04:22 +0000 |
commit | 584460dac4ee02b146000be533fb4cc8cb2ab108 (patch) | |
tree | 1d13471bf7add3ff4d0bd1f6be678b31bdfa746a /net/socket/socket_test_util.cc | |
parent | 0e5a729239c4be751a5c582249b943243c5b3e60 (diff) | |
download | chromium_src-584460dac4ee02b146000be533fb4cc8cb2ab108.zip chromium_src-584460dac4ee02b146000be533fb4cc8cb2ab108.tar.gz chromium_src-584460dac4ee02b146000be533fb4cc8cb2ab108.tar.bz2 |
Enable async IO completions on MockSockets through the
SocketDataProvider.
This makes a few changes:
- The SocketDataProvider::GetNextRead() is now allowed to return a
result of ERR_IO_PENDING. Previously, this was just an error. Now,
this informs the MockClientSocket using the SocketDataProvider that
the Mock IO will be completely asynchronously.
- MockClientSocket implements a new method called OnReadComplete().
This method is used to asynchronously complete a Read from the
SocketDataProvider. The MockClientSocket, after receiving ERR_IO_PENDING
from SocketDataProvider::GetNextRead will be blocked until this
call is made.
The rest of the patch is just refactoring the MockTCPClientSocket
to implement a true async-io simulation. It needs to record the
user buffer from the initial read, and then fill it when the data
is provided.
BUG=none
TEST=<this is for better testing>
Review URL: http://codereview.chromium.org/392003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@31723 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/socket/socket_test_util.cc')
-rw-r--r-- | net/socket/socket_test_util.cc | 100 |
1 files changed, 79 insertions, 21 deletions
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc index 8b7fcbf..239a81d 100644 --- a/net/socket/socket_test_util.cc +++ b/net/socket/socket_test_util.cc @@ -67,7 +67,10 @@ MockTCPClientSocket::MockTCPClientSocket(const net::AddressList& addresses, data_(data), read_offset_(0), read_data_(true, net::ERR_UNEXPECTED), - need_read_data_(true) { + need_read_data_(true), + pending_buf_(NULL), + pending_buf_len_(0), + pending_callback_(NULL) { DCHECK(data_); data_->Reset(); } @@ -89,11 +92,77 @@ int MockTCPClientSocket::Read(net::IOBuffer* buf, int buf_len, if (!IsConnected()) return net::ERR_UNEXPECTED; + // If the buffer is already in use, a read is already in progress! + DCHECK(pending_buf_ == NULL); + + // Store our async IO data. + pending_buf_ = buf; + pending_buf_len_ = buf_len; + pending_callback_ = callback; + if (need_read_data_) { read_data_ = data_->GetNextRead(); + // ERR_IO_PENDING means that the SocketDataProvider is taking responsibility + // to complete the async IO manually later (via OnReadComplete). + if (read_data_.result == ERR_IO_PENDING) { + DCHECK(callback); // We need to be using async IO in this case. + return ERR_IO_PENDING; + } need_read_data_ = false; } + + return CompleteRead(); +} + +int MockTCPClientSocket::Write(net::IOBuffer* buf, int buf_len, + net::CompletionCallback* callback) { + DCHECK(buf); + DCHECK_GT(buf_len, 0); + + if (!IsConnected()) + return net::ERR_UNEXPECTED; + + std::string data(buf->data(), buf_len); + net::MockWriteResult write_result = data_->OnWrite(data); + + if (write_result.async) { + RunCallbackAsync(callback, write_result.result); + return net::ERR_IO_PENDING; + } + return write_result.result; +} + +void MockTCPClientSocket::OnReadComplete(const MockRead& data) { + // There must be a read pending. + DCHECK(pending_buf_); + // You can't complete a read with another ERR_IO_PENDING status code. + DCHECK_NE(ERR_IO_PENDING, data.result); + // Since we've been waiting for data, need_read_data_ should be true. + DCHECK(need_read_data_); + // In order to fire the callback, this IO needs to be marked as async. + DCHECK(data.async); + + read_data_ = data; + need_read_data_ = false; + + CompleteRead(); +} + +int MockTCPClientSocket::CompleteRead() { + DCHECK(pending_buf_); + DCHECK(pending_buf_len_ > 0); + + // Save the pending async IO data and reset our |pending_| state. + net::IOBuffer* buf = pending_buf_; + int buf_len = pending_buf_len_; + net::CompletionCallback* callback = pending_callback_; + pending_buf_ = NULL; + pending_buf_len_ = 0; + pending_callback_ = NULL; + int result = read_data_.result; + DCHECK(result != ERR_IO_PENDING); + if (read_data_.data) { if (read_data_.data_len - read_offset_ > 0) { result = std::min(buf_len, read_data_.data_len - read_offset_); @@ -107,31 +176,15 @@ int MockTCPClientSocket::Read(net::IOBuffer* buf, int buf_len, result = 0; // EOF } } + if (read_data_.async) { + DCHECK(callback); RunCallbackAsync(callback, result); return net::ERR_IO_PENDING; } return result; } -int MockTCPClientSocket::Write(net::IOBuffer* buf, int buf_len, - net::CompletionCallback* callback) { - DCHECK(buf); - DCHECK_GT(buf_len, 0); - - if (!IsConnected()) - return net::ERR_UNEXPECTED; - - std::string data(buf->data(), buf_len); - net::MockWriteResult write_result = data_->OnWrite(data); - - if (write_result.async) { - RunCallbackAsync(callback, write_result.result); - return net::ERR_IO_PENDING; - } - return write_result.result; -} - class MockSSLClientSocket::ConnectCallback : public net::CompletionCallbackImpl<MockSSLClientSocket::ConnectCallback> { public: @@ -212,7 +265,10 @@ int MockSSLClientSocket::Write(net::IOBuffer* buf, int buf_len, } MockRead StaticSocketDataProvider::GetNextRead() { - return reads_[read_index_++]; + MockRead rv = reads_[read_index_]; + if (reads_[read_index_].data_len != 0) + read_index_++; // Don't advance past an EOF. + return rv; } MockWriteResult StaticSocketDataProvider::OnWrite(const std::string& data) { @@ -298,8 +354,10 @@ MockSSLClientSocket* MockClientSocketFactory::GetMockSSLClientSocket( ClientSocket* MockClientSocketFactory::CreateTCPClientSocket( const AddressList& addresses) { + SocketDataProvider* data_provider = mock_data_.GetNext(); MockTCPClientSocket* socket = - new MockTCPClientSocket(addresses, mock_data_.GetNext()); + new MockTCPClientSocket(addresses, data_provider); + data_provider->set_socket(socket); tcp_client_sockets_.push_back(socket); return socket; } |