Index: net/socket/socket_test_util.cc |
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc |
index a7bebed41d8d257588265780a909d937a30e79e7..d5ee9ae6470d9623d84e42dd472f88457a409b8d 100644 |
--- a/net/socket/socket_test_util.cc |
+++ b/net/socket/socket_test_util.cc |
@@ -116,977 +116,981 @@ void DumpMockRead(const MockRead& r) { |
} // namespace |
-MockClientSocket::MockClientSocket(net::NetLog* net_log) |
- : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)), |
- connected_(false), |
- net_log_(NetLog::Source(), net_log) { |
-} |
- |
-void MockClientSocket::GetSSLInfo(net::SSLInfo* ssl_info) { |
- NOTREACHED(); |
+StaticSocketDataProvider::StaticSocketDataProvider() |
+ : reads_(NULL), |
+ read_index_(0), |
+ read_count_(0), |
+ writes_(NULL), |
+ write_index_(0), |
+ write_count_(0) { |
} |
-void MockClientSocket::GetSSLCertRequestInfo( |
- net::SSLCertRequestInfo* cert_request_info) { |
+StaticSocketDataProvider::StaticSocketDataProvider(MockRead* reads, |
+ size_t reads_count, |
+ MockWrite* writes, |
+ size_t writes_count) |
+ : reads_(reads), |
+ read_index_(0), |
+ read_count_(reads_count), |
+ writes_(writes), |
+ write_index_(0), |
+ write_count_(writes_count) { |
} |
-SSLClientSocket::NextProtoStatus |
-MockClientSocket::GetNextProto(std::string* proto) { |
- proto->clear(); |
- return SSLClientSocket::kNextProtoUnsupported; |
-} |
+StaticSocketDataProvider::~StaticSocketDataProvider() {} |
-void MockClientSocket::Disconnect() { |
- connected_ = false; |
+const MockRead& StaticSocketDataProvider::PeekRead() const { |
+ DCHECK(!at_read_eof()); |
+ return reads_[read_index_]; |
} |
-bool MockClientSocket::IsConnected() const { |
- return connected_; |
+const MockWrite& StaticSocketDataProvider::PeekWrite() const { |
+ DCHECK(!at_write_eof()); |
+ return writes_[write_index_]; |
} |
-bool MockClientSocket::IsConnectedAndIdle() const { |
- return connected_; |
+const MockRead& StaticSocketDataProvider::PeekRead(size_t index) const { |
+ DCHECK_LT(index, read_count_); |
+ return reads_[index]; |
} |
-int MockClientSocket::GetPeerAddress(AddressList* address) const { |
- return net::SystemHostResolverProc("localhost", ADDRESS_FAMILY_UNSPECIFIED, |
- 0, address, NULL); |
+const MockWrite& StaticSocketDataProvider::PeekWrite(size_t index) const { |
+ DCHECK_LT(index, write_count_); |
+ return writes_[index]; |
} |
-void MockClientSocket::RunCallbackAsync(net::CompletionCallback* callback, |
- int result) { |
- MessageLoop::current()->PostTask(FROM_HERE, |
- method_factory_.NewRunnableMethod( |
- &MockClientSocket::RunCallback, callback, result)); |
+MockRead StaticSocketDataProvider::GetNextRead() { |
+ DCHECK(!at_read_eof()); |
+ reads_[read_index_].time_stamp = base::Time::Now(); |
+ return reads_[read_index_++]; |
} |
-void MockClientSocket::RunCallback(net::CompletionCallback* callback, |
- int result) { |
- if (callback) |
- callback->Run(result); |
-} |
+MockWriteResult StaticSocketDataProvider::OnWrite(const std::string& data) { |
+ if (!writes_) { |
+ // Not using mock writes; succeed synchronously. |
+ return MockWriteResult(false, data.length()); |
+ } |
-MockTCPClientSocket::MockTCPClientSocket(const net::AddressList& addresses, |
- net::NetLog* net_log, |
- net::SocketDataProvider* data) |
- : MockClientSocket(net_log), |
- addresses_(addresses), |
- data_(data), |
- read_offset_(0), |
- read_data_(false, net::ERR_UNEXPECTED), |
- need_read_data_(true), |
- peer_closed_connection_(false), |
- pending_buf_(NULL), |
- pending_buf_len_(0), |
- pending_callback_(NULL), |
- was_used_to_convey_data_(false) { |
- DCHECK(data_); |
- data_->Reset(); |
-} |
+ DCHECK(!at_write_eof()); |
-int MockTCPClientSocket::Connect(net::CompletionCallback* callback) { |
- if (connected_) |
- return net::OK; |
- connected_ = true; |
- peer_closed_connection_ = false; |
- if (data_->connect_data().async) { |
- RunCallbackAsync(callback, data_->connect_data().result); |
- return net::ERR_IO_PENDING; |
+ // Check that what we are writing matches the expectation. |
+ // Then give the mocked return value. |
+ net::MockWrite* w = &writes_[write_index_++]; |
+ w->time_stamp = base::Time::Now(); |
+ int result = w->result; |
+ if (w->data) { |
+ // Note - we can simulate a partial write here. If the expected data |
+ // is a match, but shorter than the write actually written, that is legal. |
+ // Example: |
+ // Application writes "foobarbaz" (9 bytes) |
+ // Expected write was "foo" (3 bytes) |
+ // This is a success, and we return 3 to the application. |
+ std::string expected_data(w->data, w->data_len); |
+ EXPECT_GE(data.length(), expected_data.length()); |
+ std::string actual_data(data.substr(0, w->data_len)); |
+ EXPECT_EQ(expected_data, actual_data); |
+ if (expected_data != actual_data) |
+ return MockWriteResult(false, net::ERR_UNEXPECTED); |
+ if (result == net::OK) |
+ result = w->data_len; |
} |
- return data_->connect_data().result; |
+ return MockWriteResult(w->async, result); |
} |
-void MockTCPClientSocket::Disconnect() { |
- MockClientSocket::Disconnect(); |
- pending_callback_ = NULL; |
+void StaticSocketDataProvider::Reset() { |
+ read_index_ = 0; |
+ write_index_ = 0; |
} |
-bool MockTCPClientSocket::IsConnected() const { |
- return connected_ && !peer_closed_connection_; |
+DynamicSocketDataProvider::DynamicSocketDataProvider() |
+ : short_read_limit_(0), |
+ allow_unconsumed_reads_(false) { |
} |
-int MockTCPClientSocket::Read(net::IOBuffer* buf, int buf_len, |
- net::CompletionCallback* callback) { |
- if (!connected_) |
- 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; |
+DynamicSocketDataProvider::~DynamicSocketDataProvider() {} |
- if (need_read_data_) { |
- read_data_ = data_->GetNextRead(); |
- if (read_data_.result == ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ) { |
- // This MockRead is just a marker to instruct us to set |
- // peer_closed_connection_. Skip it and get the next one. |
- read_data_ = data_->GetNextRead(); |
- peer_closed_connection_ = true; |
- } |
- // 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; |
+MockRead DynamicSocketDataProvider::GetNextRead() { |
+ if (reads_.empty()) |
+ return MockRead(false, ERR_UNEXPECTED); |
+ MockRead result = reads_.front(); |
+ if (short_read_limit_ == 0 || result.data_len <= short_read_limit_) { |
+ reads_.pop_front(); |
+ } else { |
+ result.data_len = short_read_limit_; |
+ reads_.front().data += result.data_len; |
+ reads_.front().data_len -= result.data_len; |
} |
- |
- return CompleteRead(); |
+ return result; |
} |
-int MockTCPClientSocket::Write(net::IOBuffer* buf, int buf_len, |
- net::CompletionCallback* callback) { |
- DCHECK(buf); |
- DCHECK_GT(buf_len, 0); |
- |
- if (!connected_) |
- return net::ERR_UNEXPECTED; |
- |
- std::string data(buf->data(), buf_len); |
- net::MockWriteResult write_result = data_->OnWrite(data); |
- |
- was_used_to_convey_data_ = true; |
+void DynamicSocketDataProvider::Reset() { |
+ reads_.clear(); |
+} |
- if (write_result.async) { |
- RunCallbackAsync(callback, write_result.result); |
- return net::ERR_IO_PENDING; |
+void DynamicSocketDataProvider::SimulateRead(const char* data, |
+ const size_t length) { |
+ if (!allow_unconsumed_reads_) { |
+ EXPECT_TRUE(reads_.empty()) << "Unconsumed read: " << reads_.front().data; |
} |
+ reads_.push_back(MockRead(true, data, length)); |
+} |
- return write_result.result; |
+DelayedSocketData::DelayedSocketData( |
+ int write_delay, MockRead* reads, size_t reads_count, |
+ MockWrite* writes, size_t writes_count) |
+ : StaticSocketDataProvider(reads, reads_count, writes, writes_count), |
+ write_delay_(write_delay), |
+ ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) { |
+ DCHECK_GE(write_delay_, 0); |
} |
-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_); |
+DelayedSocketData::DelayedSocketData( |
+ const MockConnect& connect, int write_delay, MockRead* reads, |
+ size_t reads_count, MockWrite* writes, size_t writes_count) |
+ : StaticSocketDataProvider(reads, reads_count, writes, writes_count), |
+ write_delay_(write_delay), |
+ ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) { |
+ DCHECK_GE(write_delay_, 0); |
+ set_connect_data(connect); |
+} |
- read_data_ = data; |
- need_read_data_ = false; |
+DelayedSocketData::~DelayedSocketData() { |
+} |
- // The caller is simulating that this IO completes right now. Don't |
- // let CompleteRead() schedule a callback. |
- read_data_.async = false; |
+void DelayedSocketData::ForceNextRead() { |
+ write_delay_ = 0; |
+ CompleteRead(); |
+} |
- net::CompletionCallback* callback = pending_callback_; |
- int rv = CompleteRead(); |
- RunCallback(callback, rv); |
+MockRead DelayedSocketData::GetNextRead() { |
+ if (write_delay_ > 0) |
+ return MockRead(true, ERR_IO_PENDING); |
+ return StaticSocketDataProvider::GetNextRead(); |
} |
-int MockTCPClientSocket::CompleteRead() { |
- DCHECK(pending_buf_); |
- DCHECK(pending_buf_len_ > 0); |
+MockWriteResult DelayedSocketData::OnWrite(const std::string& data) { |
+ MockWriteResult rv = StaticSocketDataProvider::OnWrite(data); |
+ // Now that our write has completed, we can allow reads to continue. |
+ if (!--write_delay_) |
+ MessageLoop::current()->PostDelayedTask(FROM_HERE, |
+ factory_.NewRunnableMethod(&DelayedSocketData::CompleteRead), 100); |
+ return rv; |
+} |
- was_used_to_convey_data_ = true; |
+void DelayedSocketData::Reset() { |
+ set_socket(NULL); |
+ factory_.RevokeAll(); |
+ StaticSocketDataProvider::Reset(); |
+} |
- // 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; |
+void DelayedSocketData::CompleteRead() { |
+ if (socket()) |
+ socket()->OnReadComplete(GetNextRead()); |
+} |
- int result = read_data_.result; |
- DCHECK(result != ERR_IO_PENDING); |
+OrderedSocketData::OrderedSocketData( |
+ MockRead* reads, size_t reads_count, MockWrite* writes, size_t writes_count) |
+ : StaticSocketDataProvider(reads, reads_count, writes, writes_count), |
+ sequence_number_(0), loop_stop_stage_(0), callback_(NULL), |
+ blocked_(false), ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) { |
+} |
- if (read_data_.data) { |
- if (read_data_.data_len - read_offset_ > 0) { |
- result = std::min(buf_len, read_data_.data_len - read_offset_); |
- memcpy(buf->data(), read_data_.data + read_offset_, result); |
- read_offset_ += result; |
- if (read_offset_ == read_data_.data_len) { |
- need_read_data_ = true; |
- read_offset_ = 0; |
- } |
+OrderedSocketData::OrderedSocketData( |
+ const MockConnect& connect, |
+ MockRead* reads, size_t reads_count, |
+ MockWrite* writes, size_t writes_count) |
+ : StaticSocketDataProvider(reads, reads_count, writes, writes_count), |
+ sequence_number_(0), loop_stop_stage_(0), callback_(NULL), |
+ blocked_(false), ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) { |
+ set_connect_data(connect); |
+} |
+ |
+void OrderedSocketData::EndLoop() { |
+ // If we've already stopped the loop, don't do it again until we've advanced |
+ // to the next sequence_number. |
+ NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_ << ": EndLoop()"; |
+ if (loop_stop_stage_ > 0) { |
+ const MockRead& next_read = StaticSocketDataProvider::PeekRead(); |
+ if ((next_read.sequence_number & ~MockRead::STOPLOOP) > |
+ loop_stop_stage_) { |
+ NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_ |
+ << ": Clearing stop index"; |
+ loop_stop_stage_ = 0; |
} else { |
- result = 0; // EOF |
+ return; |
} |
} |
+ // Record the sequence_number at which we stopped the loop. |
+ NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_ |
+ << ": Posting Quit at read " << read_index(); |
+ loop_stop_stage_ = sequence_number_; |
+ if (callback_) |
+ callback_->RunWithParams(Tuple1<int>(ERR_IO_PENDING)); |
+} |
- if (read_data_.async) { |
- DCHECK(callback); |
- RunCallbackAsync(callback, result); |
- return net::ERR_IO_PENDING; |
+MockRead OrderedSocketData::GetNextRead() { |
+ factory_.RevokeAll(); |
+ blocked_ = false; |
+ const MockRead& next_read = StaticSocketDataProvider::PeekRead(); |
+ if (next_read.sequence_number & MockRead::STOPLOOP) |
+ EndLoop(); |
+ if ((next_read.sequence_number & ~MockRead::STOPLOOP) <= |
+ sequence_number_++) { |
+ NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_ - 1 |
+ << ": Read " << read_index(); |
+ DumpMockRead(next_read); |
+ return StaticSocketDataProvider::GetNextRead(); |
} |
+ NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_ - 1 |
+ << ": I/O Pending"; |
+ MockRead result = MockRead(true, ERR_IO_PENDING); |
+ DumpMockRead(result); |
+ blocked_ = true; |
return result; |
} |
-DeterministicMockTCPClientSocket::DeterministicMockTCPClientSocket( |
- net::NetLog* net_log, net::DeterministicSocketData* data) |
- : MockClientSocket(net_log), |
- write_pending_(false), |
- write_callback_(NULL), |
- write_result_(0), |
- read_data_(), |
- read_buf_(NULL), |
- read_buf_len_(0), |
- read_pending_(false), |
- read_callback_(NULL), |
- data_(data), |
- was_used_to_convey_data_(false) {} |
- |
-void DeterministicMockTCPClientSocket::OnReadComplete(const MockRead& data) {} |
- |
-// TODO(erikchen): Support connect sequencing. |
-int DeterministicMockTCPClientSocket::Connect( |
- net::CompletionCallback* callback) { |
- if (connected_) |
- return net::OK; |
- connected_ = true; |
- if (data_->connect_data().async) { |
- RunCallbackAsync(callback, data_->connect_data().result); |
- return net::ERR_IO_PENDING; |
+MockWriteResult OrderedSocketData::OnWrite(const std::string& data) { |
+ NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_ |
+ << ": Write " << write_index(); |
+ DumpMockRead(PeekWrite()); |
+ ++sequence_number_; |
+ if (blocked_) { |
+ // TODO(willchan): This 100ms delay seems to work around some weirdness. We |
+ // should probably fix the weirdness. One example is in SpdyStream, |
+ // DoSendRequest() will return ERR_IO_PENDING, and there's a race. If the |
+ // SYN_REPLY causes OnResponseReceived() to get called before |
+ // SpdyStream::ReadResponseHeaders() is called, we hit a NOTREACHED(). |
+ MessageLoop::current()->PostDelayedTask( |
+ FROM_HERE, |
+ factory_.NewRunnableMethod(&OrderedSocketData::CompleteRead), 100); |
} |
- return data_->connect_data().result; |
+ return StaticSocketDataProvider::OnWrite(data); |
} |
-void DeterministicMockTCPClientSocket::Disconnect() { |
- MockClientSocket::Disconnect(); |
+void OrderedSocketData::Reset() { |
+ NET_TRACE(INFO, " *** ") << "Stage " |
+ << sequence_number_ << ": Reset()"; |
+ sequence_number_ = 0; |
+ loop_stop_stage_ = 0; |
+ set_socket(NULL); |
+ factory_.RevokeAll(); |
+ StaticSocketDataProvider::Reset(); |
} |
-bool DeterministicMockTCPClientSocket::IsConnected() const { |
- return connected_; |
+void OrderedSocketData::CompleteRead() { |
+ if (socket()) { |
+ NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_; |
+ socket()->OnReadComplete(GetNextRead()); |
+ } |
} |
-int DeterministicMockTCPClientSocket::Write( |
- net::IOBuffer* buf, int buf_len, net::CompletionCallback* callback) { |
- DCHECK(buf); |
- DCHECK_GT(buf_len, 0); |
+OrderedSocketData::~OrderedSocketData() {} |
- if (!connected_) |
- return net::ERR_UNEXPECTED; |
+DeterministicSocketData::DeterministicSocketData(MockRead* reads, |
+ size_t reads_count, MockWrite* writes, size_t writes_count) |
+ : StaticSocketDataProvider(reads, reads_count, writes, writes_count), |
+ sequence_number_(0), |
+ current_read_(), |
+ current_write_(), |
+ stopping_sequence_number_(0), |
+ stopped_(false), |
+ print_debug_(false) {} |
- std::string data(buf->data(), buf_len); |
- net::MockWriteResult write_result = data_->OnWrite(data); |
+DeterministicSocketData::~DeterministicSocketData() {} |
- if (write_result.async) { |
- write_callback_ = callback; |
- write_result_ = write_result.result; |
- DCHECK(write_callback_ != NULL); |
- write_pending_ = true; |
- return net::ERR_IO_PENDING; |
+void DeterministicSocketData::Run() { |
+ SetStopped(false); |
+ int counter = 0; |
+ // Continue to consume data until all data has run out, or the stopped_ flag |
+ // has been set. Consuming data requires two separate operations -- running |
+ // the tasks in the message loop, and explicitly invoking the read/write |
+ // callbacks (simulating network I/O). We check our conditions between each, |
+ // since they can change in either. |
+ while ((!at_write_eof() || !at_read_eof()) && !stopped()) { |
+ if (counter % 2 == 0) |
+ MessageLoop::current()->RunAllPending(); |
+ if (counter % 2 == 1) { |
+ InvokeCallbacks(); |
+ } |
+ counter++; |
} |
+ // We're done consuming new data, but it is possible there are still some |
+ // pending callbacks which we expect to complete before returning. |
+ while (socket_ && (socket_->write_pending() || socket_->read_pending()) && |
+ !stopped()) { |
+ InvokeCallbacks(); |
+ MessageLoop::current()->RunAllPending(); |
+ } |
+ SetStopped(false); |
+} |
- was_used_to_convey_data_ = true; |
- write_pending_ = false; |
- return write_result.result; |
+void DeterministicSocketData::RunFor(int steps) { |
+ StopAfter(steps); |
+ Run(); |
} |
-int DeterministicMockTCPClientSocket::Read( |
- net::IOBuffer* buf, int buf_len, net::CompletionCallback* callback) { |
- if (!connected_) |
- return net::ERR_UNEXPECTED; |
+void DeterministicSocketData::SetStop(int seq) { |
+ DCHECK_LT(sequence_number_, seq); |
+ stopping_sequence_number_ = seq; |
+ stopped_ = false; |
+} |
- read_data_ = data_->GetNextRead(); |
- // The buffer should always be big enough to contain all the MockRead data. To |
- // use small buffers, split the data into multiple MockReads. |
- DCHECK_LE(read_data_.data_len, buf_len); |
+void DeterministicSocketData::StopAfter(int seq) { |
+ SetStop(sequence_number_ + seq); |
+} |
- read_buf_ = buf; |
- read_buf_len_ = buf_len; |
- read_callback_ = callback; |
+MockRead DeterministicSocketData::GetNextRead() { |
+ current_read_ = StaticSocketDataProvider::PeekRead(); |
+ EXPECT_LE(sequence_number_, current_read_.sequence_number); |
- if (read_data_.async || (read_data_.result == ERR_IO_PENDING)) { |
- read_pending_ = true; |
- DCHECK(read_callback_); |
- return ERR_IO_PENDING; |
+ // Synchronous read while stopped is an error |
+ if (stopped() && !current_read_.async) { |
+ LOG(ERROR) << "Unable to perform synchronous IO while stopped"; |
+ return MockRead(false, ERR_UNEXPECTED); |
} |
- was_used_to_convey_data_ = true; |
- return CompleteRead(); |
-} |
+ // Async read which will be called back in a future step. |
+ if (sequence_number_ < current_read_.sequence_number) { |
+ NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_ |
+ << ": I/O Pending"; |
+ MockRead result = MockRead(false, ERR_IO_PENDING); |
+ if (!current_read_.async) { |
+ LOG(ERROR) << "Unable to perform synchronous read: " |
+ << current_read_.sequence_number |
+ << " at stage: " << sequence_number_; |
+ result = MockRead(false, ERR_UNEXPECTED); |
+ } |
+ if (print_debug_) |
+ DumpMockRead(result); |
+ return result; |
+ } |
-void DeterministicMockTCPClientSocket::CompleteWrite() { |
- was_used_to_convey_data_ = true; |
- write_pending_ = false; |
- write_callback_->Run(write_result_); |
-} |
+ NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_ |
+ << ": Read " << read_index(); |
+ if (print_debug_) |
+ DumpMockRead(current_read_); |
-int DeterministicMockTCPClientSocket::CompleteRead() { |
- DCHECK_GT(read_buf_len_, 0); |
- DCHECK_LE(read_data_.data_len, read_buf_len_); |
- DCHECK(read_buf_); |
+ // Increment the sequence number if IO is complete |
+ if (!current_read_.async) |
+ NextStep(); |
- was_used_to_convey_data_ = true; |
+ DCHECK_NE(ERR_IO_PENDING, current_read_.result); |
+ StaticSocketDataProvider::GetNextRead(); |
- if (read_data_.result == ERR_IO_PENDING) |
- read_data_ = data_->GetNextRead(); |
- DCHECK_NE(ERR_IO_PENDING, read_data_.result); |
- // If read_data_.async is true, we do not need to wait, since this is already |
- // the callback. Therefore we don't even bother to check it. |
- int result = read_data_.result; |
+ return current_read_; |
+} |
- if (read_data_.data_len > 0) { |
- DCHECK(read_data_.data); |
- result = std::min(read_buf_len_, read_data_.data_len); |
- memcpy(read_buf_->data(), read_data_.data, result); |
+MockWriteResult DeterministicSocketData::OnWrite(const std::string& data) { |
+ const MockWrite& next_write = StaticSocketDataProvider::PeekWrite(); |
+ current_write_ = next_write; |
+ |
+ // Synchronous write while stopped is an error |
+ if (stopped() && !next_write.async) { |
+ LOG(ERROR) << "Unable to perform synchronous IO while stopped"; |
+ return MockWriteResult(false, ERR_UNEXPECTED); |
} |
- if (read_pending_) { |
- read_pending_ = false; |
- read_callback_->Run(result); |
+ // Async write which will be called back in a future step. |
+ if (sequence_number_ < next_write.sequence_number) { |
+ NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_ |
+ << ": I/O Pending"; |
+ if (!next_write.async) { |
+ LOG(ERROR) << "Unable to perform synchronous write: " |
+ << next_write.sequence_number << " at stage: " << sequence_number_; |
+ return MockWriteResult(false, ERR_UNEXPECTED); |
+ } |
+ } else { |
+ NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_ |
+ << ": Write " << write_index(); |
} |
- return result; |
+ if (print_debug_) |
+ DumpMockRead(next_write); |
+ |
+ // Move to the next step if I/O is synchronous, since the operation will |
+ // complete when this method returns. |
+ if (!next_write.async) |
+ NextStep(); |
+ |
+ // This is either a sync write for this step, or an async write. |
+ return StaticSocketDataProvider::OnWrite(data); |
} |
-class MockSSLClientSocket::ConnectCallback |
- : public net::CompletionCallbackImpl<MockSSLClientSocket::ConnectCallback> { |
- public: |
- ConnectCallback(MockSSLClientSocket *ssl_client_socket, |
- net::CompletionCallback* user_callback, |
- int rv) |
- : ALLOW_THIS_IN_INITIALIZER_LIST( |
- net::CompletionCallbackImpl<MockSSLClientSocket::ConnectCallback>( |
- this, &ConnectCallback::Wrapper)), |
- ssl_client_socket_(ssl_client_socket), |
- user_callback_(user_callback), |
- rv_(rv) { |
- } |
+void DeterministicSocketData::Reset() { |
+ NET_TRACE(INFO, " *** ") << "Stage " |
+ << sequence_number_ << ": Reset()"; |
+ sequence_number_ = 0; |
+ StaticSocketDataProvider::Reset(); |
+ NOTREACHED(); |
+} |
- private: |
- void Wrapper(int rv) { |
- if (rv_ == net::OK) |
- ssl_client_socket_->connected_ = true; |
- user_callback_->Run(rv_); |
- delete this; |
+void DeterministicSocketData::InvokeCallbacks() { |
+ if (socket_ && socket_->write_pending() && |
+ (current_write().sequence_number == sequence_number())) { |
+ socket_->CompleteWrite(); |
+ NextStep(); |
+ return; |
+ } |
+ if (socket_ && socket_->read_pending() && |
+ (current_read().sequence_number == sequence_number())) { |
+ socket_->CompleteRead(); |
+ NextStep(); |
+ return; |
} |
+} |
- MockSSLClientSocket* ssl_client_socket_; |
- net::CompletionCallback* user_callback_; |
- int rv_; |
-}; |
+void DeterministicSocketData::NextStep() { |
+ // Invariant: Can never move *past* the stopping step. |
+ DCHECK_LT(sequence_number_, stopping_sequence_number_); |
+ sequence_number_++; |
+ if (sequence_number_ == stopping_sequence_number_) |
+ SetStopped(true); |
+} |
-MockSSLClientSocket::MockSSLClientSocket( |
- net::ClientSocketHandle* transport_socket, |
- const HostPortPair& host_port_pair, |
- const net::SSLConfig& ssl_config, |
- SSLHostInfo* ssl_host_info, |
- net::SSLSocketDataProvider* data) |
- : MockClientSocket(transport_socket->socket()->NetLog().net_log()), |
- transport_(transport_socket), |
- data_(data), |
- is_npn_state_set_(false), |
- new_npn_value_(false) { |
- DCHECK(data_); |
- delete ssl_host_info; // we take ownership but don't use it. |
+MockClientSocketFactory::MockClientSocketFactory() {} |
+ |
+MockClientSocketFactory::~MockClientSocketFactory() {} |
+ |
+void MockClientSocketFactory::AddSocketDataProvider( |
+ SocketDataProvider* data) { |
+ mock_data_.Add(data); |
} |
-MockSSLClientSocket::~MockSSLClientSocket() { |
- Disconnect(); |
+void MockClientSocketFactory::AddSSLSocketDataProvider( |
+ SSLSocketDataProvider* data) { |
+ mock_ssl_data_.Add(data); |
} |
-int MockSSLClientSocket::Connect(net::CompletionCallback* callback) { |
- ConnectCallback* connect_callback = new ConnectCallback( |
- this, callback, data_->connect.result); |
- int rv = transport_->socket()->Connect(connect_callback); |
- if (rv == net::OK) { |
- delete connect_callback; |
- if (data_->connect.result == net::OK) |
- connected_ = true; |
- if (data_->connect.async) { |
- RunCallbackAsync(callback, data_->connect.result); |
- return net::ERR_IO_PENDING; |
- } |
- return data_->connect.result; |
- } |
- return rv; |
+void MockClientSocketFactory::ResetNextMockIndexes() { |
+ mock_data_.ResetNextIndex(); |
+ mock_ssl_data_.ResetNextIndex(); |
} |
-void MockSSLClientSocket::Disconnect() { |
- MockClientSocket::Disconnect(); |
- if (transport_->socket() != NULL) |
- transport_->socket()->Disconnect(); |
+MockTCPClientSocket* MockClientSocketFactory::GetMockTCPClientSocket( |
+ size_t index) const { |
+ DCHECK_LT(index, tcp_client_sockets_.size()); |
+ return tcp_client_sockets_[index]; |
} |
-bool MockSSLClientSocket::IsConnected() const { |
- return transport_->socket()->IsConnected(); |
+MockSSLClientSocket* MockClientSocketFactory::GetMockSSLClientSocket( |
+ size_t index) const { |
+ DCHECK_LT(index, ssl_client_sockets_.size()); |
+ return ssl_client_sockets_[index]; |
} |
-bool MockSSLClientSocket::WasEverUsed() const { |
- return transport_->socket()->WasEverUsed(); |
+ClientSocket* MockClientSocketFactory::CreateTCPClientSocket( |
+ const AddressList& addresses, |
+ net::NetLog* net_log, |
+ const NetLog::Source& source) { |
+ SocketDataProvider* data_provider = mock_data_.GetNext(); |
+ MockTCPClientSocket* socket = |
+ new MockTCPClientSocket(addresses, net_log, data_provider); |
+ data_provider->set_socket(socket); |
+ tcp_client_sockets_.push_back(socket); |
+ return socket; |
} |
-bool MockSSLClientSocket::UsingTCPFastOpen() const { |
- return transport_->socket()->UsingTCPFastOpen(); |
+SSLClientSocket* MockClientSocketFactory::CreateSSLClientSocket( |
+ ClientSocketHandle* transport_socket, |
+ const HostPortPair& host_and_port, |
+ const SSLConfig& ssl_config, |
+ SSLHostInfo* ssl_host_info, |
+ CertVerifier* cert_verifier, |
+ DnsCertProvenanceChecker* dns_cert_checker) { |
+ MockSSLClientSocket* socket = |
+ new MockSSLClientSocket(transport_socket, host_and_port, ssl_config, |
+ ssl_host_info, mock_ssl_data_.GetNext()); |
+ ssl_client_sockets_.push_back(socket); |
+ return socket; |
} |
-int MockSSLClientSocket::Read(net::IOBuffer* buf, int buf_len, |
- net::CompletionCallback* callback) { |
- return transport_->socket()->Read(buf, buf_len, callback); |
+MockClientSocket::MockClientSocket(net::NetLog* net_log) |
+ : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)), |
+ connected_(false), |
+ net_log_(NetLog::Source(), net_log) { |
} |
-int MockSSLClientSocket::Write(net::IOBuffer* buf, int buf_len, |
- net::CompletionCallback* callback) { |
- return transport_->socket()->Write(buf, buf_len, callback); |
+bool MockClientSocket::SetReceiveBufferSize(int32 size) { |
+ return true; |
} |
-void MockSSLClientSocket::GetSSLInfo(net::SSLInfo* ssl_info) { |
- ssl_info->Reset(); |
+bool MockClientSocket::SetSendBufferSize(int32 size) { |
+ return true; |
} |
-void MockSSLClientSocket::GetSSLCertRequestInfo( |
- net::SSLCertRequestInfo* cert_request_info) { |
- DCHECK(cert_request_info); |
- if (data_->cert_request_info) { |
- cert_request_info->host_and_port = |
- data_->cert_request_info->host_and_port; |
- cert_request_info->client_certs = data_->cert_request_info->client_certs; |
- } else { |
- cert_request_info->Reset(); |
- } |
+void MockClientSocket::Disconnect() { |
+ connected_ = false; |
} |
-SSLClientSocket::NextProtoStatus MockSSLClientSocket::GetNextProto( |
- std::string* proto) { |
- *proto = data_->next_proto; |
- return data_->next_proto_status; |
+bool MockClientSocket::IsConnected() const { |
+ return connected_; |
} |
-bool MockSSLClientSocket::was_npn_negotiated() const { |
- if (is_npn_state_set_) |
- return new_npn_value_; |
- return data_->was_npn_negotiated; |
+bool MockClientSocket::IsConnectedAndIdle() const { |
+ return connected_; |
} |
-bool MockSSLClientSocket::set_was_npn_negotiated(bool negotiated) { |
- is_npn_state_set_ = true; |
- return new_npn_value_ = negotiated; |
+int MockClientSocket::GetPeerAddress(AddressList* address) const { |
+ return net::SystemHostResolverProc("localhost", ADDRESS_FAMILY_UNSPECIFIED, |
+ 0, address, NULL); |
} |
-StaticSocketDataProvider::StaticSocketDataProvider() |
- : reads_(NULL), |
- read_index_(0), |
- read_count_(0), |
- writes_(NULL), |
- write_index_(0), |
- write_count_(0) { |
+const BoundNetLog& MockClientSocket::NetLog() const { |
+ return net_log_; |
} |
-StaticSocketDataProvider::StaticSocketDataProvider(MockRead* reads, |
- size_t reads_count, |
- MockWrite* writes, |
- size_t writes_count) |
- : reads_(reads), |
- read_index_(0), |
- read_count_(reads_count), |
- writes_(writes), |
- write_index_(0), |
- write_count_(writes_count) { |
+void MockClientSocket::GetSSLInfo(net::SSLInfo* ssl_info) { |
+ NOTREACHED(); |
} |
-StaticSocketDataProvider::~StaticSocketDataProvider() {} |
+void MockClientSocket::GetSSLCertRequestInfo( |
+ net::SSLCertRequestInfo* cert_request_info) { |
+} |
-MockRead StaticSocketDataProvider::GetNextRead() { |
- DCHECK(!at_read_eof()); |
- reads_[read_index_].time_stamp = base::Time::Now(); |
- return reads_[read_index_++]; |
+SSLClientSocket::NextProtoStatus |
+MockClientSocket::GetNextProto(std::string* proto) { |
+ proto->clear(); |
+ return SSLClientSocket::kNextProtoUnsupported; |
} |
-MockWriteResult StaticSocketDataProvider::OnWrite(const std::string& data) { |
- if (!writes_) { |
- // Not using mock writes; succeed synchronously. |
- return MockWriteResult(false, data.length()); |
- } |
+MockClientSocket::~MockClientSocket() {} |
- DCHECK(!at_write_eof()); |
- |
- // Check that what we are writing matches the expectation. |
- // Then give the mocked return value. |
- net::MockWrite* w = &writes_[write_index_++]; |
- w->time_stamp = base::Time::Now(); |
- int result = w->result; |
- if (w->data) { |
- // Note - we can simulate a partial write here. If the expected data |
- // is a match, but shorter than the write actually written, that is legal. |
- // Example: |
- // Application writes "foobarbaz" (9 bytes) |
- // Expected write was "foo" (3 bytes) |
- // This is a success, and we return 3 to the application. |
- std::string expected_data(w->data, w->data_len); |
- EXPECT_GE(data.length(), expected_data.length()); |
- std::string actual_data(data.substr(0, w->data_len)); |
- EXPECT_EQ(expected_data, actual_data); |
- if (expected_data != actual_data) |
- return MockWriteResult(false, net::ERR_UNEXPECTED); |
- if (result == net::OK) |
- result = w->data_len; |
- } |
- return MockWriteResult(w->async, result); |
+void MockClientSocket::RunCallbackAsync(net::CompletionCallback* callback, |
+ int result) { |
+ MessageLoop::current()->PostTask(FROM_HERE, |
+ method_factory_.NewRunnableMethod( |
+ &MockClientSocket::RunCallback, callback, result)); |
} |
-const MockRead& StaticSocketDataProvider::PeekRead() const { |
- DCHECK(!at_read_eof()); |
- return reads_[read_index_]; |
+void MockClientSocket::RunCallback(net::CompletionCallback* callback, |
+ int result) { |
+ if (callback) |
+ callback->Run(result); |
} |
-const MockWrite& StaticSocketDataProvider::PeekWrite() const { |
- DCHECK(!at_write_eof()); |
- return writes_[write_index_]; |
+MockTCPClientSocket::MockTCPClientSocket(const net::AddressList& addresses, |
+ net::NetLog* net_log, |
+ net::SocketDataProvider* data) |
+ : MockClientSocket(net_log), |
+ addresses_(addresses), |
+ data_(data), |
+ read_offset_(0), |
+ read_data_(false, net::ERR_UNEXPECTED), |
+ need_read_data_(true), |
+ peer_closed_connection_(false), |
+ pending_buf_(NULL), |
+ pending_buf_len_(0), |
+ pending_callback_(NULL), |
+ was_used_to_convey_data_(false) { |
+ DCHECK(data_); |
+ data_->Reset(); |
} |
-const MockRead& StaticSocketDataProvider::PeekRead(size_t index) const { |
- DCHECK_LT(index, read_count_); |
- return reads_[index]; |
-} |
+int MockTCPClientSocket::Read(net::IOBuffer* buf, int buf_len, |
+ net::CompletionCallback* callback) { |
+ if (!connected_) |
+ return net::ERR_UNEXPECTED; |
-const MockWrite& StaticSocketDataProvider::PeekWrite(size_t index) const { |
- DCHECK_LT(index, write_count_); |
- return writes_[index]; |
-} |
+ // If the buffer is already in use, a read is already in progress! |
+ DCHECK(pending_buf_ == NULL); |
-void StaticSocketDataProvider::Reset() { |
- read_index_ = 0; |
- write_index_ = 0; |
-} |
+ // Store our async IO data. |
+ pending_buf_ = buf; |
+ pending_buf_len_ = buf_len; |
+ pending_callback_ = callback; |
-DynamicSocketDataProvider::DynamicSocketDataProvider() |
- : short_read_limit_(0), |
- allow_unconsumed_reads_(false) { |
+ if (need_read_data_) { |
+ read_data_ = data_->GetNextRead(); |
+ if (read_data_.result == ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ) { |
+ // This MockRead is just a marker to instruct us to set |
+ // peer_closed_connection_. Skip it and get the next one. |
+ read_data_ = data_->GetNextRead(); |
+ peer_closed_connection_ = true; |
+ } |
+ // 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(); |
} |
-DynamicSocketDataProvider::~DynamicSocketDataProvider() {} |
+int MockTCPClientSocket::Write(net::IOBuffer* buf, int buf_len, |
+ net::CompletionCallback* callback) { |
+ DCHECK(buf); |
+ DCHECK_GT(buf_len, 0); |
-MockRead DynamicSocketDataProvider::GetNextRead() { |
- if (reads_.empty()) |
- return MockRead(false, ERR_UNEXPECTED); |
- MockRead result = reads_.front(); |
- if (short_read_limit_ == 0 || result.data_len <= short_read_limit_) { |
- reads_.pop_front(); |
- } else { |
- result.data_len = short_read_limit_; |
- reads_.front().data += result.data_len; |
- reads_.front().data_len -= result.data_len; |
+ if (!connected_) |
+ return net::ERR_UNEXPECTED; |
+ |
+ std::string data(buf->data(), buf_len); |
+ net::MockWriteResult write_result = data_->OnWrite(data); |
+ |
+ was_used_to_convey_data_ = true; |
+ |
+ if (write_result.async) { |
+ RunCallbackAsync(callback, write_result.result); |
+ return net::ERR_IO_PENDING; |
} |
- return result; |
-} |
-void DynamicSocketDataProvider::Reset() { |
- reads_.clear(); |
+ return write_result.result; |
} |
-void DynamicSocketDataProvider::SimulateRead(const char* data, |
- const size_t length) { |
- if (!allow_unconsumed_reads_) { |
- EXPECT_TRUE(reads_.empty()) << "Unconsumed read: " << reads_.front().data; |
+int MockTCPClientSocket::Connect(net::CompletionCallback* callback) { |
+ if (connected_) |
+ return net::OK; |
+ connected_ = true; |
+ peer_closed_connection_ = false; |
+ if (data_->connect_data().async) { |
+ RunCallbackAsync(callback, data_->connect_data().result); |
+ return net::ERR_IO_PENDING; |
} |
- reads_.push_back(MockRead(true, data, length)); |
+ return data_->connect_data().result; |
} |
-DelayedSocketData::DelayedSocketData( |
- int write_delay, MockRead* reads, size_t reads_count, |
- MockWrite* writes, size_t writes_count) |
- : StaticSocketDataProvider(reads, reads_count, writes, writes_count), |
- write_delay_(write_delay), |
- ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) { |
- DCHECK_GE(write_delay_, 0); |
+void MockTCPClientSocket::Disconnect() { |
+ MockClientSocket::Disconnect(); |
+ pending_callback_ = NULL; |
} |
-DelayedSocketData::DelayedSocketData( |
- const MockConnect& connect, int write_delay, MockRead* reads, |
- size_t reads_count, MockWrite* writes, size_t writes_count) |
- : StaticSocketDataProvider(reads, reads_count, writes, writes_count), |
- write_delay_(write_delay), |
- ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) { |
- DCHECK_GE(write_delay_, 0); |
- set_connect_data(connect); |
+bool MockTCPClientSocket::IsConnected() const { |
+ return connected_ && !peer_closed_connection_; |
} |
-DelayedSocketData::~DelayedSocketData() { |
+bool MockTCPClientSocket::IsConnectedAndIdle() const { |
+ return IsConnected(); |
} |
-MockRead DelayedSocketData::GetNextRead() { |
- if (write_delay_ > 0) |
- return MockRead(true, ERR_IO_PENDING); |
- return StaticSocketDataProvider::GetNextRead(); |
+bool MockTCPClientSocket::WasEverUsed() const { |
+ return was_used_to_convey_data_; |
} |
-MockWriteResult DelayedSocketData::OnWrite(const std::string& data) { |
- MockWriteResult rv = StaticSocketDataProvider::OnWrite(data); |
- // Now that our write has completed, we can allow reads to continue. |
- if (!--write_delay_) |
- MessageLoop::current()->PostDelayedTask(FROM_HERE, |
- factory_.NewRunnableMethod(&DelayedSocketData::CompleteRead), 100); |
- return rv; |
+bool MockTCPClientSocket::UsingTCPFastOpen() const { |
+ return false; |
} |
-void DelayedSocketData::Reset() { |
- set_socket(NULL); |
- factory_.RevokeAll(); |
- StaticSocketDataProvider::Reset(); |
-} |
+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_); |
-void DelayedSocketData::CompleteRead() { |
- if (socket()) |
- socket()->OnReadComplete(GetNextRead()); |
-} |
+ read_data_ = data; |
+ need_read_data_ = false; |
-void DelayedSocketData::ForceNextRead() { |
- write_delay_ = 0; |
- CompleteRead(); |
-} |
+ // The caller is simulating that this IO completes right now. Don't |
+ // let CompleteRead() schedule a callback. |
+ read_data_.async = false; |
-OrderedSocketData::OrderedSocketData( |
- MockRead* reads, size_t reads_count, MockWrite* writes, size_t writes_count) |
- : StaticSocketDataProvider(reads, reads_count, writes, writes_count), |
- sequence_number_(0), loop_stop_stage_(0), callback_(NULL), |
- blocked_(false), ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) { |
+ net::CompletionCallback* callback = pending_callback_; |
+ int rv = CompleteRead(); |
+ RunCallback(callback, rv); |
} |
-OrderedSocketData::OrderedSocketData( |
- const MockConnect& connect, |
- MockRead* reads, size_t reads_count, |
- MockWrite* writes, size_t writes_count) |
- : StaticSocketDataProvider(reads, reads_count, writes, writes_count), |
- sequence_number_(0), loop_stop_stage_(0), callback_(NULL), |
- blocked_(false), ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) { |
- set_connect_data(connect); |
-} |
+int MockTCPClientSocket::CompleteRead() { |
+ DCHECK(pending_buf_); |
+ DCHECK(pending_buf_len_ > 0); |
-MockRead OrderedSocketData::GetNextRead() { |
- factory_.RevokeAll(); |
- blocked_ = false; |
- const MockRead& next_read = StaticSocketDataProvider::PeekRead(); |
- if (next_read.sequence_number & MockRead::STOPLOOP) |
- EndLoop(); |
- if ((next_read.sequence_number & ~MockRead::STOPLOOP) <= |
- sequence_number_++) { |
- NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_ - 1 |
- << ": Read " << read_index(); |
- DumpMockRead(next_read); |
- return StaticSocketDataProvider::GetNextRead(); |
- } |
- NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_ - 1 |
- << ": I/O Pending"; |
- MockRead result = MockRead(true, ERR_IO_PENDING); |
- DumpMockRead(result); |
- blocked_ = true; |
- return result; |
-} |
+ was_used_to_convey_data_ = true; |
-MockWriteResult OrderedSocketData::OnWrite(const std::string& data) { |
- NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_ |
- << ": Write " << write_index(); |
- DumpMockRead(PeekWrite()); |
- ++sequence_number_; |
- if (blocked_) { |
- // TODO(willchan): This 100ms delay seems to work around some weirdness. We |
- // should probably fix the weirdness. One example is in SpdyStream, |
- // DoSendRequest() will return ERR_IO_PENDING, and there's a race. If the |
- // SYN_REPLY causes OnResponseReceived() to get called before |
- // SpdyStream::ReadResponseHeaders() is called, we hit a NOTREACHED(). |
- MessageLoop::current()->PostDelayedTask( |
- FROM_HERE, |
- factory_.NewRunnableMethod(&OrderedSocketData::CompleteRead), 100); |
- } |
- return StaticSocketDataProvider::OnWrite(data); |
-} |
+ // 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; |
-void OrderedSocketData::Reset() { |
- NET_TRACE(INFO, " *** ") << "Stage " |
- << sequence_number_ << ": Reset()"; |
- sequence_number_ = 0; |
- loop_stop_stage_ = 0; |
- set_socket(NULL); |
- factory_.RevokeAll(); |
- StaticSocketDataProvider::Reset(); |
-} |
+ int result = read_data_.result; |
+ DCHECK(result != ERR_IO_PENDING); |
-void OrderedSocketData::EndLoop() { |
- // If we've already stopped the loop, don't do it again until we've advanced |
- // to the next sequence_number. |
- NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_ << ": EndLoop()"; |
- if (loop_stop_stage_ > 0) { |
- const MockRead& next_read = StaticSocketDataProvider::PeekRead(); |
- if ((next_read.sequence_number & ~MockRead::STOPLOOP) > |
- loop_stop_stage_) { |
- NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_ |
- << ": Clearing stop index"; |
- loop_stop_stage_ = 0; |
+ if (read_data_.data) { |
+ if (read_data_.data_len - read_offset_ > 0) { |
+ result = std::min(buf_len, read_data_.data_len - read_offset_); |
+ memcpy(buf->data(), read_data_.data + read_offset_, result); |
+ read_offset_ += result; |
+ if (read_offset_ == read_data_.data_len) { |
+ need_read_data_ = true; |
+ read_offset_ = 0; |
+ } |
} else { |
- return; |
+ result = 0; // EOF |
} |
} |
- // Record the sequence_number at which we stopped the loop. |
- NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_ |
- << ": Posting Quit at read " << read_index(); |
- loop_stop_stage_ = sequence_number_; |
- if (callback_) |
- callback_->RunWithParams(Tuple1<int>(ERR_IO_PENDING)); |
-} |
-void OrderedSocketData::CompleteRead() { |
- if (socket()) { |
- NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_; |
- socket()->OnReadComplete(GetNextRead()); |
+ if (read_data_.async) { |
+ DCHECK(callback); |
+ RunCallbackAsync(callback, result); |
+ return net::ERR_IO_PENDING; |
} |
+ return result; |
} |
-OrderedSocketData::~OrderedSocketData() {} |
+DeterministicMockTCPClientSocket::DeterministicMockTCPClientSocket( |
+ net::NetLog* net_log, net::DeterministicSocketData* data) |
+ : MockClientSocket(net_log), |
+ write_pending_(false), |
+ write_callback_(NULL), |
+ write_result_(0), |
+ read_data_(), |
+ read_buf_(NULL), |
+ read_buf_len_(0), |
+ read_pending_(false), |
+ read_callback_(NULL), |
+ data_(data), |
+ was_used_to_convey_data_(false) {} |
-DeterministicSocketData::DeterministicSocketData(MockRead* reads, |
- size_t reads_count, MockWrite* writes, size_t writes_count) |
- : StaticSocketDataProvider(reads, reads_count, writes, writes_count), |
- sequence_number_(0), |
- current_read_(), |
- current_write_(), |
- stopping_sequence_number_(0), |
- stopped_(false), |
- print_debug_(false) {} |
+DeterministicMockTCPClientSocket::~DeterministicMockTCPClientSocket() {} |
-MockRead DeterministicSocketData::GetNextRead() { |
- current_read_ = StaticSocketDataProvider::PeekRead(); |
- EXPECT_LE(sequence_number_, current_read_.sequence_number); |
+void DeterministicMockTCPClientSocket::CompleteWrite() { |
+ was_used_to_convey_data_ = true; |
+ write_pending_ = false; |
+ write_callback_->Run(write_result_); |
+} |
- // Synchronous read while stopped is an error |
- if (stopped() && !current_read_.async) { |
- LOG(ERROR) << "Unable to perform synchronous IO while stopped"; |
- return MockRead(false, ERR_UNEXPECTED); |
- } |
+int DeterministicMockTCPClientSocket::CompleteRead() { |
+ DCHECK_GT(read_buf_len_, 0); |
+ DCHECK_LE(read_data_.data_len, read_buf_len_); |
+ DCHECK(read_buf_); |
- // Async read which will be called back in a future step. |
- if (sequence_number_ < current_read_.sequence_number) { |
- NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_ |
- << ": I/O Pending"; |
- MockRead result = MockRead(false, ERR_IO_PENDING); |
- if (!current_read_.async) { |
- LOG(ERROR) << "Unable to perform synchronous read: " |
- << current_read_.sequence_number |
- << " at stage: " << sequence_number_; |
- result = MockRead(false, ERR_UNEXPECTED); |
- } |
- if (print_debug_) |
- DumpMockRead(result); |
- return result; |
- } |
+ was_used_to_convey_data_ = true; |
- NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_ |
- << ": Read " << read_index(); |
- if (print_debug_) |
- DumpMockRead(current_read_); |
+ if (read_data_.result == ERR_IO_PENDING) |
+ read_data_ = data_->GetNextRead(); |
+ DCHECK_NE(ERR_IO_PENDING, read_data_.result); |
+ // If read_data_.async is true, we do not need to wait, since this is already |
+ // the callback. Therefore we don't even bother to check it. |
+ int result = read_data_.result; |
- // Increment the sequence number if IO is complete |
- if (!current_read_.async) |
- NextStep(); |
+ if (read_data_.data_len > 0) { |
+ DCHECK(read_data_.data); |
+ result = std::min(read_buf_len_, read_data_.data_len); |
+ memcpy(read_buf_->data(), read_data_.data, result); |
+ } |
- DCHECK_NE(ERR_IO_PENDING, current_read_.result); |
- StaticSocketDataProvider::GetNextRead(); |
+ if (read_pending_) { |
+ read_pending_ = false; |
+ read_callback_->Run(result); |
+ } |
- return current_read_; |
+ return result; |
} |
-MockWriteResult DeterministicSocketData::OnWrite(const std::string& data) { |
- const MockWrite& next_write = StaticSocketDataProvider::PeekWrite(); |
- current_write_ = next_write; |
+int DeterministicMockTCPClientSocket::Write( |
+ net::IOBuffer* buf, int buf_len, net::CompletionCallback* callback) { |
+ DCHECK(buf); |
+ DCHECK_GT(buf_len, 0); |
- // Synchronous write while stopped is an error |
- if (stopped() && !next_write.async) { |
- LOG(ERROR) << "Unable to perform synchronous IO while stopped"; |
- return MockWriteResult(false, ERR_UNEXPECTED); |
- } |
+ if (!connected_) |
+ return net::ERR_UNEXPECTED; |
- // Async write which will be called back in a future step. |
- if (sequence_number_ < next_write.sequence_number) { |
- NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_ |
- << ": I/O Pending"; |
- if (!next_write.async) { |
- LOG(ERROR) << "Unable to perform synchronous write: " |
- << next_write.sequence_number << " at stage: " << sequence_number_; |
- return MockWriteResult(false, ERR_UNEXPECTED); |
- } |
- } else { |
- NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_ |
- << ": Write " << write_index(); |
+ std::string data(buf->data(), buf_len); |
+ net::MockWriteResult write_result = data_->OnWrite(data); |
+ |
+ if (write_result.async) { |
+ write_callback_ = callback; |
+ write_result_ = write_result.result; |
+ DCHECK(write_callback_ != NULL); |
+ write_pending_ = true; |
+ return net::ERR_IO_PENDING; |
} |
- if (print_debug_) |
- DumpMockRead(next_write); |
+ was_used_to_convey_data_ = true; |
+ write_pending_ = false; |
+ return write_result.result; |
+} |
- // Move to the next step if I/O is synchronous, since the operation will |
- // complete when this method returns. |
- if (!next_write.async) |
- NextStep(); |
+int DeterministicMockTCPClientSocket::Read( |
+ net::IOBuffer* buf, int buf_len, net::CompletionCallback* callback) { |
+ if (!connected_) |
+ return net::ERR_UNEXPECTED; |
- // This is either a sync write for this step, or an async write. |
- return StaticSocketDataProvider::OnWrite(data); |
+ read_data_ = data_->GetNextRead(); |
+ // The buffer should always be big enough to contain all the MockRead data. To |
+ // use small buffers, split the data into multiple MockReads. |
+ DCHECK_LE(read_data_.data_len, buf_len); |
+ |
+ read_buf_ = buf; |
+ read_buf_len_ = buf_len; |
+ read_callback_ = callback; |
+ |
+ if (read_data_.async || (read_data_.result == ERR_IO_PENDING)) { |
+ read_pending_ = true; |
+ DCHECK(read_callback_); |
+ return ERR_IO_PENDING; |
+ } |
+ |
+ was_used_to_convey_data_ = true; |
+ return CompleteRead(); |
} |
-void DeterministicSocketData::Reset() { |
- NET_TRACE(INFO, " *** ") << "Stage " |
- << sequence_number_ << ": Reset()"; |
- sequence_number_ = 0; |
- StaticSocketDataProvider::Reset(); |
- NOTREACHED(); |
+// TODO(erikchen): Support connect sequencing. |
+int DeterministicMockTCPClientSocket::Connect( |
+ net::CompletionCallback* callback) { |
+ if (connected_) |
+ return net::OK; |
+ connected_ = true; |
+ if (data_->connect_data().async) { |
+ RunCallbackAsync(callback, data_->connect_data().result); |
+ return net::ERR_IO_PENDING; |
+ } |
+ return data_->connect_data().result; |
} |
-void DeterministicSocketData::RunFor(int steps) { |
- StopAfter(steps); |
- Run(); |
+void DeterministicMockTCPClientSocket::Disconnect() { |
+ MockClientSocket::Disconnect(); |
} |
-void DeterministicSocketData::Run() { |
- SetStopped(false); |
- int counter = 0; |
- // Continue to consume data until all data has run out, or the stopped_ flag |
- // has been set. Consuming data requires two separate operations -- running |
- // the tasks in the message loop, and explicitly invoking the read/write |
- // callbacks (simulating network I/O). We check our conditions between each, |
- // since they can change in either. |
- while ((!at_write_eof() || !at_read_eof()) && !stopped()) { |
- if (counter % 2 == 0) |
- MessageLoop::current()->RunAllPending(); |
- if (counter % 2 == 1) { |
- InvokeCallbacks(); |
- } |
- counter++; |
- } |
- // We're done consuming new data, but it is possible there are still some |
- // pending callbacks which we expect to complete before returning. |
- while (socket_ && (socket_->write_pending() || socket_->read_pending()) && |
- !stopped()) { |
- InvokeCallbacks(); |
- MessageLoop::current()->RunAllPending(); |
- } |
- SetStopped(false); |
+bool DeterministicMockTCPClientSocket::IsConnected() const { |
+ return connected_; |
} |
-void DeterministicSocketData::InvokeCallbacks() { |
- if (socket_ && socket_->write_pending() && |
- (current_write().sequence_number == sequence_number())) { |
- socket_->CompleteWrite(); |
- NextStep(); |
- return; |
- } |
- if (socket_ && socket_->read_pending() && |
- (current_read().sequence_number == sequence_number())) { |
- socket_->CompleteRead(); |
- NextStep(); |
- return; |
- } |
+bool DeterministicMockTCPClientSocket::IsConnectedAndIdle() const { |
+ return IsConnected(); |
} |
-void DeterministicSocketData::NextStep() { |
- // Invariant: Can never move *past* the stopping step. |
- DCHECK_LT(sequence_number_, stopping_sequence_number_); |
- sequence_number_++; |
- if (sequence_number_ == stopping_sequence_number_) |
- SetStopped(true); |
+bool DeterministicMockTCPClientSocket::WasEverUsed() const { |
+ return was_used_to_convey_data_; |
} |
+bool DeterministicMockTCPClientSocket::UsingTCPFastOpen() const { |
+ return false; |
+} |
-MockClientSocketFactory::MockClientSocketFactory() {} |
+void DeterministicMockTCPClientSocket::OnReadComplete(const MockRead& data) {} |
-MockClientSocketFactory::~MockClientSocketFactory() {} |
+class MockSSLClientSocket::ConnectCallback |
+ : public net::CompletionCallbackImpl<MockSSLClientSocket::ConnectCallback> { |
+ public: |
+ ConnectCallback(MockSSLClientSocket *ssl_client_socket, |
+ net::CompletionCallback* user_callback, |
+ int rv) |
+ : ALLOW_THIS_IN_INITIALIZER_LIST( |
+ net::CompletionCallbackImpl<MockSSLClientSocket::ConnectCallback>( |
+ this, &ConnectCallback::Wrapper)), |
+ ssl_client_socket_(ssl_client_socket), |
+ user_callback_(user_callback), |
+ rv_(rv) { |
+ } |
-void MockClientSocketFactory::AddSocketDataProvider( |
- SocketDataProvider* data) { |
- mock_data_.Add(data); |
+ private: |
+ void Wrapper(int rv) { |
+ if (rv_ == net::OK) |
+ ssl_client_socket_->connected_ = true; |
+ user_callback_->Run(rv_); |
+ delete this; |
+ } |
+ |
+ MockSSLClientSocket* ssl_client_socket_; |
+ net::CompletionCallback* user_callback_; |
+ int rv_; |
+}; |
+ |
+MockSSLClientSocket::MockSSLClientSocket( |
+ net::ClientSocketHandle* transport_socket, |
+ const HostPortPair& host_port_pair, |
+ const net::SSLConfig& ssl_config, |
+ SSLHostInfo* ssl_host_info, |
+ net::SSLSocketDataProvider* data) |
+ : MockClientSocket(transport_socket->socket()->NetLog().net_log()), |
+ transport_(transport_socket), |
+ data_(data), |
+ is_npn_state_set_(false), |
+ new_npn_value_(false) { |
+ DCHECK(data_); |
+ delete ssl_host_info; // we take ownership but don't use it. |
} |
-void MockClientSocketFactory::AddSSLSocketDataProvider( |
- SSLSocketDataProvider* data) { |
- mock_ssl_data_.Add(data); |
+MockSSLClientSocket::~MockSSLClientSocket() { |
+ Disconnect(); |
} |
-void MockClientSocketFactory::ResetNextMockIndexes() { |
- mock_data_.ResetNextIndex(); |
- mock_ssl_data_.ResetNextIndex(); |
+int MockSSLClientSocket::Read(net::IOBuffer* buf, int buf_len, |
+ net::CompletionCallback* callback) { |
+ return transport_->socket()->Read(buf, buf_len, callback); |
} |
-MockTCPClientSocket* MockClientSocketFactory::GetMockTCPClientSocket( |
- size_t index) const { |
- DCHECK_LT(index, tcp_client_sockets_.size()); |
- return tcp_client_sockets_[index]; |
+int MockSSLClientSocket::Write(net::IOBuffer* buf, int buf_len, |
+ net::CompletionCallback* callback) { |
+ return transport_->socket()->Write(buf, buf_len, callback); |
} |
-MockSSLClientSocket* MockClientSocketFactory::GetMockSSLClientSocket( |
- size_t index) const { |
- DCHECK_LT(index, ssl_client_sockets_.size()); |
- return ssl_client_sockets_[index]; |
+int MockSSLClientSocket::Connect(net::CompletionCallback* callback) { |
+ ConnectCallback* connect_callback = new ConnectCallback( |
+ this, callback, data_->connect.result); |
+ int rv = transport_->socket()->Connect(connect_callback); |
+ if (rv == net::OK) { |
+ delete connect_callback; |
+ if (data_->connect.result == net::OK) |
+ connected_ = true; |
+ if (data_->connect.async) { |
+ RunCallbackAsync(callback, data_->connect.result); |
+ return net::ERR_IO_PENDING; |
+ } |
+ return data_->connect.result; |
+ } |
+ return rv; |
} |
-ClientSocket* MockClientSocketFactory::CreateTCPClientSocket( |
- const AddressList& addresses, |
- net::NetLog* net_log, |
- const NetLog::Source& source) { |
- SocketDataProvider* data_provider = mock_data_.GetNext(); |
- MockTCPClientSocket* socket = |
- new MockTCPClientSocket(addresses, net_log, data_provider); |
- data_provider->set_socket(socket); |
- tcp_client_sockets_.push_back(socket); |
- return socket; |
+void MockSSLClientSocket::Disconnect() { |
+ MockClientSocket::Disconnect(); |
+ if (transport_->socket() != NULL) |
+ transport_->socket()->Disconnect(); |
} |
-SSLClientSocket* MockClientSocketFactory::CreateSSLClientSocket( |
- ClientSocketHandle* transport_socket, |
- const HostPortPair& host_and_port, |
- const SSLConfig& ssl_config, |
- SSLHostInfo* ssl_host_info, |
- CertVerifier* cert_verifier, |
- DnsCertProvenanceChecker* dns_cert_checker) { |
- MockSSLClientSocket* socket = |
- new MockSSLClientSocket(transport_socket, host_and_port, ssl_config, |
- ssl_host_info, mock_ssl_data_.GetNext()); |
- ssl_client_sockets_.push_back(socket); |
- return socket; |
+bool MockSSLClientSocket::IsConnected() const { |
+ return transport_->socket()->IsConnected(); |
} |
-DeterministicMockClientSocketFactory::DeterministicMockClientSocketFactory() {} |
+bool MockSSLClientSocket::WasEverUsed() const { |
+ return transport_->socket()->WasEverUsed(); |
+} |
-DeterministicMockClientSocketFactory::~DeterministicMockClientSocketFactory() {} |
+bool MockSSLClientSocket::UsingTCPFastOpen() const { |
+ return transport_->socket()->UsingTCPFastOpen(); |
+} |
-void DeterministicMockClientSocketFactory::AddSocketDataProvider( |
- DeterministicSocketData* data) { |
- mock_data_.Add(data); |
+void MockSSLClientSocket::GetSSLInfo(net::SSLInfo* ssl_info) { |
+ ssl_info->Reset(); |
} |
-void DeterministicMockClientSocketFactory::AddSSLSocketDataProvider( |
- SSLSocketDataProvider* data) { |
- mock_ssl_data_.Add(data); |
+void MockSSLClientSocket::GetSSLCertRequestInfo( |
+ net::SSLCertRequestInfo* cert_request_info) { |
+ DCHECK(cert_request_info); |
+ if (data_->cert_request_info) { |
+ cert_request_info->host_and_port = |
+ data_->cert_request_info->host_and_port; |
+ cert_request_info->client_certs = data_->cert_request_info->client_certs; |
+ } else { |
+ cert_request_info->Reset(); |
+ } |
} |
-void DeterministicMockClientSocketFactory::ResetNextMockIndexes() { |
- mock_data_.ResetNextIndex(); |
- mock_ssl_data_.ResetNextIndex(); |
+SSLClientSocket::NextProtoStatus MockSSLClientSocket::GetNextProto( |
+ std::string* proto) { |
+ *proto = data_->next_proto; |
+ return data_->next_proto_status; |
} |
-MockSSLClientSocket* DeterministicMockClientSocketFactory:: |
- GetMockSSLClientSocket(size_t index) const { |
- DCHECK_LT(index, ssl_client_sockets_.size()); |
- return ssl_client_sockets_[index]; |
+bool MockSSLClientSocket::was_npn_negotiated() const { |
+ if (is_npn_state_set_) |
+ return new_npn_value_; |
+ return data_->was_npn_negotiated; |
} |
-ClientSocket* DeterministicMockClientSocketFactory::CreateTCPClientSocket( |
- const AddressList& addresses, |
- net::NetLog* net_log, |
- const net::NetLog::Source& source) { |
- DeterministicSocketData* data_provider = mock_data().GetNext(); |
- DeterministicMockTCPClientSocket* socket = |
- new DeterministicMockTCPClientSocket(net_log, data_provider); |
- data_provider->set_socket(socket->AsWeakPtr()); |
- tcp_client_sockets().push_back(socket); |
- return socket; |
+bool MockSSLClientSocket::set_was_npn_negotiated(bool negotiated) { |
+ is_npn_state_set_ = true; |
+ return new_npn_value_ = negotiated; |
} |
-SSLClientSocket* DeterministicMockClientSocketFactory::CreateSSLClientSocket( |
- ClientSocketHandle* transport_socket, |
- const HostPortPair& host_and_port, |
- const SSLConfig& ssl_config, |
- SSLHostInfo* ssl_host_info, |
- CertVerifier* cert_verifier, |
- DnsCertProvenanceChecker* dns_cert_checker) { |
- MockSSLClientSocket* socket = |
- new MockSSLClientSocket(transport_socket, host_and_port, ssl_config, |
- ssl_host_info, mock_ssl_data_.GetNext()); |
- ssl_client_sockets_.push_back(socket); |
- return socket; |
+void MockSSLClientSocket::OnReadComplete(const MockRead& data) { |
+ NOTIMPLEMENTED(); |
} |
TestSocketRequest::TestSocketRequest( |
@@ -1215,6 +1219,8 @@ MockTCPClientSocketPool::MockTCPClientSocketPool( |
cancel_count_(0) { |
} |
+MockTCPClientSocketPool::~MockTCPClientSocketPool() {} |
+ |
int MockTCPClientSocketPool::RequestSocket(const std::string& group_name, |
const void* socket_params, |
RequestPriority priority, |
@@ -1247,7 +1253,56 @@ void MockTCPClientSocketPool::ReleaseSocket(const std::string& group_name, |
delete socket; |
} |
-MockTCPClientSocketPool::~MockTCPClientSocketPool() {} |
+DeterministicMockClientSocketFactory::DeterministicMockClientSocketFactory() {} |
+ |
+DeterministicMockClientSocketFactory::~DeterministicMockClientSocketFactory() {} |
+ |
+void DeterministicMockClientSocketFactory::AddSocketDataProvider( |
+ DeterministicSocketData* data) { |
+ mock_data_.Add(data); |
+} |
+ |
+void DeterministicMockClientSocketFactory::AddSSLSocketDataProvider( |
+ SSLSocketDataProvider* data) { |
+ mock_ssl_data_.Add(data); |
+} |
+ |
+void DeterministicMockClientSocketFactory::ResetNextMockIndexes() { |
+ mock_data_.ResetNextIndex(); |
+ mock_ssl_data_.ResetNextIndex(); |
+} |
+ |
+MockSSLClientSocket* DeterministicMockClientSocketFactory:: |
+ GetMockSSLClientSocket(size_t index) const { |
+ DCHECK_LT(index, ssl_client_sockets_.size()); |
+ return ssl_client_sockets_[index]; |
+} |
+ |
+ClientSocket* DeterministicMockClientSocketFactory::CreateTCPClientSocket( |
+ const AddressList& addresses, |
+ net::NetLog* net_log, |
+ const net::NetLog::Source& source) { |
+ DeterministicSocketData* data_provider = mock_data().GetNext(); |
+ DeterministicMockTCPClientSocket* socket = |
+ new DeterministicMockTCPClientSocket(net_log, data_provider); |
+ data_provider->set_socket(socket->AsWeakPtr()); |
+ tcp_client_sockets().push_back(socket); |
+ return socket; |
+} |
+ |
+SSLClientSocket* DeterministicMockClientSocketFactory::CreateSSLClientSocket( |
+ ClientSocketHandle* transport_socket, |
+ const HostPortPair& host_and_port, |
+ const SSLConfig& ssl_config, |
+ SSLHostInfo* ssl_host_info, |
+ CertVerifier* cert_verifier, |
+ DnsCertProvenanceChecker* dns_cert_checker) { |
+ MockSSLClientSocket* socket = |
+ new MockSSLClientSocket(transport_socket, host_and_port, ssl_config, |
+ ssl_host_info, mock_ssl_data_.GetNext()); |
+ ssl_client_sockets_.push_back(socket); |
+ return socket; |
+} |
MockSOCKSClientSocketPool::MockSOCKSClientSocketPool( |
int max_sockets, |
@@ -1259,6 +1314,8 @@ MockSOCKSClientSocketPool::MockSOCKSClientSocketPool( |
tcp_pool_(tcp_pool) { |
} |
+MockSOCKSClientSocketPool::~MockSOCKSClientSocketPool() {} |
+ |
int MockSOCKSClientSocketPool::RequestSocket(const std::string& group_name, |
const void* socket_params, |
RequestPriority priority, |
@@ -1280,8 +1337,6 @@ void MockSOCKSClientSocketPool::ReleaseSocket(const std::string& group_name, |
return tcp_pool_->ReleaseSocket(group_name, socket, id); |
} |
-MockSOCKSClientSocketPool::~MockSOCKSClientSocketPool() {} |
- |
const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 }; |
const int kSOCKS5GreetRequestLength = arraysize(kSOCKS5GreetRequest); |