blob: 930e0656f6503877cb9018ca69f21f461623162a [file] [log] [blame]
// Copyright 2017 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/test/tcp_socket_proxy.h"
#include "base/message_loop/message_loop.h"
#include "base/threading/thread.h"
#include "build/build_config.h"
#include "net/base/io_buffer.h"
#include "net/base/test_completion_callback.h"
#include "net/socket/tcp_client_socket.h"
#include "net/socket/tcp_server_socket.h"
#include "net/test/gtest_util.h"
#include "net/test/test_with_scoped_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"
using net::test::IsOk;
namespace net {
class TcpSocketProxyTest : public TestWithScopedTaskEnvironment {
public:
TcpSocketProxyTest() : io_thread_("TcpSocketProxyTest IO Thread") {
EXPECT_TRUE(io_thread_.StartWithOptions(
base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
listen_socket_ =
std::make_unique<TCPServerSocket>(nullptr, net::NetLogSource());
int result =
listen_socket_->Listen(IPEndPoint(IPAddress::IPv4Localhost(), 0), 5);
EXPECT_THAT(result, IsOk());
// Get local address.
IPEndPoint address;
result = listen_socket_->GetLocalAddress(&address);
EXPECT_THAT(result, IsOk());
proxy_ = std::make_unique<TcpSocketProxy>(io_thread_.task_runner());
EXPECT_TRUE(proxy_->Initialize());
proxy_address_ =
IPEndPoint(IPAddress::IPv4Localhost(), proxy_->local_port());
proxy_->Start(address);
}
void MakeConnection(std::unique_ptr<StreamSocket>* client_socket,
std::unique_ptr<StreamSocket>* server_socket) {
TestCompletionCallback connect_callback;
*client_socket = std::make_unique<TCPClientSocket>(
AddressList(proxy_address_), nullptr, nullptr, NetLogSource());
int connect_result = (*client_socket)->Connect(connect_callback.callback());
TestCompletionCallback accept_callback;
int result =
listen_socket_->Accept(server_socket, accept_callback.callback());
ASSERT_THAT(connect_callback.GetResult(connect_result), IsOk());
ASSERT_THAT(accept_callback.GetResult(result), IsOk());
EXPECT_TRUE((*server_socket)->IsConnected());
EXPECT_TRUE((*client_socket)->IsConnected());
}
void SendAndReceiveData(StreamSocket* socket1, StreamSocket* socket2) {
// Send just one byte to ensure we will need only one Write() and only one
// Read().
char test_message = '0';
scoped_refptr<IOBuffer> write_buffer = base::MakeRefCounted<IOBuffer>(1);
*write_buffer->data() = test_message;
TestCompletionCallback write_callback;
int write_result =
socket1->Write(write_buffer.get(), 1, write_callback.callback(),
TRAFFIC_ANNOTATION_FOR_TESTS);
scoped_refptr<IOBufferWithSize> read_buffer =
base::MakeRefCounted<IOBufferWithSize>(1024);
TestCompletionCallback read_callback;
int read_result = socket2->Read(read_buffer.get(), read_buffer->size(),
read_callback.callback());
ASSERT_EQ(write_callback.GetResult(write_result), 1);
ASSERT_EQ(read_callback.GetResult(read_result), 1);
EXPECT_EQ(test_message, *read_buffer->data());
}
void ExpectClosed(StreamSocket* socket) {
scoped_refptr<IOBufferWithSize> read_buffer =
base::MakeRefCounted<IOBufferWithSize>(1024);
TestCompletionCallback read_callback;
int read_result = socket->Read(read_buffer.get(), read_buffer->size(),
read_callback.callback());
EXPECT_EQ(read_callback.GetResult(read_result), 0);
EXPECT_FALSE(socket->IsConnected());
}
protected:
base::Thread io_thread_;
// Server socket that simulates testserver that TcpSocketProxy normally
// would connect to.
std::unique_ptr<TCPServerSocket> listen_socket_;
std::unique_ptr<TcpSocketProxy> proxy_;
private:
IPEndPoint proxy_address_;
};
TEST_F(TcpSocketProxyTest, SendAndReceive) {
std::unique_ptr<StreamSocket> client_socket;
std::unique_ptr<StreamSocket> server_socket;
MakeConnection(&client_socket, &server_socket);
SendAndReceiveData(client_socket.get(), server_socket.get());
SendAndReceiveData(server_socket.get(), client_socket.get());
}
TEST_F(TcpSocketProxyTest, TwoConnections) {
std::unique_ptr<StreamSocket> client_socket1;
std::unique_ptr<StreamSocket> server_socket1;
MakeConnection(&client_socket1, &server_socket1);
std::unique_ptr<StreamSocket> client_socket2;
std::unique_ptr<StreamSocket> server_socket2;
MakeConnection(&client_socket2, &server_socket2);
SendAndReceiveData(client_socket1.get(), server_socket1.get());
SendAndReceiveData(client_socket2.get(), server_socket2.get());
SendAndReceiveData(server_socket1.get(), client_socket1.get());
SendAndReceiveData(server_socket2.get(), client_socket2.get());
}
// Close socket on the server side and verify that it's closed on the client
// side.
// TODO(crbug.com/804429): This test hangs occasionally on iOS.
#if defined(OS_IOS)
#define MAYBE_DisconnectServer DISABLED_DisconnectServer
#else
#define MAYBE_DisconnectServer DisconnectServer
#endif
TEST_F(TcpSocketProxyTest, MAYBE_DisconnectServer) {
std::unique_ptr<StreamSocket> client_socket;
std::unique_ptr<StreamSocket> server_socket;
MakeConnection(&client_socket, &server_socket);
server_socket.reset();
ExpectClosed(client_socket.get());
}
// Close socket on the client side and verify that it's closed on the server
// side.
// TODO(crbug.com/804429): This test hangs occasionally on iOS.
#if defined(OS_IOS)
#define MAYBE_DisconnectClient DISABLED_DisconnectClient
#else
#define MAYBE_DisconnectClient DisconnectClient
#endif
TEST_F(TcpSocketProxyTest, MAYBE_DisconnectClient) {
std::unique_ptr<StreamSocket> client_socket;
std::unique_ptr<StreamSocket> server_socket;
MakeConnection(&client_socket, &server_socket);
client_socket.reset();
ExpectClosed(server_socket.get());
}
// Starboard does not explicitly disable listening on the same port and win32
// actually does allow two sockets used by the same application to listen on
// the same port under some circumstances even though expected behavior in
// documentation is "undetermined".
#ifndef STARBOARD
// Initialize() must fail if the port is in use.
TEST_F(TcpSocketProxyTest, PortInUse) {
// Try initializing second proxy on the same port.
auto proxy2 = std::make_unique<TcpSocketProxy>(io_thread_.task_runner());
EXPECT_FALSE(proxy2->Initialize(proxy_->local_port()));
}
#endif
} // namespace net