989 lines
38 KiB
C++
989 lines
38 KiB
C++
// Copyright 2013 The Chromium Authors
|
|
// 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/functional/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 "net/android/network_change_notifier_factory_android.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, 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 wrong_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 = wrong_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 correct_socket(local_address_list(), nullptr, nullptr,
|
|
nullptr, NetLogSource(), network_handle);
|
|
EXPECT_EQ(OK, correct_socket.Bind(ip));
|
|
}
|
|
}
|
|
|
|
#endif // BUILDFLAG(IS_ANDROID)
|
|
|
|
} // namespace
|
|
} // namespace net
|