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))); +}