From a1b1bcd1a101e9cce0cfe7432af704aed7f11063 Mon Sep 17 00:00:00 2001 From: Maks Orlovich Date: Thu, 1 Nov 2018 02:25:21 +0000 Subject: [PATCH] jingle_glue: Add a NetworkService equivalent of ChromeAsyncSocket The former will have some problems with some proxy setups once the Network Service is on, so this introduces a replacement. This CL doesn't hook it up to anything, just builds & tests it. Next steps would require an equivalent to FakeSSLClientSocket, and then actually hooking those up and wiring the different injected config from Chrome. To ease the review of this somewhat, this CL was split in two, with https://chromium-review.googlesource.com/c/chromium/src/+/1237214 just copying over ChomeAsyncSocket and its tests to new files, to produce something of a meaningful diff. (Thanks to lassey@ for the idea) Bug: 875032 Change-Id: Ic5d4e4276c993e0e70f059d485b9d34aeab41e6d Reviewed-on: https://chromium-review.googlesource.com/c/1232034 Commit-Queue: Maks Orlovich Reviewed-by: Ken Rockot Reviewed-by: Matt Menke Reviewed-by: Nicolas Zea Cr-Commit-Position: refs/heads/master@{#604490} --- jingle/BUILD.gn | 19 +- jingle/DEPS | 1 + jingle/glue/DEPS | 3 + jingle/glue/network_service_async_socket.cc | 475 ++++--- jingle/glue/network_service_async_socket.h | 143 +- .../network_service_async_socket_unittest.cc | 1231 +++++++++++------ jingle/run_all_unittests.cc | 16 + 7 files changed, 1231 insertions(+), 657 deletions(-) create mode 100644 jingle/run_all_unittests.cc diff --git a/jingle/BUILD.gn b/jingle/BUILD.gn index 320a7cba359541..313e20cd920edb 100644 --- a/jingle/BUILD.gn +++ b/jingle/BUILD.gn @@ -9,6 +9,8 @@ static_library("jingle_glue") { sources = [ "glue/chrome_async_socket.cc", "glue/chrome_async_socket.h", + "glue/network_service_async_socket.cc", + "glue/network_service_async_socket.h", "glue/resolving_client_socket_factory.h", "glue/task_pump.cc", "glue/task_pump.h", @@ -28,6 +30,7 @@ static_library("jingle_glue") { "//base/third_party/dynamic_annotations", "//net", "//services/network:network_service", + "//services/network/public/mojom", "//third_party/libjingle_xmpp:rtc_task_runner", ] @@ -36,9 +39,13 @@ static_library("jingle_glue") { if (is_nacl) { sources -= [ "glue/chrome_async_socket.cc", + "glue/network_service_async_socket.cc", "glue/xmpp_client_socket_factory.cc", ] - deps -= [ "//services/network:network_service" ] + deps -= [ + "//services/network:network_service", + "//services/network/public/mojom", + ] } } @@ -117,8 +124,8 @@ static_library("notifier") { "//base", "//net", "//third_party/expat", - "//url", "//third_party/libjingle_xmpp:rtc_task_runner", + "//url", ] } @@ -151,6 +158,7 @@ test("jingle_unittests") { "glue/logging_unittest.cc", "glue/mock_task.cc", "glue/mock_task.h", + "glue/network_service_async_socket_unittest.cc", "glue/task_pump_unittest.cc", "glue/thread_wrapper_unittest.cc", "notifier/base/weak_xmpp_client_unittest.cc", @@ -166,6 +174,7 @@ test("jingle_unittests") { "notifier/listener/send_ping_task_unittest.cc", "notifier/listener/xml_element_util_unittest.cc", "notifier/listener/xmpp_push_client_unittest.cc", + "run_all_unittests.cc", ] if (is_android || is_ios) { @@ -174,6 +183,7 @@ test("jingle_unittests") { # EXPECT_DEBUG_DEATH() uses features not enabled. # Should we -std=c++0x or -std=gnu++0x? "glue/chrome_async_socket_unittest.cc", + "glue/network_service_async_socket_unittest.cc", "notifier/base/xmpp_connection_unittest.cc", ] } @@ -195,10 +205,13 @@ test("jingle_unittests") { ":notifier", ":notifier_test_util", "//base", - "//base/test:run_all_unittests", "//base/test:test_support", + "//mojo/core/embedder", + "//mojo/public/cpp/bindings", + "//mojo/public/cpp/system", "//net", "//net:test_support", + "//services/network:network_service", "//services/network:test_support", "//testing/gmock", "//testing/gtest", diff --git a/jingle/DEPS b/jingle/DEPS index cb0272b5178de7..2c53cb747c9d99 100644 --- a/jingle/DEPS +++ b/jingle/DEPS @@ -1,4 +1,5 @@ include_rules = [ + "+mojo/core/embedder", "+net", "+third_party/libjingle_xmpp/task_runner", "+third_party/libjingle_xmpp/xmllite", diff --git a/jingle/glue/DEPS b/jingle/glue/DEPS index 153dc58326012d..1865d8cc8f5f66 100644 --- a/jingle/glue/DEPS +++ b/jingle/glue/DEPS @@ -1,7 +1,10 @@ # Needed by logging_unittest.cc since it tests the overrides. include_rules = [ + "+mojo/public/cpp", "+services/network/proxy_resolving_client_socket.h", "+services/network/proxy_resolving_client_socket_factory.h", + "+services/network/proxy_resolving_socket_factory_mojo.h", + "+services/network/public/mojom", "+third_party/libjingle_xmpp/task_runner", "+third_party/webrtc", "+third_party/webrtc_overrides", diff --git a/jingle/glue/network_service_async_socket.cc b/jingle/glue/network_service_async_socket.cc index ebe8aec86138f1..4399c59e85b7a0 100644 --- a/jingle/glue/network_service_async_socket.cc +++ b/jingle/glue/network_service_async_socket.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "jingle/glue/chrome_async_socket.h" +#include "jingle/glue/network_service_async_socket.h" #include #include @@ -14,81 +14,129 @@ #include "base/compiler_specific.h" #include "base/logging.h" #include "base/threading/thread_task_runner_handle.h" -#include "jingle/glue/resolving_client_socket_factory.h" -#include "net/base/address_list.h" #include "net/base/host_port_pair.h" #include "net/base/io_buffer.h" -#include "net/socket/client_socket_handle.h" -#include "net/socket/ssl_client_socket.h" -#include "net/socket/tcp_client_socket.h" -#include "net/ssl/ssl_config_service.h" #include "third_party/webrtc/rtc_base/socketaddress.h" namespace jingle_glue { -ChromeAsyncSocket::ChromeAsyncSocket( - std::unique_ptr - resolving_client_socket_factory, +NetworkServiceAsyncSocket::NetworkServiceAsyncSocket( + GetProxyResolvingFactoryCallback get_socket_factory_callback, size_t read_buf_size, size_t write_buf_size, const net::NetworkTrafficAnnotationTag& traffic_annotation) - : resolving_client_socket_factory_( - std::move(resolving_client_socket_factory)), + : get_socket_factory_callback_(get_socket_factory_callback), + socket_observer_binding_(this), state_(STATE_CLOSED), error_(ERROR_NONE), net_error_(net::OK), read_state_(IDLE), - read_buf_(base::MakeRefCounted(read_buf_size)), + read_buf_(read_buf_size), read_start_(0U), read_end_(0U), + saw_error_on_read_pipe_(false), + saw_error_on_write_pipe_(false), + saw_read_error_on_socket_observer_pipe_(net::ERR_IO_PENDING), + saw_write_error_on_socket_observer_pipe_(net::ERR_IO_PENDING), write_state_(IDLE), - write_buf_(base::MakeRefCounted(write_buf_size)), + write_buf_(write_buf_size), write_end_(0U), - traffic_annotation_(traffic_annotation), - weak_ptr_factory_(this) { - DCHECK(resolving_client_socket_factory_.get()); + traffic_annotation_(traffic_annotation) { + DCHECK(get_socket_factory_callback_); DCHECK_GT(read_buf_size, 0U); DCHECK_GT(write_buf_size, 0U); } -ChromeAsyncSocket::~ChromeAsyncSocket() {} +NetworkServiceAsyncSocket::~NetworkServiceAsyncSocket() {} -ChromeAsyncSocket::State ChromeAsyncSocket::state() { +NetworkServiceAsyncSocket::State NetworkServiceAsyncSocket::state() { return state_; } -ChromeAsyncSocket::Error ChromeAsyncSocket::error() { +NetworkServiceAsyncSocket::Error NetworkServiceAsyncSocket::error() { return error_; } -int ChromeAsyncSocket::GetError() { +int NetworkServiceAsyncSocket::GetError() { return net_error_; } -bool ChromeAsyncSocket::IsOpen() const { +bool NetworkServiceAsyncSocket::IsOpen() const { return (state_ == STATE_OPEN) || (state_ == STATE_TLS_OPEN); } -void ChromeAsyncSocket::DoNonNetError(Error error) { +void NetworkServiceAsyncSocket::DoNonNetError(Error error) { DCHECK_NE(error, ERROR_NONE); DCHECK_NE(error, ERROR_WINSOCK); error_ = error; net_error_ = net::OK; } -void ChromeAsyncSocket::DoNetError(net::Error net_error) { +void NetworkServiceAsyncSocket::DoNetError(net::Error net_error) { error_ = ERROR_WINSOCK; net_error_ = net_error; } -void ChromeAsyncSocket::DoNetErrorFromStatus(int status) { +void NetworkServiceAsyncSocket::DoNetErrorFromStatus(int status) { DCHECK_LT(status, net::OK); DoNetError(static_cast(status)); } +void NetworkServiceAsyncSocket::ProcessSocketObserverError() { + if (saw_read_error_on_socket_observer_pipe_ == net::ERR_IO_PENDING && + saw_write_error_on_socket_observer_pipe_ == net::ERR_IO_PENDING) { + // Haven't seen an error, and the socket observer pipe got broken. + // This shouldn't normally happen, but as the trust level of network service + // is lower than of browser process, it needs to be handled. + DoNetError(net::ERR_FAILED); + DoClose(); + } + // In case an error came in on the socket observer pipe, it will + // get handled at time of read data pipe's closing. +} + +void NetworkServiceAsyncSocket::OnReadError(int32_t net_error) { + // Ignore redundant error messages. + if (saw_read_error_on_socket_observer_pipe_ != net::ERR_IO_PENDING) + return; + + // Sanitize any invalid error code, + if (net_error > 0 || net_error == net::ERR_IO_PENDING) + net_error = net::ERR_FAILED; + if (saw_error_on_read_pipe_) { + // Read pipe closure got delivered first, and so with the socket observer + // notification here, both pipes got fully handled. + ReportReadError(net_error); + } else { + // Read error notification on socket observer pipe got delivered first; + // save error code for read pipe closure to deliver. + saw_read_error_on_socket_observer_pipe_ = net_error; + } +} + +void NetworkServiceAsyncSocket::OnWriteError(int32_t net_error) { + // Ignore redundant error messages. + if (saw_write_error_on_socket_observer_pipe_ != net::ERR_IO_PENDING) + return; + + // Sanitize any invalid error code, + if (net_error >= 0 || net_error == net::ERR_IO_PENDING) + net_error = net::ERR_FAILED; + if (saw_error_on_write_pipe_) { + // Write pipe closure got delivered first, and so with the socket observer + // notification here, both pipes got fully handled. + DoNetErrorFromStatus(net_error); + DoClose(); + } else { + // Write error notification on socket observer pipe got delivered first; + // save error code for write pipe closure to deliver. + saw_write_error_on_socket_observer_pipe_ = net_error; + } +} + // STATE_CLOSED -> STATE_CONNECTING -bool ChromeAsyncSocket::Connect(const rtc::SocketAddress& address) { +bool NetworkServiceAsyncSocket::Connect(const rtc::SocketAddress& address) { if (state_ != STATE_CLOSED) { LOG(DFATAL) << "Connect() called on non-closed socket"; DoNonNetError(ERROR_WRONGSTATE); @@ -105,33 +153,33 @@ bool ChromeAsyncSocket::Connect(const rtc::SocketAddress& address) { state_ = STATE_CONNECTING; - DCHECK(!weak_ptr_factory_.HasWeakPtrs()); - weak_ptr_factory_.InvalidateWeakPtrs(); - net::HostPortPair dest_host_port_pair(address.hostname(), address.port()); - transport_socket_ = - resolving_client_socket_factory_->CreateTransportClientSocket( - dest_host_port_pair); - int status = transport_socket_->Connect( - base::Bind(&ChromeAsyncSocket::ProcessConnectDone, - weak_ptr_factory_.GetWeakPtr())); - if (status != net::ERR_IO_PENDING) { - // We defer execution of ProcessConnectDone instead of calling it - // directly here as the caller may not expect an error/close to - // happen here. This is okay, as from the caller's point of view, - // the connect always happens asynchronously. - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&ChromeAsyncSocket::ProcessConnectDone, - weak_ptr_factory_.GetWeakPtr(), status)); - } + get_socket_factory_callback_.Run(mojo::MakeRequest(&socket_factory_)); + + network::mojom::SocketObserverPtr socket_observer; + network::mojom::SocketObserverRequest socket_observer_request = + mojo::MakeRequest(&socket_observer); + socket_factory_->CreateProxyResolvingSocket( + GURL("https://" + dest_host_port_pair.ToString()), false /*use_tls*/, + net::MutableNetworkTrafficAnnotationTag(traffic_annotation_), + mojo::MakeRequest(&socket_), std::move(socket_observer), + base::BindOnce(&NetworkServiceAsyncSocket::ProcessConnectDone, + base::Unretained(this), + std::move(socket_observer_request))); return true; } // STATE_CONNECTING -> STATE_OPEN -// read_state_ == IDLE -> read_state_ == POSTED (via PostDoRead()) - -void ChromeAsyncSocket::ProcessConnectDone(int status) { +// read_state_ == IDLE -> read_state_ == WAITING (via WatchForReadReady()) + +void NetworkServiceAsyncSocket::ProcessConnectDone( + network::mojom::SocketObserverRequest socket_observer_request, + int status, + const base::Optional& local_addr, + const base::Optional& peer_addr, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream) { DCHECK_NE(status, net::ERR_IO_PENDING); DCHECK_EQ(read_state_, IDLE); DCHECK_EQ(write_state_, IDLE); @@ -142,74 +190,87 @@ void ChromeAsyncSocket::ProcessConnectDone(int status) { return; } state_ = STATE_OPEN; - PostDoRead(); + ConnectPipes(std::move(receive_stream), std::move(send_stream)); + BindSocketObserver(std::move(socket_observer_request)); + + WatchForReadReady(); // Write buffer should be empty. DCHECK_EQ(write_end_, 0U); SignalConnected(); } -// read_state_ == IDLE -> read_state_ == POSTED +// read_state_ == IDLE -> read_state_ == WAITING -void ChromeAsyncSocket::PostDoRead() { +void NetworkServiceAsyncSocket::WatchForReadReady() { + // Note that this never transitions to ProcessReadReady immediately; which + // avoids potentially error-prone synchronous notifications from within + // methods like Connect() and Read(). DCHECK(IsOpen()); DCHECK_EQ(read_state_, IDLE); DCHECK_EQ(read_start_, 0U); DCHECK_EQ(read_end_, 0U); - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&ChromeAsyncSocket::DoRead, weak_ptr_factory_.GetWeakPtr())); - read_state_ = POSTED; -} - -// read_state_ == POSTED -> read_state_ == PENDING -void ChromeAsyncSocket::DoRead() { - DCHECK(IsOpen()); - DCHECK_EQ(read_state_, POSTED); - DCHECK_EQ(read_start_, 0U); - DCHECK_EQ(read_end_, 0U); // Once we call Read(), we cannot call StartTls() until the read // finishes. This is okay, as StartTls() is called only from a read // handler (i.e., after a read finishes and before another read is // done). - int status = - transport_socket_->Read( - read_buf_.get(), read_buf_->size(), - base::Bind(&ChromeAsyncSocket::ProcessReadDone, - weak_ptr_factory_.GetWeakPtr())); - read_state_ = PENDING; - if (status != net::ERR_IO_PENDING) { - ProcessReadDone(status); - } + read_state_ = WAITING; + read_watcher_->ArmOrNotify(); } -// read_state_ == PENDING -> read_state_ == IDLE +// read_state_ == WAITING -> read_state_ == IDLE -void ChromeAsyncSocket::ProcessReadDone(int status) { - DCHECK_NE(status, net::ERR_IO_PENDING); +void NetworkServiceAsyncSocket::ProcessReadReady( + MojoResult result, + const mojo::HandleSignalsState& state) { DCHECK(IsOpen()); - DCHECK_EQ(read_state_, PENDING); + DCHECK_EQ(read_state_, WAITING); DCHECK_EQ(read_start_, 0U); DCHECK_EQ(read_end_, 0U); read_state_ = IDLE; - if (status > 0) { - read_end_ = static_cast(status); - SignalRead(); - } else if (status == 0) { + + uint32_t num_bytes = read_buf_.size(); + if (result == MOJO_RESULT_OK && !state.peer_closed()) { + result = read_pipe_->ReadData(read_buf_.data(), &num_bytes, + MOJO_READ_DATA_FLAG_NONE); + if (result == MOJO_RESULT_SHOULD_WAIT) { + WatchForReadReady(); + return; + } + } + + if (result != MOJO_RESULT_OK || !num_bytes || state.peer_closed()) { + // The pipe is closed on any error, or EOF. + if (saw_read_error_on_socket_observer_pipe_ != net::ERR_IO_PENDING) { + // Already saw socket observer's notification, report result. + ReportReadError(saw_read_error_on_socket_observer_pipe_); + } else { + // This got delivered before the error code from socket observer, let it + // know it's responsible for reporting the error/EOF. + saw_error_on_read_pipe_ = true; + } + return; + } + + read_end_ = num_bytes; + SignalRead(); +} + +void NetworkServiceAsyncSocket::ReportReadError(int net_error) { + if (net_error == 0) { // Other side closed the connection. error_ = ERROR_NONE; net_error_ = net::OK; - DoClose(); - } else { // status < 0 - DoNetErrorFromStatus(status); - DoClose(); + } else { + DoNetErrorFromStatus(net_error); } + DoClose(); } -// (maybe) read_state_ == IDLE -> read_state_ == POSTED (via -// PostDoRead()) +// (maybe) read_state_ == IDLE -> read_state_ == WAITING (via +// WatchForReadReady()) -bool ChromeAsyncSocket::Read(char* data, size_t len, size_t* len_read) { +bool NetworkServiceAsyncSocket::Read(char* data, size_t len, size_t* len_read) { if (!IsOpen() && (state_ != STATE_TLS_CONNECTING)) { // Read() may be called on a closed socket if a previous read // causes a socket close (e.g., client sends wrong password and @@ -236,22 +297,20 @@ bool ChromeAsyncSocket::Read(char* data, size_t len, size_t* len_read) { DCHECK_EQ(read_state_, IDLE); *len_read = std::min(len, read_end_ - read_start_); DCHECK_GT(*len_read, 0U); - std::memcpy(data, read_buf_->data() + read_start_, *len_read); + std::memcpy(data, read_buf_.data() + read_start_, *len_read); read_start_ += *len_read; if (read_start_ == read_end_) { read_start_ = 0U; read_end_ = 0U; - // We defer execution of DoRead() here for similar reasons as - // ProcessConnectDone(). - PostDoRead(); + WatchForReadReady(); } return true; } -// (maybe) write_state_ == IDLE -> write_state_ == POSTED (via -// PostDoWrite()) +// (maybe) write_state_ == IDLE -> write_state_ == WAITING (via +// WatchForWriteReady()) -bool ChromeAsyncSocket::Write(const char* data, size_t len) { +bool NetworkServiceAsyncSocket::Write(const char* data, size_t len) { if (!IsOpen() && (state_ != STATE_TLS_CONNECTING)) { LOG(DFATAL) << "Write() called on non-open non-tls-connecting socket"; DoNonNetError(ERROR_WRONGSTATE); @@ -259,75 +318,73 @@ bool ChromeAsyncSocket::Write(const char* data, size_t len) { } // TODO(akalin): Avoid this check by modifying the interface to have // a "ready for writing" signal. - if ((static_cast(write_buf_->size()) - write_end_) < len) { + if ((static_cast(write_buf_.size()) - write_end_) < len) { LOG(DFATAL) << "queueing " << len << " bytes would exceed the " - << "max write buffer size = " << write_buf_->size() - << " by " << (len - write_buf_->size()) << " bytes"; + << "max write buffer size = " << write_buf_.size() << " by " + << (len - write_buf_.size()) << " bytes"; DoNetError(net::ERR_INSUFFICIENT_RESOURCES); return false; } - std::memcpy(write_buf_->data() + write_end_, data, len); + std::memcpy(write_buf_.data() + write_end_, data, len); write_end_ += len; // If we're TLS-connecting, the write buffer will get flushed once // the TLS-connect finishes. Otherwise, start writing if we're not // already writing and we have something to write. - if ((state_ != STATE_TLS_CONNECTING) && - (write_state_ == IDLE) && (write_end_ > 0U)) { - // We defer execution of DoWrite() here for similar reasons as - // ProcessConnectDone(). - PostDoWrite(); + if ((state_ != STATE_TLS_CONNECTING) && (write_state_ == IDLE) && + (write_end_ > 0U)) { + WatchForWriteReady(); } return true; } -// write_state_ == IDLE -> write_state_ == POSTED +// write_state_ == IDLE -> write_state_ == WAITING -void ChromeAsyncSocket::PostDoWrite() { +void NetworkServiceAsyncSocket::WatchForWriteReady() { + // Note that this never transitions to ProcessWriteReady immediately; which + // avoids potentially error-prone synchronous notifications from within + // methods like Write(). DCHECK(IsOpen()); DCHECK_EQ(write_state_, IDLE); DCHECK_GT(write_end_, 0U); - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&ChromeAsyncSocket::DoWrite, weak_ptr_factory_.GetWeakPtr())); - write_state_ = POSTED; -} - -// write_state_ == POSTED -> write_state_ == PENDING -void ChromeAsyncSocket::DoWrite() { - DCHECK(IsOpen()); - DCHECK_EQ(write_state_, POSTED); - DCHECK_GT(write_end_, 0U); // Once we call Write(), we cannot call StartTls() until the write // finishes. This is okay, as StartTls() is called only after we // have received a reply to a message we sent to the server and // before we send the next message. - int status = - transport_socket_->Write(write_buf_.get(), write_end_, - base::Bind(&ChromeAsyncSocket::ProcessWriteDone, - weak_ptr_factory_.GetWeakPtr()), - traffic_annotation_); - write_state_ = PENDING; - if (status != net::ERR_IO_PENDING) { - ProcessWriteDone(status); - } + write_state_ = WAITING; + write_watcher_->ArmOrNotify(); } -// write_state_ == PENDING -> write_state_ == IDLE or POSTED (the -// latter via PostDoWrite()) +// write_state_ == WAITING -> write_state_ == IDLE or WAITING (the +// latter via WatchForWriteReady()) -void ChromeAsyncSocket::ProcessWriteDone(int status) { - DCHECK_NE(status, net::ERR_IO_PENDING); +void NetworkServiceAsyncSocket::ProcessWriteReady( + MojoResult result, + const mojo::HandleSignalsState& state) { DCHECK(IsOpen()); - DCHECK_EQ(write_state_, PENDING); + DCHECK_EQ(write_state_, WAITING); DCHECK_GT(write_end_, 0U); write_state_ = IDLE; - if (status < net::OK) { - DoNetErrorFromStatus(status); - DoClose(); + + // Write errors are handled in ProcessWriteClosed. + uint32_t written = write_end_; + if (result == MOJO_RESULT_OK) { + result = write_pipe_->WriteData(write_buf_.data(), &written, + MOJO_WRITE_DATA_FLAG_NONE); + } + + if (result == MOJO_RESULT_SHOULD_WAIT) { + WatchForWriteReady(); return; } - size_t written = static_cast(status); + + if (result != MOJO_RESULT_OK) { + DCHECK(socket_observer_binding_.is_bound()); + // Unlike with reads, as the pipe close notifier for writes is independent + // and always armed, it can take care of all the errors. + return; + } + if (written > write_end_) { LOG(DFATAL) << "bytes written = " << written << " exceeds bytes requested = " << write_end_; @@ -338,35 +395,63 @@ void ChromeAsyncSocket::ProcessWriteDone(int status) { // TODO(akalin): Figure out a better way to do this; perhaps a queue // of DrainableIOBuffers. This'll also allow us to not have an // artificial buffer size limit. - std::memmove(write_buf_->data(), - write_buf_->data() + written, + std::memmove(write_buf_.data(), write_buf_.data() + written, write_end_ - written); write_end_ -= written; if (write_end_ > 0U) { - PostDoWrite(); + WatchForWriteReady(); + } +} + +void NetworkServiceAsyncSocket::ProcessWriteClosed( + MojoResult result, + const mojo::HandleSignalsState& state) { + DCHECK(state.peer_closed()); + + // The pipe is closed on any error, or EOF. + if (saw_write_error_on_socket_observer_pipe_ != net::ERR_IO_PENDING) { + // Already saw socket observer's notification, report result. + DoNetErrorFromStatus(saw_write_error_on_socket_observer_pipe_); + DoClose(); + } else { + // This got delivered before the error code from socket observer, let it + // know it's responsible for reporting the error/EOF. + saw_error_on_write_pipe_ = true; } } // * -> STATE_CLOSED -bool ChromeAsyncSocket::Close() { +bool NetworkServiceAsyncSocket::Close() { DoClose(); return true; } // (not STATE_CLOSED) -> STATE_CLOSED -void ChromeAsyncSocket::DoClose() { - weak_ptr_factory_.InvalidateWeakPtrs(); - if (transport_socket_.get()) { - transport_socket_->Disconnect(); - } - transport_socket_.reset(); +void NetworkServiceAsyncSocket::DoClose() { + // As this closes all the mojo pipes and destroys all the watchers it also + // cancels all pending async operations. read_state_ = IDLE; read_start_ = 0U; read_end_ = 0U; + read_pipe_.reset(); + read_watcher_.reset(); + saw_error_on_read_pipe_ = false; + saw_error_on_write_pipe_ = false; + saw_read_error_on_socket_observer_pipe_ = net::ERR_IO_PENDING; + saw_write_error_on_socket_observer_pipe_ = net::ERR_IO_PENDING; write_state_ = IDLE; write_end_ = 0U; + write_pipe_.reset(); + write_watcher_.reset(); + write_close_watcher_.reset(); + + socket_ = nullptr; + tls_socket_ = nullptr; + socket_observer_binding_.Close(); + socket_factory_ = nullptr; + if (state_ != STATE_CLOSED) { state_ = STATE_CLOSED; SignalClosed(); @@ -379,9 +464,9 @@ void ChromeAsyncSocket::DoClose() { // STATE_OPEN -> STATE_TLS_CONNECTING -bool ChromeAsyncSocket::StartTls(const std::string& domain_name) { - if ((state_ != STATE_OPEN) || (read_state_ == PENDING) || - (write_state_ != IDLE)) { +bool NetworkServiceAsyncSocket::StartTls(const std::string& domain_name) { + DCHECK_EQ(IDLE, write_state_); + if (state_ != STATE_OPEN) { LOG(DFATAL) << "StartTls() called in wrong state"; DoNonNetError(ERROR_WRONGSTATE); return false; @@ -393,32 +478,36 @@ bool ChromeAsyncSocket::StartTls(const std::string& domain_name) { read_end_ = 0U; DCHECK_EQ(write_end_, 0U); - // Clear out any posted DoRead() tasks. - weak_ptr_factory_.InvalidateWeakPtrs(); - - DCHECK(transport_socket_.get()); - std::unique_ptr socket_handle( - new net::ClientSocketHandle()); - socket_handle->SetSocket(std::move(transport_socket_)); - transport_socket_ = resolving_client_socket_factory_->CreateSSLClientSocket( - std::move(socket_handle), net::HostPortPair(domain_name, 443)); - int status = transport_socket_->Connect( - base::Bind(&ChromeAsyncSocket::ProcessSSLConnectDone, - weak_ptr_factory_.GetWeakPtr())); - if (status != net::ERR_IO_PENDING) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&ChromeAsyncSocket::ProcessSSLConnectDone, - weak_ptr_factory_.GetWeakPtr(), status)); - } + read_watcher_ = nullptr; + read_pipe_.reset(); + write_watcher_ = nullptr; + write_close_watcher_ = nullptr; + write_pipe_.reset(); + socket_observer_binding_.Close(); + network::mojom::SocketObserverPtr socket_observer; + network::mojom::SocketObserverRequest socket_observer_request = + mojo::MakeRequest(&socket_observer); + + socket_->UpgradeToTLS( + net::HostPortPair(domain_name, 443), + net::MutableNetworkTrafficAnnotationTag(traffic_annotation_), + mojo::MakeRequest(&tls_socket_), std::move(socket_observer), + base::BindOnce(&NetworkServiceAsyncSocket::ProcessSSLConnectDone, + base::Unretained(this), + std::move(socket_observer_request))); return true; } // STATE_TLS_CONNECTING -> STATE_TLS_OPEN -// read_state_ == IDLE -> read_state_ == POSTED (via PostDoRead()) -// (maybe) write_state_ == IDLE -> write_state_ == POSTED (via -// PostDoWrite()) - -void ChromeAsyncSocket::ProcessSSLConnectDone(int status) { +// read_state_ == IDLE -> read_state_ == WAITING (via WatchForReadReady()) +// (maybe) write_state_ == IDLE -> write_state_ == WAITING (via +// WatchForWriteReady()) + +void NetworkServiceAsyncSocket::ProcessSSLConnectDone( + network::mojom::SocketObserverRequest socket_observer_request, + int status, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream) { DCHECK_NE(status, net::ERR_IO_PENDING); DCHECK_EQ(state_, STATE_TLS_CONNECTING); DCHECK_EQ(read_state_, IDLE); @@ -431,11 +520,57 @@ void ChromeAsyncSocket::ProcessSSLConnectDone(int status) { return; } state_ = STATE_TLS_OPEN; - PostDoRead(); + ConnectPipes(std::move(receive_stream), std::move(send_stream)); + BindSocketObserver(std::move(socket_observer_request)); + + WatchForReadReady(); if (write_end_ > 0U) { - PostDoWrite(); + WatchForWriteReady(); } SignalSSLConnected(); } +void NetworkServiceAsyncSocket::ConnectPipes( + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream) { + read_pipe_ = std::move(receive_stream); + read_watcher_ = std::make_unique( + FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL); + read_watcher_->Watch( + read_pipe_.get(), + MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + base::BindRepeating(&NetworkServiceAsyncSocket::ProcessReadReady, + base::Unretained(this))); + + write_pipe_ = std::move(send_stream); + write_watcher_ = std::make_unique( + FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL); + write_watcher_->Watch( + write_pipe_.get(), MOJO_HANDLE_SIGNAL_WRITABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + base::BindRepeating(&NetworkServiceAsyncSocket::ProcessWriteReady, + base::Unretained(this))); + + // Write pipe close gets a separate watcher to look for signs of trouble + // even when no write is pending. (Read doesn't need one since reads are + // always watched for). + write_close_watcher_ = std::make_unique( + FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL); + write_close_watcher_->Watch( + write_pipe_.get(), MOJO_HANDLE_SIGNAL_PEER_CLOSED, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + base::BindRepeating(&NetworkServiceAsyncSocket::ProcessWriteClosed, + base::Unretained(this))); + write_close_watcher_->ArmOrNotify(); +} + +void NetworkServiceAsyncSocket::BindSocketObserver( + network::mojom::SocketObserverRequest socket_observer_request) { + socket_observer_binding_.Bind(std::move(socket_observer_request)); + socket_observer_binding_.set_connection_error_handler( + base::BindOnce(&NetworkServiceAsyncSocket::ProcessSocketObserverError, + base::Unretained(this))); +} + } // namespace jingle_glue diff --git a/jingle/glue/network_service_async_socket.h b/jingle/glue/network_service_async_socket.h index 1612357fdcbde8..fb904878f0a372 100644 --- a/jingle/glue/network_service_async_socket.h +++ b/jingle/glue/network_service_async_socket.h @@ -2,10 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// An implementation of buzz::AsyncSocket that uses Chrome sockets. +// An implementation of buzz::AsyncSocket that uses Chrome Network Service +// sockets. -#ifndef JINGLE_GLUE_CHROME_ASYNC_SOCKET_H_ -#define JINGLE_GLUE_CHROME_ASYNC_SOCKET_H_ +#ifndef JINGLE_GLUE_NETWORK_SERVICE_ASYNC_SOCKET_H_ +#define JINGLE_GLUE_NETWORK_SERVICE_ASYNC_SOCKET_H_ #include @@ -13,35 +14,32 @@ #include #include -#include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "net/base/completion_callback.h" -#include "net/base/net_errors.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/system/data_pipe.h" +#include "mojo/public/cpp/system/simple_watcher.h" #include "net/traffic_annotation/network_traffic_annotation.h" +#include "services/network/public/mojom/proxy_resolving_socket.mojom.h" #include "third_party/libjingle_xmpp/xmpp/asyncsocket.h" -namespace net { -class IOBufferWithSize; -class StreamSocket; -} // namespace net - namespace jingle_glue { -class ResolvingClientSocketFactory; +using GetProxyResolvingFactoryCallback = base::RepeatingCallback; -class ChromeAsyncSocket : public buzz::AsyncSocket { +class NetworkServiceAsyncSocket : public buzz::AsyncSocket, + public network::mojom::SocketObserver { public: - // Takes ownership of |resolving_client_socket_factory|. - ChromeAsyncSocket(std::unique_ptr - resolving_client_socket_factory, - size_t read_buf_size, - size_t write_buf_size, - const net::NetworkTrafficAnnotationTag& traffic_annotation); + NetworkServiceAsyncSocket( + GetProxyResolvingFactoryCallback get_socket_factory_callback, + size_t read_buf_size, + size_t write_buf_size, + const net::NetworkTrafficAnnotationTag& traffic_annotation); // Does not raise any signals. - ~ChromeAsyncSocket() override; + ~NetworkServiceAsyncSocket() override; // buzz::AsyncSocket implementation. @@ -65,9 +63,8 @@ class ChromeAsyncSocket : public buzz::AsyncSocket { // // If |address| has an empty hostname or a zero port, sets error to // ERROR_DNS and returns false. (We don't use the IP address even - // if it's present, as DNS resolution is done by - // |resolving_client_socket_factory_|. But it's perfectly fine if - // the hostname is a stringified IP address.) + // if it's present, as DNS resolution is done by the network service). + // But it's perfectly fine if the hostname is a stringified IP address.) // // Otherwise, starts the connection process and returns true. // SignalConnected will be raised when the connection is successful; @@ -146,12 +143,11 @@ class ChromeAsyncSocket : public buzz::AsyncSocket { private: enum AsyncIOState { - // An I/O op is not in progress. + // An I/O op is not in progress or has been handed over to the network + // service. IDLE, - // A function has been posted to do the I/O. - POSTED, - // An async I/O operation is pending. - PENDING, + // Waiting for network service to be ready to handle an operation. + WAITING, }; bool IsOpen() const; @@ -160,61 +156,108 @@ class ChromeAsyncSocket : public buzz::AsyncSocket { void DoNonNetError(Error error); void DoNetError(net::Error net_error); void DoNetErrorFromStatus(int status); + void ProcessSocketObserverError(); + + // SocketObserver implementation + void OnReadError(int32_t net_error) override; + void OnWriteError(int32_t net_error) override; // Connection functions. - void ProcessConnectDone(int status); + void ProcessConnectDone( + network::mojom::SocketObserverRequest socket_observer_request, + int status, + const base::Optional& local_addr, + const base::Optional& peer_addr, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream); // Read loop functions. - void PostDoRead(); - void DoRead(); - void ProcessReadDone(int status); + void WatchForReadReady(); + void ProcessReadReady(MojoResult result, + const mojo::HandleSignalsState& state); + void ReportReadError(int net_error); // Write loop functions. - void PostDoWrite(); - void DoWrite(); - void ProcessWriteDone(int status); + void WatchForWriteReady(); + void ProcessWriteReady(MojoResult result, + const mojo::HandleSignalsState& state); + void ProcessWriteClosed(MojoResult result, + const mojo::HandleSignalsState& state); // SSL/TLS connection functions. - void ProcessSSLConnectDone(int status); + void ProcessSSLConnectDone( + network::mojom::SocketObserverRequest socket_observer_request, + int status, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream); // Close functions. void DoClose(); - std::unique_ptr - resolving_client_socket_factory_; + void ConnectPipes(mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream); + void BindSocketObserver( + network::mojom::SocketObserverRequest socket_observer_request); + + // |socket_factory_| is recreated every time via |get_socket_factory_callback| + // to handle network service restarts after crashes. + GetProxyResolvingFactoryCallback get_socket_factory_callback_; + network::mojom::ProxyResolvingSocketFactoryPtr socket_factory_; + // The handle to the proxy resolving socket for the current connection, if one + // exists. + network::mojom::ProxyResolvingSocketPtr socket_; + // TLS socket, if StartTls has been called. + network::mojom::TLSClientSocketPtr tls_socket_; + + // Used to route error notifications here. + mojo::Binding socket_observer_binding_; // buzz::AsyncSocket state. buzz::AsyncSocket::State state_; buzz::AsyncSocket::Error error_; net::Error net_error_; - // NULL iff state() == STATE_CLOSED. - std::unique_ptr transport_socket_; - // State for the read loop. |read_start_| <= |read_end_| <= // |read_buf_->size()|. There's a read in flight (i.e., // |read_state_| != IDLE) iff |read_end_| == 0. AsyncIOState read_state_; - scoped_refptr read_buf_; + std::vector read_buf_; size_t read_start_, read_end_; + mojo::ScopedDataPipeConsumerHandle read_pipe_; + std::unique_ptr read_watcher_; + + // Handling read errors is a bit tricky since the status is reported via + // |socket_observer_binding_|, which is unordered compared to |read_pipe_|, + // so it's possible to see an end of file (or an error) there while there is + // still useful data pending. As a result, the code waits to see both happen + // before reporting error statuses (including EOF). Likewise for write pipes. + // + bool saw_error_on_read_pipe_; + bool saw_error_on_write_pipe_; + + // This is != net::ERR_IO_PENDING (including possibly net::OK for end-of-file) + // if a read error was reported via socket observer interface. + int saw_read_error_on_socket_observer_pipe_; + int saw_write_error_on_socket_observer_pipe_; // State for the write loop. |write_end_| <= |write_buf_->size()|. // There's a write in flight (i.e., |write_state_| != IDLE) iff // |write_end_| > 0. AsyncIOState write_state_; - scoped_refptr write_buf_; + std::vector write_buf_; size_t write_end_; + mojo::ScopedDataPipeProducerHandle write_pipe_; + std::unique_ptr write_watcher_; + std::unique_ptr write_close_watcher_; - // Network traffic annotation for downstream socket write. ChromeAsyncSocket - // is not reused, hence annotation can be added in constructor and used in all - // subsequent writes. + // Network traffic annotation for downstream socket write. + // NetworkServiceAsyncSocket is not reused, hence annotation can be added in + // constructor and used in all subsequent writes. const net::NetworkTrafficAnnotationTag traffic_annotation_; - base::WeakPtrFactory weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(ChromeAsyncSocket); + DISALLOW_COPY_AND_ASSIGN(NetworkServiceAsyncSocket); }; } // namespace jingle_glue -#endif // JINGLE_GLUE_CHROME_ASYNC_SOCKET_H_ +#endif // JINGLE_GLUE_NETWORK_SERVICE_ASYNC_SOCKET_H_ diff --git a/jingle/glue/network_service_async_socket_unittest.cc b/jingle/glue/network_service_async_socket_unittest.cc index 65b9d9a7c07a9f..da455e70fa0ba6 100644 --- a/jingle/glue/network_service_async_socket_unittest.cc +++ b/jingle/glue/network_service_async_socket_unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "jingle/glue/chrome_async_socket.h" +#include "jingle/glue/network_service_async_socket.h" #include @@ -13,10 +13,14 @@ #include "base/containers/circular_deque.h" #include "base/logging.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" #include "base/message_loop/message_pump_default.h" #include "base/run_loop.h" -#include "jingle/glue/resolving_client_socket_factory.h" +#include "base/strings/strcat.h" +#include "base/strings/string_number_conversions.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/system/data_pipe_utils.h" #include "net/base/address_list.h" #include "net/base/ip_address.h" #include "net/base/net_errors.h" @@ -27,7 +31,9 @@ #include "net/socket/ssl_client_socket.h" #include "net/ssl/ssl_config_service.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" -#include "net/url_request/url_request_context_getter.h" +#include "net/url_request/url_request_test_util.h" +#include "services/network/proxy_resolving_socket_factory_mojo.h" +#include "services/network/public/mojom/proxy_resolving_socket.mojom.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/webrtc/rtc_base/ipaddress.h" #include "third_party/webrtc/rtc_base/socketaddress.h" @@ -37,7 +43,7 @@ namespace jingle_glue { namespace { -// Data provider that handles reads/writes for ChromeAsyncSocket. +// Data provider that handles reads/writes for NetworkServiceAsyncSocket. class AsyncSocketDataProvider : public net::SocketDataProvider { public: AsyncSocketDataProvider() : has_pending_read_(false) {} @@ -61,6 +67,11 @@ class AsyncSocketDataProvider : public net::SocketDataProvider { return mock_read; } + void CancelPendingRead() override { + DCHECK(has_pending_read_); + has_pending_read_ = false; + } + // Simply pops the next write and, if applicable, compares it to // |data|. net::MockWriteResult OnWrite(const std::string& data) override { @@ -87,8 +98,8 @@ class AsyncSocketDataProvider : public net::SocketDataProvider { void AddRead(const net::MockRead& mock_read) { DCHECK_NE(mock_read.result, net::ERR_IO_PENDING); if (has_pending_read_) { - socket()->OnReadComplete(mock_read); has_pending_read_ = false; + socket()->OnReadComplete(mock_read); return; } reads_.push_back(mock_read); @@ -99,13 +110,9 @@ class AsyncSocketDataProvider : public net::SocketDataProvider { writes_.push_back(mock_write); } - bool AllReadDataConsumed() const override { - return reads_.empty(); - } + bool AllReadDataConsumed() const override { return reads_.empty(); } - bool AllWriteDataConsumed() const override { - return writes_.empty(); - } + bool AllWriteDataConsumed() const override { return writes_.empty(); } private: base::circular_deque reads_; @@ -116,47 +123,157 @@ class AsyncSocketDataProvider : public net::SocketDataProvider { DISALLOW_COPY_AND_ASSIGN(AsyncSocketDataProvider); }; -class MockXmppClientSocketFactory : public ResolvingClientSocketFactory { +class MockProxyResolvingSocket : public network::mojom::ProxyResolvingSocket { public: - MockXmppClientSocketFactory( - std::unique_ptr mock_client_socket_factory, - const net::AddressList& address_list) - : mock_client_socket_factory_(std::move(mock_client_socket_factory)), - address_list_(address_list), - cert_verifier_(new net::MockCertVerifier), - transport_security_state_(new net::TransportSecurityState) {} - - // ResolvingClientSocketFactory implementation. - std::unique_ptr CreateTransportClientSocket( - const net::HostPortPair& host_and_port) override { - return mock_client_socket_factory_->CreateTransportClientSocket( - address_list_, NULL, NULL, net::NetLogSource()); + enum Event { + // These names are from the perspective of the client, not the socket. + kRead, + kWrite, + kCloseReadPipe, + kCloseWritePipe, + kReadError, + kReadErrorInvalid, + kWriteError, + kWriteErrorInvalid, + kReadEofError, + kCloseObserverPipe, + }; + + MockProxyResolvingSocket() {} + ~MockProxyResolvingSocket() override {} + + void Connect(network::mojom::SocketObserverPtr observer, + network::mojom::ProxyResolvingSocketFactory:: + CreateProxyResolvingSocketCallback callback) { + mojo::DataPipe send_pipe; + mojo::DataPipe receive_pipe; + + observer_ = std::move(observer); + receive_pipe_handle_ = std::move(receive_pipe.producer_handle); + send_pipe_handle_ = std::move(send_pipe.consumer_handle); + + std::move(callback).Run(net::OK, base::nullopt, base::nullopt, + std::move(receive_pipe.consumer_handle), + std::move(send_pipe.producer_handle)); } - std::unique_ptr CreateSSLClientSocket( - std::unique_ptr transport_socket, - const net::HostPortPair& host_and_port) override { - net::SSLClientSocketContext context; - context.cert_verifier = cert_verifier_.get(); - context.transport_security_state = transport_security_state_.get(); - return mock_client_socket_factory_->CreateSSLClientSocket( - std::move(transport_socket), host_and_port, ssl_config_, context); + void RunEvents(std::vector&& events); + + // mojom::ProxyResolvingSocket implementation. + void UpgradeToTLS( + const net::HostPortPair& host_port_pair, + const net::MutableNetworkTrafficAnnotationTag& traffic_annotation, + network::mojom::TLSClientSocketRequest request, + network::mojom::SocketObserverPtr observer, + network::mojom::ProxyResolvingSocket::UpgradeToTLSCallback callback) + override { + NOTREACHED(); } private: - std::unique_ptr mock_client_socket_factory_; - net::AddressList address_list_; - net::SSLConfig ssl_config_; - std::unique_ptr cert_verifier_; - std::unique_ptr transport_security_state_; + network::mojom::SocketObserverPtr observer_; + mojo::ScopedDataPipeProducerHandle receive_pipe_handle_; + mojo::ScopedDataPipeConsumerHandle send_pipe_handle_; + + DISALLOW_COPY_AND_ASSIGN(MockProxyResolvingSocket); }; -class ChromeAsyncSocketTest - : public testing::Test, - public sigslot::has_slots<> { +class MockProxyResolvingSocketFactory + : public network::mojom::ProxyResolvingSocketFactory { + public: + explicit MockProxyResolvingSocketFactory() : socket_raw_(nullptr) {} + ~MockProxyResolvingSocketFactory() override {} + + // mojom::ProxyResolvingSocketFactory implementation. + void CreateProxyResolvingSocket( + const GURL& url, + bool use_tls, + const net::MutableNetworkTrafficAnnotationTag& traffic_annotation, + network::mojom::ProxyResolvingSocketRequest request, + network::mojom::SocketObserverPtr observer, + CreateProxyResolvingSocketCallback callback) override { + auto socket = std::make_unique(); + socket_raw_ = socket.get(); + proxy_resolving_socket_bindings_.AddBinding(std::move(socket), + std::move(request)); + socket_raw_->Connect(std::move(observer), std::move(callback)); + } + + MockProxyResolvingSocket* socket() { return socket_raw_; } + + private: + mojo::StrongBindingSet + proxy_resolving_socket_bindings_; + + // Owned by |proxy_resolving_socket_bindings_|. + MockProxyResolvingSocket* socket_raw_; + + DISALLOW_COPY_AND_ASSIGN(MockProxyResolvingSocketFactory); +}; + +void MockProxyResolvingSocket::RunEvents(std::vector&& events) { + for (Event ev : events) { + switch (ev) { + case kRead: + mojo::BlockingCopyFromString("data", receive_pipe_handle_); + break; + case kWrite: { + std::string written; + while (true) { + char read_buffer[1024]; + uint32_t read_size = sizeof(read_buffer); + MojoResult result = send_pipe_handle_->ReadData( + read_buffer, &read_size, MOJO_READ_DATA_FLAG_NONE); + if (result != MOJO_RESULT_OK) + break; + written.append(read_buffer, read_size); + } + + EXPECT_EQ("atad", written); + break; + } + case kCloseReadPipe: + receive_pipe_handle_.reset(); + break; + case kCloseWritePipe: + send_pipe_handle_.reset(); + break; + case kReadError: + observer_->OnReadError(net::ERR_OUT_OF_MEMORY); + observer_.FlushForTesting(); + break; + case kReadErrorInvalid: + observer_->OnReadError(42); + observer_.FlushForTesting(); + break; + case kWriteError: + observer_->OnWriteError(net::ERR_ACCESS_DENIED); + observer_.FlushForTesting(); + break; + case kWriteErrorInvalid: + observer_->OnWriteError(net::ERR_IO_PENDING); + observer_.FlushForTesting(); + break; + case kReadEofError: + observer_->OnReadError(0); + observer_.FlushForTesting(); + break; + case kCloseObserverPipe: + observer_.reset(); + break; + } + // Make sure the event is actually delivered. + base::RunLoop().RunUntilIdle(); + } +} + +class NetworkServiceAsyncSocketTest : public testing::Test, + public sigslot::has_slots<> { protected: - ChromeAsyncSocketTest() + explicit NetworkServiceAsyncSocketTest(bool use_mojo_level_mock = false) : ssl_socket_data_provider_(net::ASYNC, net::OK), + use_mojo_level_mock_(use_mojo_level_mock), + mock_proxy_resolving_socket_factory_(nullptr), addr_("localhost", 35) { // GTest death tests by default execute in a fork()ed but not exec()ed // process. On macOS, a CoreFoundation-backed MessageLoop will exit with a @@ -165,36 +282,53 @@ class ChromeAsyncSocketTest testing::GTEST_FLAG(death_test_style) = "threadsafe"; } - ~ChromeAsyncSocketTest() override {} + ~NetworkServiceAsyncSocketTest() override {} void SetUp() override { - std::unique_ptr mock_client_socket_factory( - new net::MockClientSocketFactory()); - mock_client_socket_factory->AddSocketDataProvider( + mock_client_socket_factory_ = + std::make_unique(); + mock_client_socket_factory_->set_enable_read_if_ready(true); + mock_client_socket_factory_->AddSocketDataProvider( &async_socket_data_provider_); - mock_client_socket_factory->AddSSLSocketDataProvider( + mock_client_socket_factory_->AddSSLSocketDataProvider( &ssl_socket_data_provider_); - // Fake DNS resolution for |addr_| and pass it to the factory. - const net::AddressList address_list = net::AddressList::CreateFromIPAddress( - net::IPAddress::IPv4Localhost(), addr_.port()); - std::unique_ptr - mock_xmpp_client_socket_factory(new MockXmppClientSocketFactory( - std::move(mock_client_socket_factory), address_list)); - chrome_async_socket_.reset( - new ChromeAsyncSocket(std::move(mock_xmpp_client_socket_factory), 14, - 20, TRAFFIC_ANNOTATION_FOR_TESTS)), - - chrome_async_socket_->SignalConnected.connect( - this, &ChromeAsyncSocketTest::OnConnect); - chrome_async_socket_->SignalSSLConnected.connect( - this, &ChromeAsyncSocketTest::OnSSLConnect); - chrome_async_socket_->SignalClosed.connect( - this, &ChromeAsyncSocketTest::OnClose); - chrome_async_socket_->SignalRead.connect( - this, &ChromeAsyncSocketTest::OnRead); - chrome_async_socket_->SignalError.connect( - this, &ChromeAsyncSocketTest::OnError); + test_url_request_context_ = + std::make_unique(true /* delay init */); + test_url_request_context_->set_client_socket_factory( + mock_client_socket_factory_.get()); + test_url_request_context_->Init(); + + if (use_mojo_level_mock_) { + auto mock_proxy_resolving_socket_factory = + std::make_unique(); + mock_proxy_resolving_socket_factory_ = + mock_proxy_resolving_socket_factory.get(); + proxy_resolving_socket_factory_ = + std::move(mock_proxy_resolving_socket_factory); + } else { + mock_proxy_resolving_socket_factory_ = nullptr; + proxy_resolving_socket_factory_ = + std::make_unique( + test_url_request_context_.get()); + } + + ns_async_socket_.reset(new NetworkServiceAsyncSocket( + base::BindRepeating( + &NetworkServiceAsyncSocketTest::BindToProxyResolvingSocketFactory, + base::Unretained(this)), + 14, 20, TRAFFIC_ANNOTATION_FOR_TESTS)); + + ns_async_socket_->SignalConnected.connect( + this, &NetworkServiceAsyncSocketTest::OnConnect); + ns_async_socket_->SignalSSLConnected.connect( + this, &NetworkServiceAsyncSocketTest::OnSSLConnect); + ns_async_socket_->SignalClosed.connect( + this, &NetworkServiceAsyncSocketTest::OnClose); + ns_async_socket_->SignalRead.connect( + this, &NetworkServiceAsyncSocketTest::OnRead); + ns_async_socket_->SignalError.connect( + this, &NetworkServiceAsyncSocketTest::OnError); } void TearDown() override { @@ -202,7 +336,15 @@ class ChromeAsyncSocketTest base::RunLoop().RunUntilIdle(); ExpectClosed(); ExpectNoSignal(); - chrome_async_socket_.reset(); + ns_async_socket_.reset(); + } + + void BindToProxyResolvingSocketFactory( + network::mojom::ProxyResolvingSocketFactoryRequest request) { + proxy_resolving_socket_factory_binding_ = std::make_unique< + mojo::Binding>( + proxy_resolving_socket_factory_.get()); + proxy_resolving_socket_factory_binding_->Bind(std::move(request)); } enum Signal { @@ -218,98 +360,82 @@ class ChromeAsyncSocketTest struct SignalSocketState { SignalSocketState() : signal(SIGNAL_ERROR), - state(ChromeAsyncSocket::STATE_CLOSED), - error(ChromeAsyncSocket::ERROR_NONE), + state(NetworkServiceAsyncSocket::STATE_CLOSED), + error(NetworkServiceAsyncSocket::ERROR_NONE), net_error(net::OK) {} - SignalSocketState( - Signal signal, - ChromeAsyncSocket::State state, - ChromeAsyncSocket::Error error, - net::Error net_error) - : signal(signal), - state(state), - error(error), - net_error(net_error) {} + SignalSocketState(Signal signal, + NetworkServiceAsyncSocket::State state, + NetworkServiceAsyncSocket::Error error, + net::Error net_error) + : signal(signal), state(state), error(error), net_error(net_error) {} bool IsEqual(const SignalSocketState& other) const { - return - (signal == other.signal) && - (state == other.state) && - (error == other.error) && - (net_error == other.net_error); + return (signal == other.signal) && (state == other.state) && + (error == other.error) && (net_error == other.net_error); } - static SignalSocketState FromAsyncSocket( - Signal signal, - buzz::AsyncSocket* async_socket) { - return SignalSocketState(signal, - async_socket->state(), - async_socket->error(), - static_cast( - async_socket->GetError())); + static SignalSocketState FromAsyncSocket(Signal signal, + buzz::AsyncSocket* async_socket) { + return SignalSocketState( + signal, async_socket->state(), async_socket->error(), + static_cast(async_socket->GetError())); } - static SignalSocketState NoError( - Signal signal, buzz::AsyncSocket::State state) { - return SignalSocketState(signal, state, - buzz::AsyncSocket::ERROR_NONE, - net::OK); + static SignalSocketState NoError(Signal signal, + buzz::AsyncSocket::State state) { + return SignalSocketState(signal, state, buzz::AsyncSocket::ERROR_NONE, + net::OK); + } + + std::string ToString() const { + return base::StrCat( + {"(", base::IntToString(signal), ",", base::IntToString(state), ",", + base::IntToString(error), ",", base::IntToString(net_error), ")"}); } Signal signal; - ChromeAsyncSocket::State state; - ChromeAsyncSocket::Error error; + NetworkServiceAsyncSocket::State state; + NetworkServiceAsyncSocket::Error error; net::Error net_error; }; void CaptureSocketState(Signal signal) { signal_socket_states_.push_back( - SignalSocketState::FromAsyncSocket( - signal, chrome_async_socket_.get())); + SignalSocketState::FromAsyncSocket(signal, ns_async_socket_.get())); } - void OnConnect() { - CaptureSocketState(SIGNAL_CONNECT); - } + void OnConnect() { CaptureSocketState(SIGNAL_CONNECT); } - void OnSSLConnect() { - CaptureSocketState(SIGNAL_SSL_CONNECT); - } + void OnSSLConnect() { CaptureSocketState(SIGNAL_SSL_CONNECT); } - void OnClose() { - CaptureSocketState(SIGNAL_CLOSE); - } + void OnClose() { CaptureSocketState(SIGNAL_CLOSE); } - void OnRead() { - CaptureSocketState(SIGNAL_READ); - } + void OnRead() { CaptureSocketState(SIGNAL_READ); } - void OnError() { - ADD_FAILURE(); - } + void OnError() { ADD_FAILURE(); } // State expect functions. - void ExpectState(ChromeAsyncSocket::State state, - ChromeAsyncSocket::Error error, + void ExpectState(NetworkServiceAsyncSocket::State state, + NetworkServiceAsyncSocket::Error error, net::Error net_error) { - EXPECT_EQ(state, chrome_async_socket_->state()); - EXPECT_EQ(error, chrome_async_socket_->error()); - EXPECT_EQ(net_error, chrome_async_socket_->GetError()); + EXPECT_EQ(state, ns_async_socket_->state()); + EXPECT_EQ(error, ns_async_socket_->error()); + EXPECT_EQ(net_error, ns_async_socket_->GetError()); } - void ExpectNonErrorState(ChromeAsyncSocket::State state) { - ExpectState(state, ChromeAsyncSocket::ERROR_NONE, net::OK); + void ExpectNonErrorState(NetworkServiceAsyncSocket::State state) { + ExpectState(state, NetworkServiceAsyncSocket::ERROR_NONE, net::OK); } - void ExpectErrorState(ChromeAsyncSocket::State state, - ChromeAsyncSocket::Error error) { + void ExpectErrorState(NetworkServiceAsyncSocket::State state, + NetworkServiceAsyncSocket::Error error) { ExpectState(state, error, net::OK); } void ExpectClosed() { - ExpectNonErrorState(ChromeAsyncSocket::STATE_CLOSED); + ExpectNonErrorState(NetworkServiceAsyncSocket::STATE_CLOSED); } // Signal expect functions. @@ -320,34 +446,31 @@ class ChromeAsyncSocketTest } } - void ExpectSignalSocketState( - SignalSocketState expected_signal_socket_state) { + void ExpectSignalSocketState(SignalSocketState expected_signal_socket_state) { if (signal_socket_states_.empty()) { ADD_FAILURE() << expected_signal_socket_state.signal; return; } - EXPECT_TRUE(expected_signal_socket_state.IsEqual( - signal_socket_states_.front())) - << signal_socket_states_.front().signal; + EXPECT_TRUE( + expected_signal_socket_state.IsEqual(signal_socket_states_.front())) + << "Expected signal:" << expected_signal_socket_state.ToString() + << " actual signal: " << signal_socket_states_.front().ToString(); signal_socket_states_.pop_front(); } void ExpectReadSignal() { - ExpectSignalSocketState( - SignalSocketState::NoError( - SIGNAL_READ, ChromeAsyncSocket::STATE_OPEN)); + ExpectSignalSocketState(SignalSocketState::NoError( + SIGNAL_READ, NetworkServiceAsyncSocket::STATE_OPEN)); } void ExpectSSLConnectSignal() { - ExpectSignalSocketState( - SignalSocketState::NoError(SIGNAL_SSL_CONNECT, - ChromeAsyncSocket::STATE_TLS_OPEN)); + ExpectSignalSocketState(SignalSocketState::NoError( + SIGNAL_SSL_CONNECT, NetworkServiceAsyncSocket::STATE_TLS_OPEN)); } void ExpectSSLReadSignal() { - ExpectSignalSocketState( - SignalSocketState::NoError( - SIGNAL_READ, ChromeAsyncSocket::STATE_TLS_OPEN)); + ExpectSignalSocketState(SignalSocketState::NoError( + SIGNAL_READ, NetworkServiceAsyncSocket::STATE_TLS_OPEN)); } // Open/close utility functions. @@ -356,29 +479,27 @@ class ChromeAsyncSocketTest ExpectClosed(); async_socket_data_provider_.set_connect_data( net::MockConnect(net::SYNCHRONOUS, net::OK)); - EXPECT_TRUE(chrome_async_socket_->Connect(addr_)); - ExpectNonErrorState(ChromeAsyncSocket::STATE_CONNECTING); + EXPECT_TRUE(ns_async_socket_->Connect(addr_)); + ExpectNonErrorState(NetworkServiceAsyncSocket::STATE_CONNECTING); base::RunLoop().RunUntilIdle(); // We may not necessarily be open; may have been other events // queued up. - ExpectSignalSocketState( - SignalSocketState::NoError( - SIGNAL_CONNECT, ChromeAsyncSocket::STATE_OPEN)); + ExpectSignalSocketState(SignalSocketState::NoError( + SIGNAL_CONNECT, NetworkServiceAsyncSocket::STATE_OPEN)); } void DoCloseOpened(SignalSocketState expected_signal_socket_state) { // We may be in an error state, so just compare state(). - EXPECT_EQ(ChromeAsyncSocket::STATE_OPEN, chrome_async_socket_->state()); - EXPECT_TRUE(chrome_async_socket_->Close()); + EXPECT_EQ(NetworkServiceAsyncSocket::STATE_OPEN, ns_async_socket_->state()); + EXPECT_TRUE(ns_async_socket_->Close()); ExpectSignalSocketState(expected_signal_socket_state); - ExpectNonErrorState(ChromeAsyncSocket::STATE_CLOSED); + ExpectNonErrorState(NetworkServiceAsyncSocket::STATE_CLOSED); } void DoCloseOpenedNoError() { - DoCloseOpened( - SignalSocketState::NoError( - SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED)); + DoCloseOpened(SignalSocketState::NoError( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED)); } void DoSSLOpenClosed() { @@ -388,37 +509,35 @@ class ChromeAsyncSocketTest ExpectReadSignal(); EXPECT_EQ(kDummyData, DrainRead(1)); - EXPECT_TRUE(chrome_async_socket_->StartTls("fakedomain.com")); + EXPECT_TRUE(ns_async_socket_->StartTls("fakedomain.com")); base::RunLoop().RunUntilIdle(); ExpectSSLConnectSignal(); ExpectNoSignal(); - ExpectNonErrorState(ChromeAsyncSocket::STATE_TLS_OPEN); + ExpectNonErrorState(NetworkServiceAsyncSocket::STATE_TLS_OPEN); } void DoSSLCloseOpened(SignalSocketState expected_signal_socket_state) { // We may be in an error state, so just compare state(). - EXPECT_EQ(ChromeAsyncSocket::STATE_TLS_OPEN, - chrome_async_socket_->state()); - EXPECT_TRUE(chrome_async_socket_->Close()); + EXPECT_EQ(NetworkServiceAsyncSocket::STATE_TLS_OPEN, + ns_async_socket_->state()); + EXPECT_TRUE(ns_async_socket_->Close()); ExpectSignalSocketState(expected_signal_socket_state); - ExpectNonErrorState(ChromeAsyncSocket::STATE_CLOSED); + ExpectNonErrorState(NetworkServiceAsyncSocket::STATE_CLOSED); } void DoSSLCloseOpenedNoError() { - DoSSLCloseOpened( - SignalSocketState::NoError( - SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED)); + DoSSLCloseOpened(SignalSocketState::NoError( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED)); } - // Read utility fucntions. + // Read utility functions. std::string DrainRead(size_t buf_size) { std::string read; std::unique_ptr buf(new char[buf_size]); size_t len_read; while (true) { - bool success = - chrome_async_socket_->Read(buf.get(), buf_size, &len_read); + bool success = ns_async_socket_->Read(buf.get(), buf_size, &len_read); if (!success) { ADD_FAILURE(); break; @@ -431,35 +550,46 @@ class ChromeAsyncSocketTest return read; } - // ChromeAsyncSocket expects a message loop. + // Need a message loop for both the socket and Mojo. base::MessageLoop message_loop_; AsyncSocketDataProvider async_socket_data_provider_; net::SSLSocketDataProvider ssl_socket_data_provider_; - std::unique_ptr chrome_async_socket_; + bool use_mojo_level_mock_; + + std::unique_ptr mock_client_socket_factory_; + std::unique_ptr test_url_request_context_; + // Either null or owned by proxy_resolving_socket_factory_. + MockProxyResolvingSocketFactory* mock_proxy_resolving_socket_factory_; + std::unique_ptr + proxy_resolving_socket_factory_; + std::unique_ptr> + proxy_resolving_socket_factory_binding_; + + std::unique_ptr ns_async_socket_; base::circular_deque signal_socket_states_; const rtc::SocketAddress addr_; private: - DISALLOW_COPY_AND_ASSIGN(ChromeAsyncSocketTest); + DISALLOW_COPY_AND_ASSIGN(NetworkServiceAsyncSocketTest); }; -TEST_F(ChromeAsyncSocketTest, InitialState) { +TEST_F(NetworkServiceAsyncSocketTest, InitialState) { ExpectClosed(); ExpectNoSignal(); } -TEST_F(ChromeAsyncSocketTest, EmptyClose) { +TEST_F(NetworkServiceAsyncSocketTest, EmptyClose) { ExpectClosed(); - EXPECT_TRUE(chrome_async_socket_->Close()); + EXPECT_TRUE(ns_async_socket_->Close()); ExpectClosed(); } -TEST_F(ChromeAsyncSocketTest, ImmediateConnectAndClose) { +TEST_F(NetworkServiceAsyncSocketTest, ImmediateConnectAndClose) { DoOpenClosed(); - ExpectNonErrorState(ChromeAsyncSocket::STATE_OPEN); + ExpectNonErrorState(NetworkServiceAsyncSocket::STATE_OPEN); DoCloseOpenedNoError(); } @@ -467,93 +597,89 @@ TEST_F(ChromeAsyncSocketTest, ImmediateConnectAndClose) { // After this, no need to test immediate successful connect and // Close() so thoroughly. -TEST_F(ChromeAsyncSocketTest, DoubleClose) { +TEST_F(NetworkServiceAsyncSocketTest, DoubleClose) { DoOpenClosed(); - EXPECT_TRUE(chrome_async_socket_->Close()); + EXPECT_TRUE(ns_async_socket_->Close()); ExpectClosed(); - ExpectSignalSocketState( - SignalSocketState::NoError( - SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED)); + ExpectSignalSocketState(SignalSocketState::NoError( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED)); - EXPECT_TRUE(chrome_async_socket_->Close()); + EXPECT_TRUE(ns_async_socket_->Close()); ExpectClosed(); } -TEST_F(ChromeAsyncSocketTest, NoHostnameConnect) { +TEST_F(NetworkServiceAsyncSocketTest, NoHostnameConnect) { rtc::IPAddress ip_address; EXPECT_TRUE(rtc::IPFromString("127.0.0.1", &ip_address)); const rtc::SocketAddress no_hostname_addr(ip_address, addr_.port()); - EXPECT_FALSE(chrome_async_socket_->Connect(no_hostname_addr)); - ExpectErrorState(ChromeAsyncSocket::STATE_CLOSED, - ChromeAsyncSocket::ERROR_DNS); + EXPECT_FALSE(ns_async_socket_->Connect(no_hostname_addr)); + ExpectErrorState(NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_DNS); - EXPECT_TRUE(chrome_async_socket_->Close()); + EXPECT_TRUE(ns_async_socket_->Close()); ExpectClosed(); } -TEST_F(ChromeAsyncSocketTest, ZeroPortConnect) { +TEST_F(NetworkServiceAsyncSocketTest, ZeroPortConnect) { const rtc::SocketAddress zero_port_addr(addr_.hostname(), 0); - EXPECT_FALSE(chrome_async_socket_->Connect(zero_port_addr)); - ExpectErrorState(ChromeAsyncSocket::STATE_CLOSED, - ChromeAsyncSocket::ERROR_DNS); + EXPECT_FALSE(ns_async_socket_->Connect(zero_port_addr)); + ExpectErrorState(NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_DNS); - EXPECT_TRUE(chrome_async_socket_->Close()); + EXPECT_TRUE(ns_async_socket_->Close()); ExpectClosed(); } -TEST_F(ChromeAsyncSocketTest, DoubleConnect) { - EXPECT_DEBUG_DEATH({ - DoOpenClosed(); +TEST_F(NetworkServiceAsyncSocketTest, DoubleConnect) { + EXPECT_DEBUG_DEATH( + { + DoOpenClosed(); - EXPECT_FALSE(chrome_async_socket_->Connect(addr_)); - ExpectErrorState(ChromeAsyncSocket::STATE_OPEN, - ChromeAsyncSocket::ERROR_WRONGSTATE); + EXPECT_FALSE(ns_async_socket_->Connect(addr_)); + ExpectErrorState(NetworkServiceAsyncSocket::STATE_OPEN, + NetworkServiceAsyncSocket::ERROR_WRONGSTATE); - DoCloseOpened( - SignalSocketState(SIGNAL_CLOSE, - ChromeAsyncSocket::STATE_CLOSED, - ChromeAsyncSocket::ERROR_WRONGSTATE, - net::OK)); - }, "non-closed socket"); + DoCloseOpened(SignalSocketState( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WRONGSTATE, net::OK)); + }, + "non-closed socket"); } -TEST_F(ChromeAsyncSocketTest, ImmediateConnectCloseBeforeRead) { +TEST_F(NetworkServiceAsyncSocketTest, ImmediateConnectCloseBeforeRead) { DoOpenClosed(); - EXPECT_TRUE(chrome_async_socket_->Close()); + EXPECT_TRUE(ns_async_socket_->Close()); ExpectClosed(); - ExpectSignalSocketState( - SignalSocketState::NoError( - SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED)); + ExpectSignalSocketState(SignalSocketState::NoError( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED)); base::RunLoop().RunUntilIdle(); } -TEST_F(ChromeAsyncSocketTest, HangingConnect) { - EXPECT_TRUE(chrome_async_socket_->Connect(addr_)); - ExpectNonErrorState(ChromeAsyncSocket::STATE_CONNECTING); +TEST_F(NetworkServiceAsyncSocketTest, HangingConnect) { + EXPECT_TRUE(ns_async_socket_->Connect(addr_)); + ExpectNonErrorState(NetworkServiceAsyncSocket::STATE_CONNECTING); ExpectNoSignal(); - EXPECT_TRUE(chrome_async_socket_->Close()); + EXPECT_TRUE(ns_async_socket_->Close()); ExpectClosed(); - ExpectSignalSocketState( - SignalSocketState::NoError( - SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED)); + ExpectSignalSocketState(SignalSocketState::NoError( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED)); } -TEST_F(ChromeAsyncSocketTest, PendingConnect) { +TEST_F(NetworkServiceAsyncSocketTest, PendingConnect) { async_socket_data_provider_.set_connect_data( net::MockConnect(net::ASYNC, net::OK)); - EXPECT_TRUE(chrome_async_socket_->Connect(addr_)); - ExpectNonErrorState(ChromeAsyncSocket::STATE_CONNECTING); + EXPECT_TRUE(ns_async_socket_->Connect(addr_)); + ExpectNonErrorState(NetworkServiceAsyncSocket::STATE_CONNECTING); ExpectNoSignal(); base::RunLoop().RunUntilIdle(); - ExpectNonErrorState(ChromeAsyncSocket::STATE_OPEN); - ExpectSignalSocketState( - SignalSocketState::NoError( - SIGNAL_CONNECT, ChromeAsyncSocket::STATE_OPEN)); + ExpectNonErrorState(NetworkServiceAsyncSocket::STATE_OPEN); + ExpectSignalSocketState(SignalSocketState::NoError( + SIGNAL_CONNECT, NetworkServiceAsyncSocket::STATE_OPEN)); ExpectNoSignal(); base::RunLoop().RunUntilIdle(); @@ -564,80 +690,79 @@ TEST_F(ChromeAsyncSocketTest, PendingConnect) { // After this no need to test successful pending connect so // thoroughly. -TEST_F(ChromeAsyncSocketTest, PendingConnectCloseBeforeRead) { +TEST_F(NetworkServiceAsyncSocketTest, PendingConnectCloseBeforeRead) { async_socket_data_provider_.set_connect_data( net::MockConnect(net::ASYNC, net::OK)); - EXPECT_TRUE(chrome_async_socket_->Connect(addr_)); + EXPECT_TRUE(ns_async_socket_->Connect(addr_)); base::RunLoop().RunUntilIdle(); - ExpectSignalSocketState( - SignalSocketState::NoError( - SIGNAL_CONNECT, ChromeAsyncSocket::STATE_OPEN)); + ExpectSignalSocketState(SignalSocketState::NoError( + SIGNAL_CONNECT, NetworkServiceAsyncSocket::STATE_OPEN)); DoCloseOpenedNoError(); base::RunLoop().RunUntilIdle(); } -TEST_F(ChromeAsyncSocketTest, PendingConnectError) { +TEST_F(NetworkServiceAsyncSocketTest, PendingConnectError) { async_socket_data_provider_.set_connect_data( net::MockConnect(net::ASYNC, net::ERR_TIMED_OUT)); - EXPECT_TRUE(chrome_async_socket_->Connect(addr_)); + EXPECT_TRUE(ns_async_socket_->Connect(addr_)); base::RunLoop().RunUntilIdle(); - ExpectSignalSocketState( - SignalSocketState( - SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED, - ChromeAsyncSocket::ERROR_WINSOCK, net::ERR_TIMED_OUT)); + ExpectSignalSocketState(SignalSocketState( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WINSOCK, net::ERR_TIMED_OUT)); } // After this we can assume Connect() and Close() work as expected. -TEST_F(ChromeAsyncSocketTest, EmptyRead) { +TEST_F(NetworkServiceAsyncSocketTest, EmptyRead) { DoOpenClosed(); char buf[4096]; size_t len_read = 10000U; - EXPECT_TRUE(chrome_async_socket_->Read(buf, sizeof(buf), &len_read)); + EXPECT_TRUE(ns_async_socket_->Read(buf, sizeof(buf), &len_read)); EXPECT_EQ(0U, len_read); DoCloseOpenedNoError(); } -TEST_F(ChromeAsyncSocketTest, WrongRead) { - EXPECT_DEBUG_DEATH({ - async_socket_data_provider_.set_connect_data( - net::MockConnect(net::ASYNC, net::OK)); - EXPECT_TRUE(chrome_async_socket_->Connect(addr_)); - ExpectNonErrorState(ChromeAsyncSocket::STATE_CONNECTING); - ExpectNoSignal(); - - char buf[4096]; - size_t len_read; - EXPECT_FALSE(chrome_async_socket_->Read(buf, sizeof(buf), &len_read)); - ExpectErrorState(ChromeAsyncSocket::STATE_CONNECTING, - ChromeAsyncSocket::ERROR_WRONGSTATE); - EXPECT_TRUE(chrome_async_socket_->Close()); - ExpectSignalSocketState( - SignalSocketState( - SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED, - ChromeAsyncSocket::ERROR_WRONGSTATE, net::OK)); - }, "non-open"); +TEST_F(NetworkServiceAsyncSocketTest, WrongRead) { + EXPECT_DEBUG_DEATH( + { + async_socket_data_provider_.set_connect_data( + net::MockConnect(net::ASYNC, net::OK)); + EXPECT_TRUE(ns_async_socket_->Connect(addr_)); + ExpectNonErrorState(NetworkServiceAsyncSocket::STATE_CONNECTING); + ExpectNoSignal(); + + char buf[4096]; + size_t len_read; + EXPECT_FALSE(ns_async_socket_->Read(buf, sizeof(buf), &len_read)); + ExpectErrorState(NetworkServiceAsyncSocket::STATE_CONNECTING, + NetworkServiceAsyncSocket::ERROR_WRONGSTATE); + EXPECT_TRUE(ns_async_socket_->Close()); + ExpectSignalSocketState(SignalSocketState( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WRONGSTATE, net::OK)); + }, + "non-open"); } -TEST_F(ChromeAsyncSocketTest, WrongReadClosed) { +TEST_F(NetworkServiceAsyncSocketTest, WrongReadClosed) { char buf[4096]; size_t len_read; - EXPECT_FALSE(chrome_async_socket_->Read(buf, sizeof(buf), &len_read)); - ExpectErrorState(ChromeAsyncSocket::STATE_CLOSED, - ChromeAsyncSocket::ERROR_WRONGSTATE); - EXPECT_TRUE(chrome_async_socket_->Close()); + EXPECT_FALSE(ns_async_socket_->Read(buf, sizeof(buf), &len_read)); + ExpectErrorState(NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WRONGSTATE); + EXPECT_TRUE(ns_async_socket_->Close()); } const char kReadData[] = "mydatatoread"; -TEST_F(ChromeAsyncSocketTest, Read) { +TEST_F(NetworkServiceAsyncSocketTest, Read) { async_socket_data_provider_.AddRead(net::MockRead(kReadData)); DoOpenClosed(); @@ -651,7 +776,7 @@ TEST_F(ChromeAsyncSocketTest, Read) { DoCloseOpenedNoError(); } -TEST_F(ChromeAsyncSocketTest, ReadTwice) { +TEST_F(NetworkServiceAsyncSocketTest, ReadTwice) { async_socket_data_provider_.AddRead(net::MockRead(kReadData)); DoOpenClosed(); @@ -664,6 +789,7 @@ TEST_F(ChromeAsyncSocketTest, ReadTwice) { const char kReadData2[] = "mydatatoread2"; async_socket_data_provider_.AddRead(net::MockRead(kReadData2)); + base::RunLoop().RunUntilIdle(); ExpectReadSignal(); ExpectNoSignal(); @@ -673,7 +799,7 @@ TEST_F(ChromeAsyncSocketTest, ReadTwice) { DoCloseOpenedNoError(); } -TEST_F(ChromeAsyncSocketTest, ReadError) { +TEST_F(NetworkServiceAsyncSocketTest, ReadError) { async_socket_data_provider_.AddRead(net::MockRead(kReadData)); DoOpenClosed(); @@ -686,32 +812,48 @@ TEST_F(ChromeAsyncSocketTest, ReadError) { async_socket_data_provider_.AddRead( net::MockRead(net::SYNCHRONOUS, net::ERR_TIMED_OUT)); + base::RunLoop().RunUntilIdle(); - ExpectSignalSocketState( - SignalSocketState( - SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED, - ChromeAsyncSocket::ERROR_WINSOCK, net::ERR_TIMED_OUT)); + ExpectSignalSocketState(SignalSocketState( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WINSOCK, net::ERR_TIMED_OUT)); } -TEST_F(ChromeAsyncSocketTest, ReadEmpty) { +TEST_F(NetworkServiceAsyncSocketTest, ReadEOF) { + async_socket_data_provider_.AddRead(net::MockRead(kReadData)); + DoOpenClosed(); + + ExpectReadSignal(); + ExpectNoSignal(); + + EXPECT_EQ(kReadData, DrainRead(1)); + + base::RunLoop().RunUntilIdle(); + + async_socket_data_provider_.AddRead(net::MockRead(net::SYNCHRONOUS, net::OK)); + base::RunLoop().RunUntilIdle(); + ExpectSignalSocketState(SignalSocketState::NoError( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED)); +} + +TEST_F(NetworkServiceAsyncSocketTest, ReadEmpty) { async_socket_data_provider_.AddRead(net::MockRead("")); DoOpenClosed(); - ExpectSignalSocketState( - SignalSocketState::NoError( - SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED)); + ExpectSignalSocketState(SignalSocketState::NoError( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED)); } -TEST_F(ChromeAsyncSocketTest, PendingRead) { +TEST_F(NetworkServiceAsyncSocketTest, PendingRead) { DoOpenClosed(); ExpectNoSignal(); async_socket_data_provider_.AddRead(net::MockRead(kReadData)); + base::RunLoop().RunUntilIdle(); - ExpectSignalSocketState( - SignalSocketState::NoError( - SIGNAL_READ, ChromeAsyncSocket::STATE_OPEN)); + ExpectSignalSocketState(SignalSocketState::NoError( + SIGNAL_READ, NetworkServiceAsyncSocket::STATE_OPEN)); ExpectNoSignal(); EXPECT_EQ(kReadData, DrainRead(1)); @@ -721,62 +863,63 @@ TEST_F(ChromeAsyncSocketTest, PendingRead) { DoCloseOpenedNoError(); } -TEST_F(ChromeAsyncSocketTest, PendingEmptyRead) { +TEST_F(NetworkServiceAsyncSocketTest, PendingEmptyRead) { DoOpenClosed(); ExpectNoSignal(); async_socket_data_provider_.AddRead(net::MockRead("")); + base::RunLoop().RunUntilIdle(); - ExpectSignalSocketState( - SignalSocketState::NoError( - SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED)); + ExpectSignalSocketState(SignalSocketState::NoError( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED)); } -TEST_F(ChromeAsyncSocketTest, PendingReadError) { +TEST_F(NetworkServiceAsyncSocketTest, PendingReadError) { DoOpenClosed(); ExpectNoSignal(); async_socket_data_provider_.AddRead( net::MockRead(net::ASYNC, net::ERR_TIMED_OUT)); + base::RunLoop().RunUntilIdle(); - ExpectSignalSocketState( - SignalSocketState( - SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED, - ChromeAsyncSocket::ERROR_WINSOCK, net::ERR_TIMED_OUT)); + ExpectSignalSocketState(SignalSocketState( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WINSOCK, net::ERR_TIMED_OUT)); } // After this we can assume non-SSL Read() works as expected. -TEST_F(ChromeAsyncSocketTest, WrongWrite) { - EXPECT_DEBUG_DEATH({ - std::string data("foo"); - EXPECT_FALSE(chrome_async_socket_->Write(data.data(), data.size())); - ExpectErrorState(ChromeAsyncSocket::STATE_CLOSED, - ChromeAsyncSocket::ERROR_WRONGSTATE); - EXPECT_TRUE(chrome_async_socket_->Close()); - }, "non-open"); +TEST_F(NetworkServiceAsyncSocketTest, WrongWrite) { + EXPECT_DEBUG_DEATH( + { + std::string data("foo"); + EXPECT_FALSE(ns_async_socket_->Write(data.data(), data.size())); + ExpectErrorState(NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WRONGSTATE); + EXPECT_TRUE(ns_async_socket_->Close()); + }, + "non-open"); } const char kWriteData[] = "mydatatowrite"; -TEST_F(ChromeAsyncSocketTest, SyncWrite) { +TEST_F(NetworkServiceAsyncSocketTest, SyncWrite) { async_socket_data_provider_.AddWrite( net::MockWrite(net::SYNCHRONOUS, kWriteData, 3)); async_socket_data_provider_.AddWrite( net::MockWrite(net::SYNCHRONOUS, kWriteData + 3, 5)); - async_socket_data_provider_.AddWrite( - net::MockWrite(net::SYNCHRONOUS, - kWriteData + 8, arraysize(kWriteData) - 8)); + async_socket_data_provider_.AddWrite(net::MockWrite( + net::SYNCHRONOUS, kWriteData + 8, arraysize(kWriteData) - 8)); DoOpenClosed(); - EXPECT_TRUE(chrome_async_socket_->Write(kWriteData, 3)); + EXPECT_TRUE(ns_async_socket_->Write(kWriteData, 3)); base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(chrome_async_socket_->Write(kWriteData + 3, 5)); + EXPECT_TRUE(ns_async_socket_->Write(kWriteData + 3, 5)); base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(chrome_async_socket_->Write(kWriteData + 8, - arraysize(kWriteData) - 8)); + EXPECT_TRUE( + ns_async_socket_->Write(kWriteData + 8, arraysize(kWriteData) - 8)); base::RunLoop().RunUntilIdle(); ExpectNoSignal(); @@ -784,7 +927,7 @@ TEST_F(ChromeAsyncSocketTest, SyncWrite) { DoCloseOpenedNoError(); } -TEST_F(ChromeAsyncSocketTest, AsyncWrite) { +TEST_F(NetworkServiceAsyncSocketTest, AsyncWrite) { DoOpenClosed(); async_socket_data_provider_.AddWrite( @@ -794,12 +937,12 @@ TEST_F(ChromeAsyncSocketTest, AsyncWrite) { async_socket_data_provider_.AddWrite( net::MockWrite(net::ASYNC, kWriteData + 8, arraysize(kWriteData) - 8)); - EXPECT_TRUE(chrome_async_socket_->Write(kWriteData, 3)); + EXPECT_TRUE(ns_async_socket_->Write(kWriteData, 3)); base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(chrome_async_socket_->Write(kWriteData + 3, 5)); + EXPECT_TRUE(ns_async_socket_->Write(kWriteData + 3, 5)); base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(chrome_async_socket_->Write(kWriteData + 8, - arraysize(kWriteData) - 8)); + EXPECT_TRUE( + ns_async_socket_->Write(kWriteData + 8, arraysize(kWriteData) - 8)); base::RunLoop().RunUntilIdle(); ExpectNoSignal(); @@ -807,7 +950,7 @@ TEST_F(ChromeAsyncSocketTest, AsyncWrite) { DoCloseOpenedNoError(); } -TEST_F(ChromeAsyncSocketTest, AsyncWriteError) { +TEST_F(NetworkServiceAsyncSocketTest, AsyncWriteError) { DoOpenClosed(); async_socket_data_provider_.AddWrite( @@ -817,111 +960,111 @@ TEST_F(ChromeAsyncSocketTest, AsyncWriteError) { async_socket_data_provider_.AddWrite( net::MockWrite(net::ASYNC, net::ERR_TIMED_OUT)); - EXPECT_TRUE(chrome_async_socket_->Write(kWriteData, 3)); + EXPECT_TRUE(ns_async_socket_->Write(kWriteData, 3)); base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(chrome_async_socket_->Write(kWriteData + 3, 5)); + EXPECT_TRUE(ns_async_socket_->Write(kWriteData + 3, 5)); base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(chrome_async_socket_->Write(kWriteData + 8, - arraysize(kWriteData) - 8)); + EXPECT_TRUE( + ns_async_socket_->Write(kWriteData + 8, arraysize(kWriteData) - 8)); base::RunLoop().RunUntilIdle(); - ExpectSignalSocketState( - SignalSocketState( - SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED, - ChromeAsyncSocket::ERROR_WINSOCK, net::ERR_TIMED_OUT)); + ExpectSignalSocketState(SignalSocketState( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WINSOCK, net::ERR_TIMED_OUT)); } -TEST_F(ChromeAsyncSocketTest, LargeWrite) { - EXPECT_DEBUG_DEATH({ - DoOpenClosed(); - - std::string large_data(100, 'x'); - EXPECT_FALSE(chrome_async_socket_->Write(large_data.data(), - large_data.size())); - ExpectState(ChromeAsyncSocket::STATE_OPEN, - ChromeAsyncSocket::ERROR_WINSOCK, - net::ERR_INSUFFICIENT_RESOURCES); - DoCloseOpened( - SignalSocketState( - SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED, - ChromeAsyncSocket::ERROR_WINSOCK, +TEST_F(NetworkServiceAsyncSocketTest, LargeWrite) { + EXPECT_DEBUG_DEATH( + { + DoOpenClosed(); + + std::string large_data(100, 'x'); + EXPECT_FALSE( + ns_async_socket_->Write(large_data.data(), large_data.size())); + ExpectState(NetworkServiceAsyncSocket::STATE_OPEN, + NetworkServiceAsyncSocket::ERROR_WINSOCK, + net::ERR_INSUFFICIENT_RESOURCES); + DoCloseOpened(SignalSocketState( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WINSOCK, net::ERR_INSUFFICIENT_RESOURCES)); - }, "exceed the max write buffer"); + }, + "exceed the max write buffer"); } -TEST_F(ChromeAsyncSocketTest, LargeAccumulatedWrite) { - EXPECT_DEBUG_DEATH({ - DoOpenClosed(); - - std::string data(15, 'x'); - EXPECT_TRUE(chrome_async_socket_->Write(data.data(), data.size())); - EXPECT_FALSE(chrome_async_socket_->Write(data.data(), data.size())); - ExpectState(ChromeAsyncSocket::STATE_OPEN, - ChromeAsyncSocket::ERROR_WINSOCK, - net::ERR_INSUFFICIENT_RESOURCES); - DoCloseOpened( - SignalSocketState( - SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED, - ChromeAsyncSocket::ERROR_WINSOCK, +TEST_F(NetworkServiceAsyncSocketTest, LargeAccumulatedWrite) { + EXPECT_DEBUG_DEATH( + { + DoOpenClosed(); + + std::string data(15, 'x'); + EXPECT_TRUE(ns_async_socket_->Write(data.data(), data.size())); + EXPECT_FALSE(ns_async_socket_->Write(data.data(), data.size())); + ExpectState(NetworkServiceAsyncSocket::STATE_OPEN, + NetworkServiceAsyncSocket::ERROR_WINSOCK, + net::ERR_INSUFFICIENT_RESOURCES); + DoCloseOpened(SignalSocketState( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WINSOCK, net::ERR_INSUFFICIENT_RESOURCES)); - }, "exceed the max write buffer"); + }, + "exceed the max write buffer"); } // After this we can assume non-SSL I/O works as expected. -TEST_F(ChromeAsyncSocketTest, HangingSSLConnect) { +TEST_F(NetworkServiceAsyncSocketTest, HangingSSLConnect) { async_socket_data_provider_.AddRead(net::MockRead(kReadData)); DoOpenClosed(); ExpectReadSignal(); - EXPECT_TRUE(chrome_async_socket_->StartTls("fakedomain.com")); + EXPECT_TRUE(ns_async_socket_->StartTls("fakedomain.com")); ExpectNoSignal(); - ExpectNonErrorState(ChromeAsyncSocket::STATE_TLS_CONNECTING); - EXPECT_TRUE(chrome_async_socket_->Close()); - ExpectSignalSocketState( - SignalSocketState::NoError(SIGNAL_CLOSE, - ChromeAsyncSocket::STATE_CLOSED)); - ExpectNonErrorState(ChromeAsyncSocket::STATE_CLOSED); + ExpectNonErrorState(NetworkServiceAsyncSocket::STATE_TLS_CONNECTING); + EXPECT_TRUE(ns_async_socket_->Close()); + ExpectSignalSocketState(SignalSocketState::NoError( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED)); + ExpectNonErrorState(NetworkServiceAsyncSocket::STATE_CLOSED); } -TEST_F(ChromeAsyncSocketTest, ImmediateSSLConnect) { +TEST_F(NetworkServiceAsyncSocketTest, ImmediateSSLConnect) { async_socket_data_provider_.AddRead(net::MockRead(kReadData)); DoOpenClosed(); ExpectReadSignal(); - EXPECT_TRUE(chrome_async_socket_->StartTls("fakedomain.com")); + EXPECT_TRUE(ns_async_socket_->StartTls("fakedomain.com")); base::RunLoop().RunUntilIdle(); ExpectSSLConnectSignal(); ExpectNoSignal(); - ExpectNonErrorState(ChromeAsyncSocket::STATE_TLS_OPEN); + ExpectNonErrorState(NetworkServiceAsyncSocket::STATE_TLS_OPEN); DoSSLCloseOpenedNoError(); } -TEST_F(ChromeAsyncSocketTest, DoubleSSLConnect) { - EXPECT_DEBUG_DEATH({ - async_socket_data_provider_.AddRead(net::MockRead(kReadData)); - DoOpenClosed(); - ExpectReadSignal(); - - EXPECT_TRUE(chrome_async_socket_->StartTls("fakedomain.com")); - base::RunLoop().RunUntilIdle(); - ExpectSSLConnectSignal(); - ExpectNoSignal(); - ExpectNonErrorState(ChromeAsyncSocket::STATE_TLS_OPEN); - - EXPECT_FALSE(chrome_async_socket_->StartTls("fakedomain.com")); - - DoSSLCloseOpened( - SignalSocketState(SIGNAL_CLOSE, - ChromeAsyncSocket::STATE_CLOSED, - ChromeAsyncSocket::ERROR_WRONGSTATE, - net::OK)); - }, "wrong state"); +TEST_F(NetworkServiceAsyncSocketTest, DoubleSSLConnect) { + EXPECT_DEBUG_DEATH( + { + async_socket_data_provider_.AddRead(net::MockRead(kReadData)); + DoOpenClosed(); + ExpectReadSignal(); + + EXPECT_TRUE(ns_async_socket_->StartTls("fakedomain.com")); + base::RunLoop().RunUntilIdle(); + ExpectSSLConnectSignal(); + ExpectNoSignal(); + ExpectNonErrorState(NetworkServiceAsyncSocket::STATE_TLS_OPEN); + + EXPECT_FALSE(ns_async_socket_->StartTls("fakedomain.com")); + + DoSSLCloseOpened(SignalSocketState( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WRONGSTATE, net::OK)); + }, + "wrong state"); } -TEST_F(ChromeAsyncSocketTest, FailedSSLConnect) { +TEST_F(NetworkServiceAsyncSocketTest, FailedSSLConnect) { ssl_socket_data_provider_.connect = net::MockConnect(net::ASYNC, net::ERR_CERT_COMMON_NAME_INVALID), @@ -929,25 +1072,24 @@ TEST_F(ChromeAsyncSocketTest, FailedSSLConnect) { DoOpenClosed(); ExpectReadSignal(); - EXPECT_TRUE(chrome_async_socket_->StartTls("fakedomain.com")); + EXPECT_TRUE(ns_async_socket_->StartTls("fakedomain.com")); base::RunLoop().RunUntilIdle(); ExpectSignalSocketState( - SignalSocketState( - SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED, - ChromeAsyncSocket::ERROR_WINSOCK, - net::ERR_CERT_COMMON_NAME_INVALID)); + SignalSocketState(SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WINSOCK, + net::ERR_CERT_COMMON_NAME_INVALID)); - EXPECT_TRUE(chrome_async_socket_->Close()); + EXPECT_TRUE(ns_async_socket_->Close()); ExpectClosed(); } -TEST_F(ChromeAsyncSocketTest, ReadDuringSSLConnecting) { +TEST_F(NetworkServiceAsyncSocketTest, ReadDuringSSLConnecting) { async_socket_data_provider_.AddRead(net::MockRead(kReadData)); DoOpenClosed(); ExpectReadSignal(); EXPECT_EQ(kReadData, DrainRead(1)); - EXPECT_TRUE(chrome_async_socket_->StartTls("fakedomain.com")); + EXPECT_TRUE(ns_async_socket_->StartTls("fakedomain.com")); ExpectNoSignal(); // Shouldn't do anything. @@ -955,36 +1097,36 @@ TEST_F(ChromeAsyncSocketTest, ReadDuringSSLConnecting) { char buf[4096]; size_t len_read = 10000U; - EXPECT_TRUE(chrome_async_socket_->Read(buf, sizeof(buf), &len_read)); + EXPECT_TRUE(ns_async_socket_->Read(buf, sizeof(buf), &len_read)); EXPECT_EQ(0U, len_read); base::RunLoop().RunUntilIdle(); ExpectSSLConnectSignal(); ExpectSSLReadSignal(); ExpectNoSignal(); - ExpectNonErrorState(ChromeAsyncSocket::STATE_TLS_OPEN); + ExpectNonErrorState(NetworkServiceAsyncSocket::STATE_TLS_OPEN); len_read = 10000U; - EXPECT_TRUE(chrome_async_socket_->Read(buf, sizeof(buf), &len_read)); + EXPECT_TRUE(ns_async_socket_->Read(buf, sizeof(buf), &len_read)); EXPECT_EQ(kReadData, std::string(buf, len_read)); DoSSLCloseOpenedNoError(); } -TEST_F(ChromeAsyncSocketTest, WriteDuringSSLConnecting) { +TEST_F(NetworkServiceAsyncSocketTest, WriteDuringSSLConnecting) { async_socket_data_provider_.AddRead(net::MockRead(kReadData)); DoOpenClosed(); ExpectReadSignal(); - EXPECT_TRUE(chrome_async_socket_->StartTls("fakedomain.com")); + EXPECT_TRUE(ns_async_socket_->StartTls("fakedomain.com")); ExpectNoSignal(); - ExpectNonErrorState(ChromeAsyncSocket::STATE_TLS_CONNECTING); + ExpectNonErrorState(NetworkServiceAsyncSocket::STATE_TLS_CONNECTING); async_socket_data_provider_.AddWrite( net::MockWrite(net::ASYNC, kWriteData, 3)); // Shouldn't do anything. - EXPECT_TRUE(chrome_async_socket_->Write(kWriteData, 3)); + EXPECT_TRUE(ns_async_socket_->Write(kWriteData, 3)); // TODO(akalin): Figure out how to test that the write happens // *after* the SSL connect. @@ -998,43 +1140,9 @@ TEST_F(ChromeAsyncSocketTest, WriteDuringSSLConnecting) { DoSSLCloseOpenedNoError(); } -TEST_F(ChromeAsyncSocketTest, SSLConnectDuringPendingRead) { - EXPECT_DEBUG_DEATH({ - DoOpenClosed(); - - EXPECT_FALSE(chrome_async_socket_->StartTls("fakedomain.com")); - - DoCloseOpened( - SignalSocketState(SIGNAL_CLOSE, - ChromeAsyncSocket::STATE_CLOSED, - ChromeAsyncSocket::ERROR_WRONGSTATE, - net::OK)); - }, "wrong state"); -} - -TEST_F(ChromeAsyncSocketTest, SSLConnectDuringPostedWrite) { - EXPECT_DEBUG_DEATH({ - DoOpenClosed(); - - async_socket_data_provider_.AddWrite( - net::MockWrite(net::ASYNC, kWriteData, 3)); - EXPECT_TRUE(chrome_async_socket_->Write(kWriteData, 3)); - - EXPECT_FALSE(chrome_async_socket_->StartTls("fakedomain.com")); - - base::RunLoop().RunUntilIdle(); - - DoCloseOpened( - SignalSocketState(SIGNAL_CLOSE, - ChromeAsyncSocket::STATE_CLOSED, - ChromeAsyncSocket::ERROR_WRONGSTATE, - net::OK)); - }, "wrong state"); -} - // After this we can assume SSL connect works as expected. -TEST_F(ChromeAsyncSocketTest, SSLRead) { +TEST_F(NetworkServiceAsyncSocketTest, SSLRead) { DoSSLOpenClosed(); async_socket_data_provider_.AddRead(net::MockRead(kReadData)); base::RunLoop().RunUntilIdle(); @@ -1049,22 +1157,21 @@ TEST_F(ChromeAsyncSocketTest, SSLRead) { DoSSLCloseOpenedNoError(); } -TEST_F(ChromeAsyncSocketTest, SSLSyncWrite) { +TEST_F(NetworkServiceAsyncSocketTest, SSLSyncWrite) { async_socket_data_provider_.AddWrite( net::MockWrite(net::SYNCHRONOUS, kWriteData, 3)); async_socket_data_provider_.AddWrite( net::MockWrite(net::SYNCHRONOUS, kWriteData + 3, 5)); - async_socket_data_provider_.AddWrite( - net::MockWrite(net::SYNCHRONOUS, - kWriteData + 8, arraysize(kWriteData) - 8)); + async_socket_data_provider_.AddWrite(net::MockWrite( + net::SYNCHRONOUS, kWriteData + 8, arraysize(kWriteData) - 8)); DoSSLOpenClosed(); - EXPECT_TRUE(chrome_async_socket_->Write(kWriteData, 3)); + EXPECT_TRUE(ns_async_socket_->Write(kWriteData, 3)); base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(chrome_async_socket_->Write(kWriteData + 3, 5)); + EXPECT_TRUE(ns_async_socket_->Write(kWriteData + 3, 5)); base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(chrome_async_socket_->Write(kWriteData + 8, - arraysize(kWriteData) - 8)); + EXPECT_TRUE( + ns_async_socket_->Write(kWriteData + 8, arraysize(kWriteData) - 8)); base::RunLoop().RunUntilIdle(); ExpectNoSignal(); @@ -1072,7 +1179,7 @@ TEST_F(ChromeAsyncSocketTest, SSLSyncWrite) { DoSSLCloseOpenedNoError(); } -TEST_F(ChromeAsyncSocketTest, SSLAsyncWrite) { +TEST_F(NetworkServiceAsyncSocketTest, SSLAsyncWrite) { DoSSLOpenClosed(); async_socket_data_provider_.AddWrite( @@ -1082,12 +1189,12 @@ TEST_F(ChromeAsyncSocketTest, SSLAsyncWrite) { async_socket_data_provider_.AddWrite( net::MockWrite(net::ASYNC, kWriteData + 8, arraysize(kWriteData) - 8)); - EXPECT_TRUE(chrome_async_socket_->Write(kWriteData, 3)); + EXPECT_TRUE(ns_async_socket_->Write(kWriteData, 3)); base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(chrome_async_socket_->Write(kWriteData + 3, 5)); + EXPECT_TRUE(ns_async_socket_->Write(kWriteData + 3, 5)); base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(chrome_async_socket_->Write(kWriteData + 8, - arraysize(kWriteData) - 8)); + EXPECT_TRUE( + ns_async_socket_->Write(kWriteData + 8, arraysize(kWriteData) - 8)); base::RunLoop().RunUntilIdle(); ExpectNoSignal(); @@ -1095,6 +1202,262 @@ TEST_F(ChromeAsyncSocketTest, SSLAsyncWrite) { DoSSLCloseOpenedNoError(); } +class NetworkServiceAsyncSocketMojoTest : public NetworkServiceAsyncSocketTest { + protected: + NetworkServiceAsyncSocketMojoTest() + : NetworkServiceAsyncSocketTest(true /* use_mojo_level_mock */) {} + ~NetworkServiceAsyncSocketMojoTest() override {} +}; + +TEST_F(NetworkServiceAsyncSocketMojoTest, ReadEOF1) { + DoOpenClosed(); + mock_proxy_resolving_socket_factory_->socket()->RunEvents( + {MockProxyResolvingSocket::kRead, + MockProxyResolvingSocket::kCloseReadPipe, + MockProxyResolvingSocket::kReadEofError, + MockProxyResolvingSocket::kCloseObserverPipe}); + + ExpectReadSignal(); + ExpectNoSignal(); + EXPECT_EQ("data", DrainRead(1)); + + base::RunLoop().RunUntilIdle(); + ExpectSignalSocketState(SignalSocketState::NoError( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED)); + ExpectClosed(); +} + +TEST_F(NetworkServiceAsyncSocketMojoTest, ReadEOF2) { + DoOpenClosed(); + mock_proxy_resolving_socket_factory_->socket()->RunEvents( + {MockProxyResolvingSocket::kReadEofError, + MockProxyResolvingSocket::kCloseObserverPipe, + MockProxyResolvingSocket::kRead, + MockProxyResolvingSocket::kCloseReadPipe}); + + ExpectReadSignal(); + ExpectNoSignal(); + EXPECT_EQ("data", DrainRead(1)); + + base::RunLoop().RunUntilIdle(); + ExpectSignalSocketState(SignalSocketState::NoError( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED)); + ExpectClosed(); +} + +TEST_F(NetworkServiceAsyncSocketMojoTest, ReadError1) { + DoOpenClosed(); + mock_proxy_resolving_socket_factory_->socket()->RunEvents( + {MockProxyResolvingSocket::kRead, + MockProxyResolvingSocket::kCloseReadPipe, + MockProxyResolvingSocket::kReadError, + MockProxyResolvingSocket::kCloseObserverPipe}); + + ExpectReadSignal(); + ExpectNoSignal(); + EXPECT_EQ("data", DrainRead(1)); + + base::RunLoop().RunUntilIdle(); + ExpectSignalSocketState(SignalSocketState( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WINSOCK, net::ERR_OUT_OF_MEMORY)); + ExpectClosed(); +} + +TEST_F(NetworkServiceAsyncSocketMojoTest, ReadError2) { + DoOpenClosed(); + mock_proxy_resolving_socket_factory_->socket()->RunEvents( + {MockProxyResolvingSocket::kReadError, + MockProxyResolvingSocket::kCloseObserverPipe, + MockProxyResolvingSocket::kRead, + MockProxyResolvingSocket::kCloseReadPipe}); + + ExpectReadSignal(); + ExpectNoSignal(); + EXPECT_EQ("data", DrainRead(1)); + + base::RunLoop().RunUntilIdle(); + ExpectSignalSocketState(SignalSocketState( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WINSOCK, net::ERR_OUT_OF_MEMORY)); + ExpectClosed(); +} + +TEST_F(NetworkServiceAsyncSocketMojoTest, ReadErrorDouble) { + DoOpenClosed(); + mock_proxy_resolving_socket_factory_->socket()->RunEvents( + {MockProxyResolvingSocket::kReadError, + MockProxyResolvingSocket::kReadError, + MockProxyResolvingSocket::kCloseObserverPipe, + MockProxyResolvingSocket::kRead, + MockProxyResolvingSocket::kCloseReadPipe}); + + ExpectReadSignal(); + ExpectNoSignal(); + EXPECT_EQ("data", DrainRead(1)); + + base::RunLoop().RunUntilIdle(); + ExpectSignalSocketState(SignalSocketState( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WINSOCK, net::ERR_OUT_OF_MEMORY)); + ExpectClosed(); +} + +TEST_F(NetworkServiceAsyncSocketMojoTest, ReadErrorDoubleInvalid) { + DoOpenClosed(); + mock_proxy_resolving_socket_factory_->socket()->RunEvents( + {MockProxyResolvingSocket::kReadError, + MockProxyResolvingSocket::kReadErrorInvalid, + MockProxyResolvingSocket::kCloseObserverPipe, + MockProxyResolvingSocket::kRead, + MockProxyResolvingSocket::kCloseReadPipe}); + + ExpectReadSignal(); + ExpectNoSignal(); + EXPECT_EQ("data", DrainRead(1)); + + base::RunLoop().RunUntilIdle(); + ExpectSignalSocketState(SignalSocketState( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WINSOCK, net::ERR_OUT_OF_MEMORY)); + ExpectClosed(); +} + +TEST_F(NetworkServiceAsyncSocketMojoTest, ReadErrorDoubleInvalid2) { + DoOpenClosed(); + mock_proxy_resolving_socket_factory_->socket()->RunEvents( + {MockProxyResolvingSocket::kReadErrorInvalid, + MockProxyResolvingSocket::kReadError, + MockProxyResolvingSocket::kCloseObserverPipe, + MockProxyResolvingSocket::kRead, + MockProxyResolvingSocket::kCloseReadPipe}); + + ExpectReadSignal(); + ExpectNoSignal(); + EXPECT_EQ("data", DrainRead(1)); + + base::RunLoop().RunUntilIdle(); + ExpectSignalSocketState(SignalSocketState( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WINSOCK, net::ERR_FAILED)); + ExpectClosed(); +} + +TEST_F(NetworkServiceAsyncSocketMojoTest, ReadErrorClosedObserverPipe) { + DoOpenClosed(); + mock_proxy_resolving_socket_factory_->socket()->RunEvents( + {MockProxyResolvingSocket::kRead, + MockProxyResolvingSocket::kCloseObserverPipe}); + // Can't run kCloseReadPipe since it'll already be closed. + + ExpectReadSignal(); + // Since this is a misbehaving network service process scenario, no attempt + // to recover the data is made. + ExpectSignalSocketState(SignalSocketState( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WINSOCK, net::ERR_FAILED)); + ExpectClosed(); +} + +TEST_F(NetworkServiceAsyncSocketMojoTest, WriteError1) { + DoOpenClosed(); + ExpectNoSignal(); + ns_async_socket_->Write("atad", 4); + base::RunLoop().RunUntilIdle(); + + mock_proxy_resolving_socket_factory_->socket()->RunEvents( + {MockProxyResolvingSocket::kWrite, + MockProxyResolvingSocket::kCloseWritePipe, + MockProxyResolvingSocket::kWriteError}); + // Cannot close the observer pipe here at the end since the other size + // would have closed it already. + + base::RunLoop().RunUntilIdle(); + ExpectSignalSocketState(SignalSocketState( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WINSOCK, net::ERR_ACCESS_DENIED)); + ExpectClosed(); +} + +TEST_F(NetworkServiceAsyncSocketMojoTest, WriteError2) { + DoOpenClosed(); + ExpectNoSignal(); + ns_async_socket_->Write("atad", 4); + base::RunLoop().RunUntilIdle(); + + mock_proxy_resolving_socket_factory_->socket()->RunEvents( + {MockProxyResolvingSocket::kWriteError, + MockProxyResolvingSocket::kCloseObserverPipe, + MockProxyResolvingSocket::kWrite, + MockProxyResolvingSocket::kCloseWritePipe}); + + base::RunLoop().RunUntilIdle(); + ExpectSignalSocketState(SignalSocketState( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WINSOCK, net::ERR_ACCESS_DENIED)); + ExpectClosed(); +} + +TEST_F(NetworkServiceAsyncSocketMojoTest, WriteErrorDouble) { + DoOpenClosed(); + ExpectNoSignal(); + ns_async_socket_->Write("atad", 4); + base::RunLoop().RunUntilIdle(); + + mock_proxy_resolving_socket_factory_->socket()->RunEvents( + {MockProxyResolvingSocket::kWriteError, + MockProxyResolvingSocket::kWriteError, + MockProxyResolvingSocket::kCloseObserverPipe, + MockProxyResolvingSocket::kWrite, + MockProxyResolvingSocket::kCloseWritePipe}); + + base::RunLoop().RunUntilIdle(); + ExpectSignalSocketState(SignalSocketState( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WINSOCK, net::ERR_ACCESS_DENIED)); + ExpectClosed(); +} + +TEST_F(NetworkServiceAsyncSocketMojoTest, WriteErrorDoubleInvalid) { + DoOpenClosed(); + ExpectNoSignal(); + ns_async_socket_->Write("atad", 4); + base::RunLoop().RunUntilIdle(); + + mock_proxy_resolving_socket_factory_->socket()->RunEvents( + {MockProxyResolvingSocket::kWriteError, + MockProxyResolvingSocket::kWriteErrorInvalid, + MockProxyResolvingSocket::kCloseObserverPipe, + MockProxyResolvingSocket::kWrite, + MockProxyResolvingSocket::kCloseWritePipe}); + + base::RunLoop().RunUntilIdle(); + ExpectSignalSocketState(SignalSocketState( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WINSOCK, net::ERR_ACCESS_DENIED)); + ExpectClosed(); +} + +TEST_F(NetworkServiceAsyncSocketMojoTest, WriteErrorDoubleInvalid2) { + DoOpenClosed(); + ExpectNoSignal(); + ns_async_socket_->Write("atad", 4); + base::RunLoop().RunUntilIdle(); + + mock_proxy_resolving_socket_factory_->socket()->RunEvents( + {MockProxyResolvingSocket::kWriteErrorInvalid, + MockProxyResolvingSocket::kWriteError, + MockProxyResolvingSocket::kCloseObserverPipe, + MockProxyResolvingSocket::kWrite, + MockProxyResolvingSocket::kCloseWritePipe}); + + base::RunLoop().RunUntilIdle(); + ExpectSignalSocketState(SignalSocketState( + SIGNAL_CLOSE, NetworkServiceAsyncSocket::STATE_CLOSED, + NetworkServiceAsyncSocket::ERROR_WINSOCK, net::ERR_FAILED)); + ExpectClosed(); +} + } // namespace } // namespace jingle_glue diff --git a/jingle/run_all_unittests.cc b/jingle/run_all_unittests.cc new file mode 100644 index 00000000000000..f4da01b37a9d08 --- /dev/null +++ b/jingle/run_all_unittests.cc @@ -0,0 +1,16 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/test/launcher/unit_test_launcher.h" +#include "base/test/test_suite.h" +#include "mojo/core/embedder/embedder.h" + +int main(int argc, char** argv) { + base::TestSuite test_suite(argc, argv); + + mojo::core::Init(); + return base::LaunchUnitTests( + argc, argv, + base::BindOnce(&base::TestSuite::Run, base::Unretained(&test_suite))); +}