123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050 |
- // Copyright 2013 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 "net/socket/tcp_socket.h"
- #include <stddef.h>
- #include <string.h>
- #include <memory>
- #include <string>
- #include <vector>
- #include "base/bind.h"
- #include "base/memory/ref_counted.h"
- #include "base/test/bind.h"
- #include "base/time/time.h"
- #include "build/build_config.h"
- #include "net/base/address_list.h"
- #include "net/base/io_buffer.h"
- #include "net/base/ip_endpoint.h"
- #include "net/base/net_errors.h"
- #include "net/base/sockaddr_storage.h"
- #include "net/base/sys_addrinfo.h"
- #include "net/base/test_completion_callback.h"
- #include "net/log/net_log_source.h"
- #include "net/socket/socket_descriptor.h"
- #include "net/socket/socket_performance_watcher.h"
- #include "net/socket/socket_test_util.h"
- #include "net/socket/tcp_client_socket.h"
- #include "net/test/embedded_test_server/embedded_test_server.h"
- #include "net/test/gtest_util.h"
- #include "net/test/test_with_task_environment.h"
- #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "testing/platform_test.h"
- #if BUILDFLAG(IS_ANDROID)
- #include "base/android/build_info.h"
- #include "base/android/radio_utils.h"
- #include "base/test/metrics/histogram_tester.h"
- #include "base/test/scoped_feature_list.h"
- #include "net/android/network_change_notifier_factory_android.h"
- #include "net/android/radio_activity_tracker.h"
- #include "net/base/features.h"
- #include "net/base/network_change_notifier.h"
- #endif // BUILDFLAG(IS_ANDROID)
- // For getsockopt() call.
- #if BUILDFLAG(IS_WIN)
- #include <winsock2.h>
- #else // !BUILDFLAG(IS_WIN)
- #include <sys/socket.h>
- #endif // !BUILDFLAG(IS_WIN)
- using net::test::IsError;
- using net::test::IsOk;
- namespace net {
- namespace {
- // IOBuffer with the ability to invoke a callback when destroyed. Useful for
- // checking for leaks.
- class IOBufferWithDestructionCallback : public IOBufferWithSize {
- public:
- explicit IOBufferWithDestructionCallback(base::OnceClosure on_destroy_closure)
- : IOBufferWithSize(1024),
- on_destroy_closure_(std::move(on_destroy_closure)) {
- DCHECK(on_destroy_closure_);
- }
- protected:
- ~IOBufferWithDestructionCallback() override {
- std::move(on_destroy_closure_).Run();
- }
- base::OnceClosure on_destroy_closure_;
- };
- class TestSocketPerformanceWatcher : public SocketPerformanceWatcher {
- public:
- explicit TestSocketPerformanceWatcher(bool should_notify_updated_rtt)
- : should_notify_updated_rtt_(should_notify_updated_rtt) {}
- TestSocketPerformanceWatcher(const TestSocketPerformanceWatcher&) = delete;
- TestSocketPerformanceWatcher& operator=(const TestSocketPerformanceWatcher&) =
- delete;
- ~TestSocketPerformanceWatcher() override = default;
- bool ShouldNotifyUpdatedRTT() const override {
- return should_notify_updated_rtt_;
- }
- void OnUpdatedRTTAvailable(const base::TimeDelta& rtt) override {
- rtt_notification_count_++;
- }
- void OnConnectionChanged() override { connection_changed_count_++; }
- size_t rtt_notification_count() const { return rtt_notification_count_; }
- size_t connection_changed_count() const { return connection_changed_count_; }
- private:
- const bool should_notify_updated_rtt_;
- size_t connection_changed_count_ = 0u;
- size_t rtt_notification_count_ = 0u;
- };
- const int kListenBacklog = 5;
- class TCPSocketTest : public PlatformTest, public WithTaskEnvironment {
- protected:
- TCPSocketTest() : socket_(nullptr, nullptr, NetLogSource()) {}
- void SetUpListenIPv4() {
- ASSERT_THAT(socket_.Open(ADDRESS_FAMILY_IPV4), IsOk());
- ASSERT_THAT(socket_.Bind(IPEndPoint(IPAddress::IPv4Localhost(), 0)),
- IsOk());
- ASSERT_THAT(socket_.Listen(kListenBacklog), IsOk());
- ASSERT_THAT(socket_.GetLocalAddress(&local_address_), IsOk());
- }
- void SetUpListenIPv6(bool* success) {
- *success = false;
- if (socket_.Open(ADDRESS_FAMILY_IPV6) != OK ||
- socket_.Bind(IPEndPoint(IPAddress::IPv6Localhost(), 0)) != OK ||
- socket_.Listen(kListenBacklog) != OK) {
- LOG(ERROR) << "Failed to listen on ::1 - probably because IPv6 is "
- "disabled. Skipping the test";
- return;
- }
- ASSERT_THAT(socket_.GetLocalAddress(&local_address_), IsOk());
- *success = true;
- }
- void TestAcceptAsync() {
- TestCompletionCallback accept_callback;
- std::unique_ptr<TCPSocket> accepted_socket;
- IPEndPoint accepted_address;
- ASSERT_THAT(socket_.Accept(&accepted_socket, &accepted_address,
- accept_callback.callback()),
- IsError(ERR_IO_PENDING));
- TestCompletionCallback connect_callback;
- TCPClientSocket connecting_socket(local_address_list(), nullptr, nullptr,
- nullptr, NetLogSource());
- int connect_result = connecting_socket.Connect(connect_callback.callback());
- EXPECT_THAT(connect_callback.GetResult(connect_result), IsOk());
- EXPECT_THAT(accept_callback.WaitForResult(), IsOk());
- EXPECT_TRUE(accepted_socket.get());
- // Both sockets should be on the loopback network interface.
- EXPECT_EQ(accepted_address.address(), local_address_.address());
- }
- #if defined(TCP_INFO) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
- // Tests that notifications to Socket Performance Watcher (SPW) are delivered
- // correctly. |should_notify_updated_rtt| is true if the SPW is interested in
- // receiving RTT notifications. |num_messages| is the number of messages that
- // are written/read by the sockets. |expect_connection_changed_count| is the
- // expected number of connection change notifications received by the SPW.
- // |expect_rtt_notification_count| is the expected number of RTT
- // notifications received by the SPW. This test works by writing
- // |num_messages| to the socket. A different socket (with a SPW attached to
- // it) reads the messages.
- void TestSPWNotifications(bool should_notify_updated_rtt,
- size_t num_messages,
- size_t expect_connection_changed_count,
- size_t expect_rtt_notification_count) {
- ASSERT_NO_FATAL_FAILURE(SetUpListenIPv4());
- TestCompletionCallback connect_callback;
- auto watcher = std::make_unique<TestSocketPerformanceWatcher>(
- should_notify_updated_rtt);
- TestSocketPerformanceWatcher* watcher_ptr = watcher.get();
- TCPSocket connecting_socket(std::move(watcher), nullptr, NetLogSource());
- int result = connecting_socket.Open(ADDRESS_FAMILY_IPV4);
- ASSERT_THAT(result, IsOk());
- int connect_result =
- connecting_socket.Connect(local_address_, connect_callback.callback());
- TestCompletionCallback accept_callback;
- std::unique_ptr<TCPSocket> accepted_socket;
- IPEndPoint accepted_address;
- result = socket_.Accept(&accepted_socket, &accepted_address,
- accept_callback.callback());
- ASSERT_THAT(accept_callback.GetResult(result), IsOk());
- ASSERT_TRUE(accepted_socket.get());
- // Both sockets should be on the loopback network interface.
- EXPECT_EQ(accepted_address.address(), local_address_.address());
- ASSERT_THAT(connect_callback.GetResult(connect_result), IsOk());
- for (size_t i = 0; i < num_messages; ++i) {
- // Use a 1 byte message so that the watcher is notified at most once per
- // message.
- const std::string message("t");
- scoped_refptr<IOBufferWithSize> write_buffer =
- base::MakeRefCounted<IOBufferWithSize>(message.size());
- memmove(write_buffer->data(), message.data(), message.size());
- TestCompletionCallback write_callback;
- int write_result = accepted_socket->Write(
- write_buffer.get(), write_buffer->size(), write_callback.callback(),
- TRAFFIC_ANNOTATION_FOR_TESTS);
- scoped_refptr<IOBufferWithSize> read_buffer =
- base::MakeRefCounted<IOBufferWithSize>(message.size());
- TestCompletionCallback read_callback;
- int read_result = connecting_socket.Read(
- read_buffer.get(), read_buffer->size(), read_callback.callback());
- ASSERT_EQ(1, write_callback.GetResult(write_result));
- ASSERT_EQ(1, read_callback.GetResult(read_result));
- }
- EXPECT_EQ(expect_connection_changed_count,
- watcher_ptr->connection_changed_count());
- EXPECT_EQ(expect_rtt_notification_count,
- watcher_ptr->rtt_notification_count());
- }
- #endif // defined(TCP_INFO) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
- AddressList local_address_list() const {
- return AddressList(local_address_);
- }
- TCPSocket socket_;
- IPEndPoint local_address_;
- };
- // Test listening and accepting with a socket bound to an IPv4 address.
- TEST_F(TCPSocketTest, Accept) {
- ASSERT_NO_FATAL_FAILURE(SetUpListenIPv4());
- TestCompletionCallback connect_callback;
- // TODO(yzshen): Switch to use TCPSocket when it supports client socket
- // operations.
- TCPClientSocket connecting_socket(local_address_list(), nullptr, nullptr,
- nullptr, NetLogSource());
- int connect_result = connecting_socket.Connect(connect_callback.callback());
- TestCompletionCallback accept_callback;
- std::unique_ptr<TCPSocket> accepted_socket;
- IPEndPoint accepted_address;
- int result = socket_.Accept(&accepted_socket, &accepted_address,
- accept_callback.callback());
- ASSERT_THAT(accept_callback.GetResult(result), IsOk());
- EXPECT_TRUE(accepted_socket.get());
- // Both sockets should be on the loopback network interface.
- EXPECT_EQ(accepted_address.address(), local_address_.address());
- EXPECT_THAT(connect_callback.GetResult(connect_result), IsOk());
- }
- // Test Accept() callback.
- TEST_F(TCPSocketTest, AcceptAsync) {
- ASSERT_NO_FATAL_FAILURE(SetUpListenIPv4());
- TestAcceptAsync();
- }
- // Test AdoptConnectedSocket()
- TEST_F(TCPSocketTest, AdoptConnectedSocket) {
- TCPSocket accepting_socket(nullptr, nullptr, NetLogSource());
- ASSERT_THAT(accepting_socket.Open(ADDRESS_FAMILY_IPV4), IsOk());
- ASSERT_THAT(accepting_socket.Bind(IPEndPoint(IPAddress::IPv4Localhost(), 0)),
- IsOk());
- ASSERT_THAT(accepting_socket.GetLocalAddress(&local_address_), IsOk());
- ASSERT_THAT(accepting_socket.Listen(kListenBacklog), IsOk());
- TestCompletionCallback connect_callback;
- // TODO(yzshen): Switch to use TCPSocket when it supports client socket
- // operations.
- TCPClientSocket connecting_socket(local_address_list(), nullptr, nullptr,
- nullptr, NetLogSource());
- int connect_result = connecting_socket.Connect(connect_callback.callback());
- TestCompletionCallback accept_callback;
- std::unique_ptr<TCPSocket> accepted_socket;
- IPEndPoint accepted_address;
- int result = accepting_socket.Accept(&accepted_socket, &accepted_address,
- accept_callback.callback());
- ASSERT_THAT(accept_callback.GetResult(result), IsOk());
- SocketDescriptor accepted_descriptor =
- accepted_socket->ReleaseSocketDescriptorForTesting();
- ASSERT_THAT(
- socket_.AdoptConnectedSocket(accepted_descriptor, accepted_address),
- IsOk());
- // socket_ should now have the local address.
- IPEndPoint adopted_address;
- ASSERT_THAT(socket_.GetLocalAddress(&adopted_address), IsOk());
- EXPECT_EQ(local_address_.address(), adopted_address.address());
- EXPECT_THAT(connect_callback.GetResult(connect_result), IsOk());
- }
- // Test Accept() for AdoptUnconnectedSocket.
- TEST_F(TCPSocketTest, AcceptForAdoptedUnconnectedSocket) {
- SocketDescriptor existing_socket =
- CreatePlatformSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- ASSERT_THAT(socket_.AdoptUnconnectedSocket(existing_socket), IsOk());
- IPEndPoint address(IPAddress::IPv4Localhost(), 0);
- SockaddrStorage storage;
- ASSERT_TRUE(address.ToSockAddr(storage.addr, &storage.addr_len));
- ASSERT_EQ(0, bind(existing_socket, storage.addr, storage.addr_len));
- ASSERT_THAT(socket_.Listen(kListenBacklog), IsOk());
- ASSERT_THAT(socket_.GetLocalAddress(&local_address_), IsOk());
- TestAcceptAsync();
- }
- // Accept two connections simultaneously.
- TEST_F(TCPSocketTest, Accept2Connections) {
- ASSERT_NO_FATAL_FAILURE(SetUpListenIPv4());
- TestCompletionCallback accept_callback;
- std::unique_ptr<TCPSocket> accepted_socket;
- IPEndPoint accepted_address;
- ASSERT_THAT(socket_.Accept(&accepted_socket, &accepted_address,
- accept_callback.callback()),
- IsError(ERR_IO_PENDING));
- TestCompletionCallback connect_callback;
- TCPClientSocket connecting_socket(local_address_list(), nullptr, nullptr,
- nullptr, NetLogSource());
- int connect_result = connecting_socket.Connect(connect_callback.callback());
- TestCompletionCallback connect_callback2;
- TCPClientSocket connecting_socket2(local_address_list(), nullptr, nullptr,
- nullptr, NetLogSource());
- int connect_result2 =
- connecting_socket2.Connect(connect_callback2.callback());
- EXPECT_THAT(accept_callback.WaitForResult(), IsOk());
- TestCompletionCallback accept_callback2;
- std::unique_ptr<TCPSocket> accepted_socket2;
- IPEndPoint accepted_address2;
- int result = socket_.Accept(&accepted_socket2, &accepted_address2,
- accept_callback2.callback());
- ASSERT_THAT(accept_callback2.GetResult(result), IsOk());
- EXPECT_THAT(connect_callback.GetResult(connect_result), IsOk());
- EXPECT_THAT(connect_callback2.GetResult(connect_result2), IsOk());
- EXPECT_TRUE(accepted_socket.get());
- EXPECT_TRUE(accepted_socket2.get());
- EXPECT_NE(accepted_socket.get(), accepted_socket2.get());
- EXPECT_EQ(accepted_address.address(), local_address_.address());
- EXPECT_EQ(accepted_address2.address(), local_address_.address());
- }
- // Test listening and accepting with a socket bound to an IPv6 address.
- TEST_F(TCPSocketTest, AcceptIPv6) {
- bool initialized = false;
- ASSERT_NO_FATAL_FAILURE(SetUpListenIPv6(&initialized));
- if (!initialized)
- return;
- TestCompletionCallback connect_callback;
- TCPClientSocket connecting_socket(local_address_list(), nullptr, nullptr,
- nullptr, NetLogSource());
- int connect_result = connecting_socket.Connect(connect_callback.callback());
- TestCompletionCallback accept_callback;
- std::unique_ptr<TCPSocket> accepted_socket;
- IPEndPoint accepted_address;
- int result = socket_.Accept(&accepted_socket, &accepted_address,
- accept_callback.callback());
- ASSERT_THAT(accept_callback.GetResult(result), IsOk());
- EXPECT_TRUE(accepted_socket.get());
- // Both sockets should be on the loopback network interface.
- EXPECT_EQ(accepted_address.address(), local_address_.address());
- EXPECT_THAT(connect_callback.GetResult(connect_result), IsOk());
- }
- TEST_F(TCPSocketTest, ReadWrite) {
- ASSERT_NO_FATAL_FAILURE(SetUpListenIPv4());
- TestCompletionCallback connect_callback;
- TCPSocket connecting_socket(nullptr, nullptr, NetLogSource());
- int result = connecting_socket.Open(ADDRESS_FAMILY_IPV4);
- ASSERT_THAT(result, IsOk());
- int connect_result =
- connecting_socket.Connect(local_address_, connect_callback.callback());
- TestCompletionCallback accept_callback;
- std::unique_ptr<TCPSocket> accepted_socket;
- IPEndPoint accepted_address;
- result = socket_.Accept(&accepted_socket, &accepted_address,
- accept_callback.callback());
- ASSERT_THAT(accept_callback.GetResult(result), IsOk());
- ASSERT_TRUE(accepted_socket.get());
- // Both sockets should be on the loopback network interface.
- EXPECT_EQ(accepted_address.address(), local_address_.address());
- EXPECT_THAT(connect_callback.GetResult(connect_result), IsOk());
- const std::string message("test message");
- std::vector<char> buffer(message.size());
- size_t bytes_written = 0;
- while (bytes_written < message.size()) {
- scoped_refptr<IOBufferWithSize> write_buffer =
- base::MakeRefCounted<IOBufferWithSize>(message.size() - bytes_written);
- memmove(write_buffer->data(), message.data() + bytes_written,
- message.size() - bytes_written);
- TestCompletionCallback write_callback;
- int write_result = accepted_socket->Write(
- write_buffer.get(), write_buffer->size(), write_callback.callback(),
- TRAFFIC_ANNOTATION_FOR_TESTS);
- write_result = write_callback.GetResult(write_result);
- ASSERT_TRUE(write_result >= 0);
- bytes_written += write_result;
- ASSERT_TRUE(bytes_written <= message.size());
- }
- size_t bytes_read = 0;
- while (bytes_read < message.size()) {
- scoped_refptr<IOBufferWithSize> read_buffer =
- base::MakeRefCounted<IOBufferWithSize>(message.size() - bytes_read);
- TestCompletionCallback read_callback;
- int read_result = connecting_socket.Read(
- read_buffer.get(), read_buffer->size(), read_callback.callback());
- read_result = read_callback.GetResult(read_result);
- ASSERT_TRUE(read_result >= 0);
- ASSERT_TRUE(bytes_read + read_result <= message.size());
- memmove(&buffer[bytes_read], read_buffer->data(), read_result);
- bytes_read += read_result;
- }
- std::string received_message(buffer.begin(), buffer.end());
- ASSERT_EQ(message, received_message);
- }
- // Destroy a TCPSocket while there's a pending read, and make sure the read
- // IOBuffer that the socket was holding on to is destroyed.
- // See https://crbug.com/804868.
- TEST_F(TCPSocketTest, DestroyWithPendingRead) {
- ASSERT_NO_FATAL_FAILURE(SetUpListenIPv4());
- // Create a connected socket.
- TestCompletionCallback connect_callback;
- std::unique_ptr<TCPSocket> connecting_socket =
- std::make_unique<TCPSocket>(nullptr, nullptr, NetLogSource());
- int result = connecting_socket->Open(ADDRESS_FAMILY_IPV4);
- ASSERT_THAT(result, IsOk());
- int connect_result =
- connecting_socket->Connect(local_address_, connect_callback.callback());
- TestCompletionCallback accept_callback;
- std::unique_ptr<TCPSocket> accepted_socket;
- IPEndPoint accepted_address;
- result = socket_.Accept(&accepted_socket, &accepted_address,
- accept_callback.callback());
- ASSERT_THAT(accept_callback.GetResult(result), IsOk());
- ASSERT_TRUE(accepted_socket.get());
- ASSERT_THAT(connect_callback.GetResult(connect_result), IsOk());
- // Try to read from the socket, but never write anything to the other end.
- base::RunLoop run_loop;
- scoped_refptr<IOBufferWithDestructionCallback> read_buffer(
- base::MakeRefCounted<IOBufferWithDestructionCallback>(
- run_loop.QuitClosure()));
- TestCompletionCallback read_callback;
- EXPECT_EQ(ERR_IO_PENDING,
- connecting_socket->Read(read_buffer.get(), read_buffer->size(),
- read_callback.callback()));
- // Release the handle to the read buffer and destroy the socket. Make sure the
- // read buffer is destroyed.
- read_buffer = nullptr;
- connecting_socket.reset();
- run_loop.Run();
- }
- // Destroy a TCPSocket while there's a pending write, and make sure the write
- // IOBuffer that the socket was holding on to is destroyed.
- TEST_F(TCPSocketTest, DestroyWithPendingWrite) {
- ASSERT_NO_FATAL_FAILURE(SetUpListenIPv4());
- // Create a connected socket.
- TestCompletionCallback connect_callback;
- std::unique_ptr<TCPSocket> connecting_socket =
- std::make_unique<TCPSocket>(nullptr, nullptr, NetLogSource());
- int result = connecting_socket->Open(ADDRESS_FAMILY_IPV4);
- ASSERT_THAT(result, IsOk());
- int connect_result =
- connecting_socket->Connect(local_address_, connect_callback.callback());
- TestCompletionCallback accept_callback;
- std::unique_ptr<TCPSocket> accepted_socket;
- IPEndPoint accepted_address;
- result = socket_.Accept(&accepted_socket, &accepted_address,
- accept_callback.callback());
- ASSERT_THAT(accept_callback.GetResult(result), IsOk());
- ASSERT_TRUE(accepted_socket.get());
- ASSERT_THAT(connect_callback.GetResult(connect_result), IsOk());
- // Repeatedly write to the socket until an operation does not complete
- // synchronously.
- base::RunLoop run_loop;
- scoped_refptr<IOBufferWithDestructionCallback> write_buffer(
- base::MakeRefCounted<IOBufferWithDestructionCallback>(
- run_loop.QuitClosure()));
- memset(write_buffer->data(), '1', write_buffer->size());
- TestCompletionCallback write_callback;
- while (true) {
- result = connecting_socket->Write(write_buffer.get(), write_buffer->size(),
- write_callback.callback(),
- TRAFFIC_ANNOTATION_FOR_TESTS);
- if (result == ERR_IO_PENDING)
- break;
- ASSERT_LT(0, result);
- }
- // Release the handle to the read buffer and destroy the socket. Make sure the
- // write buffer is destroyed.
- write_buffer = nullptr;
- connecting_socket.reset();
- run_loop.Run();
- }
- // If a ReadIfReady is pending, it's legal to cancel it and start reading later.
- TEST_F(TCPSocketTest, CancelPendingReadIfReady) {
- ASSERT_NO_FATAL_FAILURE(SetUpListenIPv4());
- // Create a connected socket.
- TestCompletionCallback connect_callback;
- std::unique_ptr<TCPSocket> connecting_socket =
- std::make_unique<TCPSocket>(nullptr, nullptr, NetLogSource());
- int result = connecting_socket->Open(ADDRESS_FAMILY_IPV4);
- ASSERT_THAT(result, IsOk());
- int connect_result =
- connecting_socket->Connect(local_address_, connect_callback.callback());
- TestCompletionCallback accept_callback;
- std::unique_ptr<TCPSocket> accepted_socket;
- IPEndPoint accepted_address;
- result = socket_.Accept(&accepted_socket, &accepted_address,
- accept_callback.callback());
- ASSERT_THAT(accept_callback.GetResult(result), IsOk());
- ASSERT_TRUE(accepted_socket.get());
- ASSERT_THAT(connect_callback.GetResult(connect_result), IsOk());
- // Try to read from the socket, but never write anything to the other end.
- base::RunLoop run_loop;
- scoped_refptr<IOBufferWithDestructionCallback> read_buffer(
- base::MakeRefCounted<IOBufferWithDestructionCallback>(
- run_loop.QuitClosure()));
- TestCompletionCallback read_callback;
- EXPECT_EQ(ERR_IO_PENDING, connecting_socket->ReadIfReady(
- read_buffer.get(), read_buffer->size(),
- read_callback.callback()));
- // Now cancel the pending ReadIfReady().
- connecting_socket->CancelReadIfReady();
- // Send data to |connecting_socket|.
- const char kMsg[] = "hello!";
- scoped_refptr<StringIOBuffer> write_buffer =
- base::MakeRefCounted<StringIOBuffer>(kMsg);
- TestCompletionCallback write_callback;
- int write_result = accepted_socket->Write(write_buffer.get(), strlen(kMsg),
- write_callback.callback(),
- TRAFFIC_ANNOTATION_FOR_TESTS);
- const int msg_size = strlen(kMsg);
- ASSERT_EQ(msg_size, write_result);
- TestCompletionCallback read_callback2;
- int read_result = connecting_socket->ReadIfReady(
- read_buffer.get(), read_buffer->size(), read_callback2.callback());
- if (read_result == ERR_IO_PENDING) {
- ASSERT_EQ(OK, read_callback2.GetResult(read_result));
- read_result = connecting_socket->ReadIfReady(
- read_buffer.get(), read_buffer->size(), read_callback2.callback());
- }
- ASSERT_EQ(msg_size, read_result);
- ASSERT_EQ(0, memcmp(&kMsg, read_buffer->data(), msg_size));
- }
- TEST_F(TCPSocketTest, IsConnected) {
- ASSERT_NO_FATAL_FAILURE(SetUpListenIPv4());
- TestCompletionCallback accept_callback;
- std::unique_ptr<TCPSocket> accepted_socket;
- IPEndPoint accepted_address;
- EXPECT_THAT(socket_.Accept(&accepted_socket, &accepted_address,
- accept_callback.callback()),
- IsError(ERR_IO_PENDING));
- TestCompletionCallback connect_callback;
- TCPClientSocket connecting_socket(local_address_list(), nullptr, nullptr,
- nullptr, NetLogSource());
- // Immediately after creation, the socket should not be connected.
- EXPECT_FALSE(connecting_socket.IsConnected());
- EXPECT_FALSE(connecting_socket.IsConnectedAndIdle());
- int connect_result = connecting_socket.Connect(connect_callback.callback());
- EXPECT_THAT(accept_callback.WaitForResult(), IsOk());
- EXPECT_THAT(connect_callback.GetResult(connect_result), IsOk());
- // |connecting_socket| and |accepted_socket| should now both be reported as
- // connected, and idle
- EXPECT_TRUE(accepted_socket->IsConnected());
- EXPECT_TRUE(accepted_socket->IsConnectedAndIdle());
- EXPECT_TRUE(connecting_socket.IsConnected());
- EXPECT_TRUE(connecting_socket.IsConnectedAndIdle());
- // Write one byte to the |accepted_socket|, then close it.
- const char kSomeData[] = "!";
- scoped_refptr<IOBuffer> some_data_buffer =
- base::MakeRefCounted<StringIOBuffer>(kSomeData);
- TestCompletionCallback write_callback;
- EXPECT_THAT(write_callback.GetResult(accepted_socket->Write(
- some_data_buffer.get(), 1, write_callback.callback(),
- TRAFFIC_ANNOTATION_FOR_TESTS)),
- 1);
- accepted_socket.reset();
- // Wait until |connecting_socket| is signalled as having data to read.
- fd_set read_fds;
- FD_ZERO(&read_fds);
- SocketDescriptor connecting_fd =
- connecting_socket.SocketDescriptorForTesting();
- FD_SET(connecting_fd, &read_fds);
- ASSERT_EQ(select(FD_SETSIZE, &read_fds, nullptr, nullptr, nullptr), 1);
- ASSERT_TRUE(FD_ISSET(connecting_fd, &read_fds));
- // It should now be reported as connected, but not as idle.
- EXPECT_TRUE(connecting_socket.IsConnected());
- EXPECT_FALSE(connecting_socket.IsConnectedAndIdle());
- // Read the message from |connecting_socket_|, then read the end-of-stream.
- scoped_refptr<IOBufferWithSize> read_buffer =
- base::MakeRefCounted<IOBufferWithSize>(2);
- TestCompletionCallback read_callback;
- EXPECT_THAT(
- read_callback.GetResult(connecting_socket.Read(
- read_buffer.get(), read_buffer->size(), read_callback.callback())),
- 1);
- EXPECT_THAT(
- read_callback.GetResult(connecting_socket.Read(
- read_buffer.get(), read_buffer->size(), read_callback.callback())),
- 0);
- // |connecting_socket| has no more data to read, so should noe be reported
- // as disconnected.
- EXPECT_FALSE(connecting_socket.IsConnected());
- EXPECT_FALSE(connecting_socket.IsConnectedAndIdle());
- }
- // Tests that setting a socket option in the BeforeConnectCallback works. With
- // real sockets, socket options often have to be set before the connect() call,
- // and the BeforeConnectCallback is the only way to do that, with a
- // TCPClientSocket.
- TEST_F(TCPSocketTest, BeforeConnectCallback) {
- // A receive buffer size that is between max and minimum buffer size limits,
- // and weird enough to likely not be a default value.
- const int kReceiveBufferSize = 32 * 1024 + 1117;
- ASSERT_NO_FATAL_FAILURE(SetUpListenIPv4());
- TestCompletionCallback accept_callback;
- std::unique_ptr<TCPSocket> accepted_socket;
- IPEndPoint accepted_address;
- EXPECT_THAT(socket_.Accept(&accepted_socket, &accepted_address,
- accept_callback.callback()),
- IsError(ERR_IO_PENDING));
- TestCompletionCallback connect_callback;
- TCPClientSocket connecting_socket(local_address_list(), nullptr, nullptr,
- nullptr, NetLogSource());
- connecting_socket.SetBeforeConnectCallback(base::BindLambdaForTesting([&] {
- EXPECT_FALSE(connecting_socket.IsConnected());
- int result = connecting_socket.SetReceiveBufferSize(kReceiveBufferSize);
- EXPECT_THAT(result, IsOk());
- return result;
- }));
- int connect_result = connecting_socket.Connect(connect_callback.callback());
- EXPECT_THAT(accept_callback.WaitForResult(), IsOk());
- EXPECT_THAT(connect_callback.GetResult(connect_result), IsOk());
- int actual_size = 0;
- socklen_t actual_size_len = sizeof(actual_size);
- int os_result = getsockopt(
- connecting_socket.SocketDescriptorForTesting(), SOL_SOCKET, SO_RCVBUF,
- reinterpret_cast<char*>(&actual_size), &actual_size_len);
- ASSERT_EQ(0, os_result);
- // Linux platforms generally allocate twice as much buffer size is requested to
- // account for internal kernel data structures.
- #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
- EXPECT_EQ(2 * kReceiveBufferSize, actual_size);
- // Unfortunately, Apple platform behavior doesn't seem to be documented, and
- // doesn't match behavior on any other platforms.
- // Fuchsia doesn't currently implement SO_RCVBUF.
- #elif !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_FUCHSIA)
- EXPECT_EQ(kReceiveBufferSize, actual_size);
- #endif
- }
- TEST_F(TCPSocketTest, BeforeConnectCallbackFails) {
- // Setting up a server isn't strictly necessary, but it does allow checking
- // the server was never connected to.
- ASSERT_NO_FATAL_FAILURE(SetUpListenIPv4());
- TestCompletionCallback accept_callback;
- std::unique_ptr<TCPSocket> accepted_socket;
- IPEndPoint accepted_address;
- EXPECT_THAT(socket_.Accept(&accepted_socket, &accepted_address,
- accept_callback.callback()),
- IsError(ERR_IO_PENDING));
- TestCompletionCallback connect_callback;
- TCPClientSocket connecting_socket(local_address_list(), nullptr, nullptr,
- nullptr, NetLogSource());
- // Set a callback that returns a nonsensical error, and make sure it's
- // returned.
- connecting_socket.SetBeforeConnectCallback(base::BindRepeating(
- [] { return static_cast<int>(net::ERR_NAME_NOT_RESOLVED); }));
- int connect_result = connecting_socket.Connect(connect_callback.callback());
- EXPECT_THAT(connect_callback.GetResult(connect_result),
- IsError(net::ERR_NAME_NOT_RESOLVED));
- // Best effort check that the socket wasn't accepted - may flakily pass on
- // regression, unfortunately.
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(accept_callback.have_result());
- }
- TEST_F(TCPSocketTest, SetKeepAlive) {
- ASSERT_NO_FATAL_FAILURE(SetUpListenIPv4());
- TestCompletionCallback accept_callback;
- std::unique_ptr<TCPSocket> accepted_socket;
- IPEndPoint accepted_address;
- EXPECT_THAT(socket_.Accept(&accepted_socket, &accepted_address,
- accept_callback.callback()),
- IsError(ERR_IO_PENDING));
- TestCompletionCallback connect_callback;
- TCPClientSocket connecting_socket(local_address_list(), nullptr, nullptr,
- nullptr, NetLogSource());
- // Non-connected sockets should not be able to set KeepAlive.
- ASSERT_FALSE(connecting_socket.IsConnected());
- EXPECT_FALSE(
- connecting_socket.SetKeepAlive(true /* enable */, 14 /* delay */));
- // Connect.
- int connect_result = connecting_socket.Connect(connect_callback.callback());
- EXPECT_THAT(accept_callback.WaitForResult(), IsOk());
- EXPECT_THAT(connect_callback.GetResult(connect_result), IsOk());
- // Connected sockets should be able to enable and disable KeepAlive.
- ASSERT_TRUE(connecting_socket.IsConnected());
- EXPECT_TRUE(
- connecting_socket.SetKeepAlive(true /* enable */, 22 /* delay */));
- EXPECT_TRUE(
- connecting_socket.SetKeepAlive(false /* enable */, 3 /* delay */));
- }
- TEST_F(TCPSocketTest, SetNoDelay) {
- ASSERT_NO_FATAL_FAILURE(SetUpListenIPv4());
- TestCompletionCallback accept_callback;
- std::unique_ptr<TCPSocket> accepted_socket;
- IPEndPoint accepted_address;
- EXPECT_THAT(socket_.Accept(&accepted_socket, &accepted_address,
- accept_callback.callback()),
- IsError(ERR_IO_PENDING));
- TestCompletionCallback connect_callback;
- TCPClientSocket connecting_socket(local_address_list(), nullptr, nullptr,
- nullptr, NetLogSource());
- // Non-connected sockets should not be able to set NoDelay.
- ASSERT_FALSE(connecting_socket.IsConnected());
- EXPECT_FALSE(connecting_socket.SetNoDelay(true /* no_delay */));
- // Connect.
- int connect_result = connecting_socket.Connect(connect_callback.callback());
- EXPECT_THAT(accept_callback.WaitForResult(), IsOk());
- EXPECT_THAT(connect_callback.GetResult(connect_result), IsOk());
- // Connected sockets should be able to enable and disable NoDelay.
- ASSERT_TRUE(connecting_socket.IsConnected());
- EXPECT_TRUE(connecting_socket.SetNoDelay(true /* no_delay */));
- EXPECT_TRUE(connecting_socket.SetNoDelay(false /* no_delay */));
- }
- // These tests require kernel support for tcp_info struct, and so they are
- // enabled only on certain platforms.
- #if defined(TCP_INFO) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
- // If SocketPerformanceWatcher::ShouldNotifyUpdatedRTT always returns false,
- // then the wtatcher should not receive any notifications.
- TEST_F(TCPSocketTest, SPWNotInterested) {
- TestSPWNotifications(false, 2u, 0u, 0u);
- }
- // One notification should be received when the socket connects. One
- // additional notification should be received for each message read.
- TEST_F(TCPSocketTest, SPWNoAdvance) {
- TestSPWNotifications(true, 2u, 0u, 3u);
- }
- #endif // defined(TCP_INFO) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
- // On Android, where socket tagging is supported, verify that TCPSocket::Tag
- // works as expected.
- #if BUILDFLAG(IS_ANDROID)
- TEST_F(TCPSocketTest, Tag) {
- if (!CanGetTaggedBytes()) {
- DVLOG(0) << "Skipping test - GetTaggedBytes unsupported.";
- return;
- }
- // Start test server.
- EmbeddedTestServer test_server;
- test_server.AddDefaultHandlers(base::FilePath());
- ASSERT_TRUE(test_server.Start());
- AddressList addr_list;
- ASSERT_TRUE(test_server.GetAddressList(&addr_list));
- EXPECT_EQ(socket_.Open(addr_list[0].GetFamily()), OK);
- // Verify TCP connect packets are tagged and counted properly.
- int32_t tag_val1 = 0x12345678;
- uint64_t old_traffic = GetTaggedBytes(tag_val1);
- SocketTag tag1(SocketTag::UNSET_UID, tag_val1);
- socket_.ApplySocketTag(tag1);
- TestCompletionCallback connect_callback;
- int connect_result =
- socket_.Connect(addr_list[0], connect_callback.callback());
- EXPECT_THAT(connect_callback.GetResult(connect_result), IsOk());
- EXPECT_GT(GetTaggedBytes(tag_val1), old_traffic);
- // Verify socket can be retagged with a new value and the current process's
- // UID.
- int32_t tag_val2 = 0x87654321;
- old_traffic = GetTaggedBytes(tag_val2);
- SocketTag tag2(getuid(), tag_val2);
- socket_.ApplySocketTag(tag2);
- const char kRequest1[] = "GET / HTTP/1.0";
- scoped_refptr<IOBuffer> write_buffer1 =
- base::MakeRefCounted<StringIOBuffer>(kRequest1);
- TestCompletionCallback write_callback1;
- EXPECT_EQ(
- socket_.Write(write_buffer1.get(), strlen(kRequest1),
- write_callback1.callback(), TRAFFIC_ANNOTATION_FOR_TESTS),
- static_cast<int>(strlen(kRequest1)));
- EXPECT_GT(GetTaggedBytes(tag_val2), old_traffic);
- // Verify socket can be retagged with a new value and the current process's
- // UID.
- old_traffic = GetTaggedBytes(tag_val1);
- socket_.ApplySocketTag(tag1);
- const char kRequest2[] = "\n\n";
- scoped_refptr<IOBuffer> write_buffer2 =
- base::MakeRefCounted<StringIOBuffer>(kRequest2);
- TestCompletionCallback write_callback2;
- EXPECT_EQ(
- socket_.Write(write_buffer2.get(), strlen(kRequest2),
- write_callback2.callback(), TRAFFIC_ANNOTATION_FOR_TESTS),
- static_cast<int>(strlen(kRequest2)));
- EXPECT_GT(GetTaggedBytes(tag_val1), old_traffic);
- socket_.Close();
- }
- TEST_F(TCPSocketTest, TagAfterConnect) {
- if (!CanGetTaggedBytes()) {
- DVLOG(0) << "Skipping test - GetTaggedBytes unsupported.";
- return;
- }
- // Start test server.
- EmbeddedTestServer test_server;
- test_server.AddDefaultHandlers(base::FilePath());
- ASSERT_TRUE(test_server.Start());
- AddressList addr_list;
- ASSERT_TRUE(test_server.GetAddressList(&addr_list));
- EXPECT_EQ(socket_.Open(addr_list[0].GetFamily()), OK);
- // Connect socket.
- TestCompletionCallback connect_callback;
- int connect_result =
- socket_.Connect(addr_list[0], connect_callback.callback());
- EXPECT_THAT(connect_callback.GetResult(connect_result), IsOk());
- // Verify socket can be tagged with a new value and the current process's
- // UID.
- int32_t tag_val2 = 0x87654321;
- uint64_t old_traffic = GetTaggedBytes(tag_val2);
- SocketTag tag2(getuid(), tag_val2);
- socket_.ApplySocketTag(tag2);
- const char kRequest1[] = "GET / HTTP/1.0";
- scoped_refptr<IOBuffer> write_buffer1 =
- base::MakeRefCounted<StringIOBuffer>(kRequest1);
- TestCompletionCallback write_callback1;
- EXPECT_EQ(
- socket_.Write(write_buffer1.get(), strlen(kRequest1),
- write_callback1.callback(), TRAFFIC_ANNOTATION_FOR_TESTS),
- static_cast<int>(strlen(kRequest1)));
- EXPECT_GT(GetTaggedBytes(tag_val2), old_traffic);
- // Verify socket can be retagged with a new value and the current process's
- // UID.
- int32_t tag_val1 = 0x12345678;
- old_traffic = GetTaggedBytes(tag_val1);
- SocketTag tag1(SocketTag::UNSET_UID, tag_val1);
- socket_.ApplySocketTag(tag1);
- const char kRequest2[] = "\n\n";
- scoped_refptr<IOBuffer> write_buffer2 =
- base::MakeRefCounted<StringIOBuffer>(kRequest2);
- TestCompletionCallback write_callback2;
- EXPECT_EQ(
- socket_.Write(write_buffer2.get(), strlen(kRequest2),
- write_callback2.callback(), TRAFFIC_ANNOTATION_FOR_TESTS),
- static_cast<int>(strlen(kRequest2)));
- EXPECT_GT(GetTaggedBytes(tag_val1), old_traffic);
- socket_.Close();
- }
- TEST_F(TCPSocketTest, RecordRadioWakeUpTrigger) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(features::kRecordRadioWakeupTrigger);
- base::HistogramTester histograms;
- // Simulates the radio state is dormant.
- android::RadioActivityTracker::GetInstance().OverrideRadioActivityForTesting(
- base::android::RadioDataActivity::kDormant);
- android::RadioActivityTracker::GetInstance().OverrideRadioTypeForTesting(
- base::android::RadioConnectionType::kCell);
- ASSERT_NO_FATAL_FAILURE(SetUpListenIPv4());
- // Create a connected socket.
- TestCompletionCallback connect_callback;
- std::unique_ptr<TCPSocket> connecting_socket =
- std::make_unique<TCPSocket>(nullptr, nullptr, NetLogSource());
- int result = connecting_socket->Open(ADDRESS_FAMILY_IPV4);
- ASSERT_THAT(result, IsOk());
- int connect_result =
- connecting_socket->Connect(local_address_, connect_callback.callback());
- TestCompletionCallback accept_callback;
- std::unique_ptr<TCPSocket> accepted_socket;
- IPEndPoint accepted_address;
- result = socket_.Accept(&accepted_socket, &accepted_address,
- accept_callback.callback());
- ASSERT_THAT(accept_callback.GetResult(result), IsOk());
- ASSERT_TRUE(accepted_socket.get());
- ASSERT_THAT(connect_callback.GetResult(connect_result), IsOk());
- // Write to the socket once.
- base::RunLoop run_loop;
- scoped_refptr<IOBufferWithDestructionCallback> write_buffer(
- base::MakeRefCounted<IOBufferWithDestructionCallback>(
- run_loop.QuitClosure()));
- memset(write_buffer->data(), '1', write_buffer->size());
- TestCompletionCallback write_callback;
- result = connecting_socket->Write(write_buffer.get(), write_buffer->size(),
- write_callback.callback(),
- TRAFFIC_ANNOTATION_FOR_TESTS);
- ASSERT_LT(0, result);
- // Release the handle to the read buffer and destroy the socket. Make sure the
- // write buffer is destroyed.
- write_buffer = nullptr;
- connecting_socket.reset();
- run_loop.Run();
- // Check the write is recorded as a possible radio wake-up trigger.
- histograms.ExpectTotalCount(
- android::kUmaNamePossibleWakeupTriggerTCPWriteAnnotationId, 1);
- }
- TEST_F(TCPSocketTest, BindToNetwork) {
- NetworkChangeNotifierFactoryAndroid ncn_factory;
- NetworkChangeNotifier::DisableForTest ncn_disable_for_test;
- std::unique_ptr<NetworkChangeNotifier> ncn(ncn_factory.CreateInstance());
- if (!NetworkChangeNotifier::AreNetworkHandlesSupported())
- GTEST_SKIP() << "Network handles are required to test BindToNetwork.";
- const handles::NetworkHandle wrong_network_handle = 65536;
- // Try binding to this IP to trigger the underlying BindToNetwork call.
- const IPEndPoint ip(IPAddress::IPv4Localhost(), 0);
- // TestCompletionCallback connect_callback;
- TCPClientSocket connecting_socket(local_address_list(), nullptr, nullptr,
- nullptr, NetLogSource(),
- wrong_network_handle);
- // Different Android versions might report different errors. Hence, just check
- // what shouldn't happen.
- int rv = connecting_socket.Bind(ip);
- EXPECT_NE(OK, rv);
- EXPECT_NE(ERR_NOT_IMPLEMENTED, rv);
- // Connecting using an existing network should succeed.
- const handles::NetworkHandle network_handle =
- NetworkChangeNotifier::GetDefaultNetwork();
- if (network_handle != handles::kInvalidNetworkHandle) {
- TCPClientSocket connecting_socket(local_address_list(), nullptr, nullptr,
- nullptr, NetLogSource(),
- wrong_network_handle);
- EXPECT_EQ(OK, connecting_socket.Bind(ip));
- }
- }
- #endif // BUILDFLAG(IS_ANDROID)
- } // namespace
- } // namespace net
|