| // Copyright (c) 2012 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 "ppapi/tests/test_tcp_server_socket_private.h" |
| |
| #include <cstdio> |
| #include <vector> |
| |
| #include "ppapi/cpp/pass_ref.h" |
| #include "ppapi/cpp/private/net_address_private.h" |
| #include "ppapi/cpp/private/tcp_server_socket_private.h" |
| #include "ppapi/cpp/private/tcp_socket_private.h" |
| #include "ppapi/tests/test_utils.h" |
| #include "ppapi/tests/testing_instance.h" |
| |
| using pp::NetAddressPrivate; |
| using pp::TCPServerSocketPrivate; |
| using pp::TCPSocketPrivate; |
| |
| REGISTER_TEST_CASE(TCPServerSocketPrivate); |
| |
| TestTCPServerSocketPrivate::TestTCPServerSocketPrivate( |
| TestingInstance* instance) : TestCase(instance) { |
| } |
| |
| bool TestTCPServerSocketPrivate::Init() { |
| bool tcp_server_socket_private_is_available = |
| TCPServerSocketPrivate::IsAvailable(); |
| if (!tcp_server_socket_private_is_available) { |
| instance_->AppendError( |
| "PPB_TCPServerSocket_Private interface not available"); |
| } |
| |
| bool tcp_socket_private_is_available = TCPSocketPrivate::IsAvailable(); |
| if (!tcp_socket_private_is_available) |
| instance_->AppendError("PPB_TCPSocket_Private interface not available"); |
| |
| bool net_address_private_is_available = NetAddressPrivate::IsAvailable(); |
| if (!net_address_private_is_available) |
| instance_->AppendError("PPB_NetAddress_Private interface not available"); |
| |
| bool init_host_port = GetLocalHostPort(instance_->pp_instance(), |
| &host_, &port_); |
| if (!init_host_port) |
| instance_->AppendError("Can't init host and port"); |
| |
| return tcp_server_socket_private_is_available && |
| tcp_socket_private_is_available && |
| net_address_private_is_available && |
| init_host_port && |
| CheckTestingInterface() && |
| EnsureRunningOverHTTP(); |
| } |
| |
| void TestTCPServerSocketPrivate::RunTests(const std::string& filter) { |
| RUN_CALLBACK_TEST(TestTCPServerSocketPrivate, Listen, filter); |
| RUN_CALLBACK_TEST(TestTCPServerSocketPrivate, Backlog, filter); |
| } |
| |
| std::string TestTCPServerSocketPrivate::GetLocalAddress( |
| PP_NetAddress_Private* address) { |
| TCPSocketPrivate socket(instance_); |
| TestCompletionCallback callback(instance_->pp_instance(), callback_type()); |
| callback.WaitForResult( |
| socket.Connect(host_.c_str(), port_, callback.GetCallback())); |
| CHECK_CALLBACK_BEHAVIOR(callback); |
| ASSERT_EQ(PP_OK, callback.result()); |
| ASSERT_TRUE(socket.GetLocalAddress(address)); |
| socket.Disconnect(); |
| PASS(); |
| } |
| |
| std::string TestTCPServerSocketPrivate::SyncRead(TCPSocketPrivate* socket, |
| char* buffer, |
| size_t num_bytes) { |
| while (num_bytes > 0) { |
| TestCompletionCallback callback(instance_->pp_instance(), callback_type()); |
| callback.WaitForResult( |
| socket->Read(buffer, static_cast<int32_t>(num_bytes), |
| callback.GetCallback())); |
| CHECK_CALLBACK_BEHAVIOR(callback); |
| ASSERT_TRUE(callback.result() >= 0); |
| buffer += callback.result(); |
| num_bytes -= callback.result(); |
| } |
| PASS(); |
| } |
| |
| std::string TestTCPServerSocketPrivate::SyncWrite(TCPSocketPrivate* socket, |
| const char* buffer, |
| size_t num_bytes) { |
| while (num_bytes > 0) { |
| TestCompletionCallback callback(instance_->pp_instance(), callback_type()); |
| callback.WaitForResult( |
| socket->Write(buffer, static_cast<int32_t>(num_bytes), |
| callback.GetCallback())); |
| CHECK_CALLBACK_BEHAVIOR(callback); |
| ASSERT_TRUE(callback.result() >= 0); |
| buffer += callback.result(); |
| num_bytes -= callback.result(); |
| } |
| PASS(); |
| } |
| |
| std::string TestTCPServerSocketPrivate::SyncConnect( |
| TCPSocketPrivate* socket, |
| PP_NetAddress_Private* address) { |
| TestCompletionCallback callback(instance_->pp_instance(), callback_type()); |
| callback.WaitForResult( |
| socket->ConnectWithNetAddress(address, callback.GetCallback())); |
| CHECK_CALLBACK_BEHAVIOR(callback); |
| ASSERT_EQ(PP_OK, callback.result()); |
| PASS(); |
| } |
| |
| void TestTCPServerSocketPrivate::ForceConnect(TCPSocketPrivate* socket, |
| PP_NetAddress_Private* address) { |
| std::string error_message; |
| do { |
| error_message = SyncConnect(socket, address); |
| } while (!error_message.empty()); |
| } |
| |
| std::string TestTCPServerSocketPrivate::SyncListen( |
| TCPServerSocketPrivate* socket, |
| PP_NetAddress_Private* address, |
| int32_t backlog) { |
| PP_NetAddress_Private base_address; |
| ASSERT_SUBTEST_SUCCESS(GetLocalAddress(&base_address)); |
| if (!NetAddressPrivate::ReplacePort(base_address, 0, address)) |
| return ReportError("PPB_NetAddress_Private::ReplacePort", 0); |
| TestCompletionCallback callback(instance_->pp_instance(), callback_type()); |
| callback.WaitForResult( |
| socket->Listen(address, backlog, callback.GetCallback())); |
| CHECK_CALLBACK_BEHAVIOR(callback); |
| ASSERT_EQ(PP_OK, callback.result()); |
| int32_t rv = socket->GetLocalAddress(address); |
| ASSERT_EQ(PP_OK, rv); |
| ASSERT_TRUE(NetAddressPrivate::GetPort(*address) != 0); |
| PASS(); |
| } |
| |
| std::string TestTCPServerSocketPrivate::TestListen() { |
| static const int kBacklog = 2; |
| |
| TCPServerSocketPrivate server_socket(instance_); |
| PP_NetAddress_Private address; |
| ASSERT_SUBTEST_SUCCESS(SyncListen(&server_socket, &address, kBacklog)); |
| |
| // We can't use a blocking callback for Accept, because it will wait forever |
| // for the client to connect, since the client connects after. |
| TestCompletionCallback accept_callback(instance_->pp_instance(), PP_REQUIRED); |
| // We need to make sure there's a message loop to run accept_callback on. |
| pp::MessageLoop current_thread_loop(pp::MessageLoop::GetCurrent()); |
| if (current_thread_loop.is_null() && testing_interface_->IsOutOfProcess()) { |
| current_thread_loop = pp::MessageLoop(instance_); |
| current_thread_loop.AttachToCurrentThread(); |
| } |
| |
| PP_Resource resource; |
| int32_t accept_rv = server_socket.Accept(&resource, |
| accept_callback.GetCallback()); |
| |
| TCPSocketPrivate client_socket(instance_); |
| ForceConnect(&client_socket, &address); |
| |
| PP_NetAddress_Private client_local_addr, client_remote_addr; |
| ASSERT_TRUE(client_socket.GetLocalAddress(&client_local_addr)); |
| ASSERT_TRUE(client_socket.GetRemoteAddress(&client_remote_addr)); |
| |
| accept_callback.WaitForResult(accept_rv); |
| CHECK_CALLBACK_BEHAVIOR(accept_callback); |
| ASSERT_EQ(PP_OK, accept_callback.result()); |
| |
| ASSERT_TRUE(resource != 0); |
| TCPSocketPrivate accepted_socket(pp::PassRef(), resource); |
| PP_NetAddress_Private accepted_local_addr, accepted_remote_addr; |
| ASSERT_TRUE(accepted_socket.GetLocalAddress(&accepted_local_addr)); |
| ASSERT_TRUE(accepted_socket.GetRemoteAddress(&accepted_remote_addr)); |
| ASSERT_TRUE(NetAddressPrivate::AreEqual(client_local_addr, |
| accepted_remote_addr)); |
| |
| const char kSentByte = 'a'; |
| ASSERT_SUBTEST_SUCCESS(SyncWrite(&client_socket, |
| &kSentByte, |
| sizeof(kSentByte))); |
| |
| char received_byte; |
| ASSERT_SUBTEST_SUCCESS(SyncRead(&accepted_socket, |
| &received_byte, |
| sizeof(received_byte))); |
| ASSERT_EQ(kSentByte, received_byte); |
| |
| accepted_socket.Disconnect(); |
| client_socket.Disconnect(); |
| server_socket.StopListening(); |
| |
| PASS(); |
| } |
| |
| std::string TestTCPServerSocketPrivate::TestBacklog() { |
| static const size_t kBacklog = 5; |
| |
| TCPServerSocketPrivate server_socket(instance_); |
| PP_NetAddress_Private address; |
| ASSERT_SUBTEST_SUCCESS(SyncListen(&server_socket, &address, 2 * kBacklog)); |
| |
| std::vector<TCPSocketPrivate*> client_sockets(kBacklog); |
| std::vector<TestCompletionCallback*> connect_callbacks(kBacklog); |
| std::vector<int32_t> connect_rv(kBacklog); |
| for (size_t i = 0; i < kBacklog; ++i) { |
| client_sockets[i] = new TCPSocketPrivate(instance_); |
| connect_callbacks[i] = new TestCompletionCallback(instance_->pp_instance(), |
| callback_type()); |
| connect_rv[i] = client_sockets[i]->ConnectWithNetAddress( |
| &address, |
| connect_callbacks[i]->GetCallback()); |
| } |
| |
| std::vector<PP_Resource> resources(kBacklog); |
| std::vector<TCPSocketPrivate*> accepted_sockets(kBacklog); |
| for (size_t i = 0; i < kBacklog; ++i) { |
| TestCompletionCallback callback(instance_->pp_instance(), callback_type()); |
| callback.WaitForResult( |
| server_socket.Accept(&resources[i], callback.GetCallback())); |
| CHECK_CALLBACK_BEHAVIOR(callback); |
| ASSERT_EQ(PP_OK, callback.result()); |
| |
| ASSERT_TRUE(resources[i] != 0); |
| accepted_sockets[i] = new TCPSocketPrivate(pp::PassRef(), resources[i]); |
| } |
| |
| for (size_t i = 0; i < kBacklog; ++i) { |
| connect_callbacks[i]->WaitForResult(connect_rv[i]); |
| CHECK_CALLBACK_BEHAVIOR(*connect_callbacks[i]); |
| ASSERT_EQ(PP_OK, connect_callbacks[i]->result()); |
| } |
| |
| for (size_t i = 0; i < kBacklog; ++i) { |
| const char byte = static_cast<char>('a' + i); |
| ASSERT_SUBTEST_SUCCESS(SyncWrite(client_sockets[i], &byte, sizeof(byte))); |
| } |
| |
| bool byte_received[kBacklog] = {}; |
| for (size_t i = 0; i < kBacklog; ++i) { |
| char byte; |
| ASSERT_SUBTEST_SUCCESS(SyncRead(accepted_sockets[i], &byte, sizeof(byte))); |
| const size_t index = byte - 'a'; |
| ASSERT_FALSE(byte_received[index]); |
| byte_received[index] = true; |
| } |
| |
| for (size_t i = 0; i < kBacklog; ++i) { |
| client_sockets[i]->Disconnect(); |
| delete client_sockets[i]; |
| delete connect_callbacks[i]; |
| accepted_sockets[i]->Disconnect(); |
| delete accepted_sockets[i]; |
| } |
| |
| server_socket.StopListening(); |
| PASS(); |
| } |