1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ppapi/tests/test_tcp_server_socket_private.h"
6
7#include <cstdio>
8#include <vector>
9
10#include "ppapi/cpp/pass_ref.h"
11#include "ppapi/cpp/private/net_address_private.h"
12#include "ppapi/cpp/private/tcp_server_socket_private.h"
13#include "ppapi/cpp/private/tcp_socket_private.h"
14#include "ppapi/tests/test_utils.h"
15#include "ppapi/tests/testing_instance.h"
16
17using pp::NetAddressPrivate;
18using pp::TCPServerSocketPrivate;
19using pp::TCPSocketPrivate;
20
21REGISTER_TEST_CASE(TCPServerSocketPrivate);
22
23TestTCPServerSocketPrivate::TestTCPServerSocketPrivate(
24    TestingInstance* instance) : TestCase(instance) {
25}
26
27bool TestTCPServerSocketPrivate::Init() {
28  bool tcp_server_socket_private_is_available =
29      TCPServerSocketPrivate::IsAvailable();
30  if (!tcp_server_socket_private_is_available) {
31    instance_->AppendError(
32        "PPB_TCPServerSocket_Private interface not available");
33  }
34
35  bool tcp_socket_private_is_available = TCPSocketPrivate::IsAvailable();
36  if (!tcp_socket_private_is_available)
37    instance_->AppendError("PPB_TCPSocket_Private interface not available");
38
39  bool net_address_private_is_available = NetAddressPrivate::IsAvailable();
40  if (!net_address_private_is_available)
41    instance_->AppendError("PPB_NetAddress_Private interface not available");
42
43  bool init_host_port = GetLocalHostPort(instance_->pp_instance(),
44                                         &host_, &port_);
45  if (!init_host_port)
46    instance_->AppendError("Can't init host and port");
47
48  return tcp_server_socket_private_is_available &&
49      tcp_socket_private_is_available &&
50      net_address_private_is_available &&
51      init_host_port &&
52      CheckTestingInterface() &&
53      EnsureRunningOverHTTP();
54}
55
56void TestTCPServerSocketPrivate::RunTests(const std::string& filter) {
57  RUN_CALLBACK_TEST(TestTCPServerSocketPrivate, Listen, filter);
58  RUN_CALLBACK_TEST(TestTCPServerSocketPrivate, Backlog, filter);
59}
60
61std::string TestTCPServerSocketPrivate::GetLocalAddress(
62    PP_NetAddress_Private* address) {
63  TCPSocketPrivate socket(instance_);
64  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
65  callback.WaitForResult(
66      socket.Connect(host_.c_str(), port_, callback.GetCallback()));
67  CHECK_CALLBACK_BEHAVIOR(callback);
68  ASSERT_EQ(PP_OK, callback.result());
69  ASSERT_TRUE(socket.GetLocalAddress(address));
70  socket.Disconnect();
71  PASS();
72}
73
74std::string TestTCPServerSocketPrivate::SyncRead(TCPSocketPrivate* socket,
75                                                 char* buffer,
76                                                 size_t num_bytes) {
77  while (num_bytes > 0) {
78    TestCompletionCallback callback(instance_->pp_instance(), callback_type());
79    callback.WaitForResult(
80        socket->Read(buffer, num_bytes, callback.GetCallback()));
81    CHECK_CALLBACK_BEHAVIOR(callback);
82    ASSERT_TRUE(callback.result() >= 0);
83    buffer += callback.result();
84    num_bytes -= callback.result();
85  }
86  PASS();
87}
88
89std::string TestTCPServerSocketPrivate::SyncWrite(TCPSocketPrivate* socket,
90                                                  const char* buffer,
91                                                  size_t num_bytes) {
92  while (num_bytes > 0) {
93    TestCompletionCallback callback(instance_->pp_instance(), callback_type());
94    callback.WaitForResult(
95        socket->Write(buffer, num_bytes, callback.GetCallback()));
96    CHECK_CALLBACK_BEHAVIOR(callback);
97    ASSERT_TRUE(callback.result() >= 0);
98    buffer += callback.result();
99    num_bytes -= callback.result();
100  }
101  PASS();
102}
103
104std::string TestTCPServerSocketPrivate::SyncConnect(
105    TCPSocketPrivate* socket,
106    PP_NetAddress_Private* address) {
107  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
108  callback.WaitForResult(
109      socket->ConnectWithNetAddress(address, callback.GetCallback()));
110  CHECK_CALLBACK_BEHAVIOR(callback);
111  ASSERT_EQ(PP_OK, callback.result());
112  PASS();
113}
114
115void TestTCPServerSocketPrivate::ForceConnect(TCPSocketPrivate* socket,
116                                              PP_NetAddress_Private* address) {
117  std::string error_message;
118  do {
119    error_message = SyncConnect(socket, address);
120  } while (!error_message.empty());
121}
122
123std::string TestTCPServerSocketPrivate::SyncListen(
124    TCPServerSocketPrivate* socket,
125    PP_NetAddress_Private* address,
126    int32_t backlog) {
127  PP_NetAddress_Private base_address;
128  ASSERT_SUBTEST_SUCCESS(GetLocalAddress(&base_address));
129  if (!NetAddressPrivate::ReplacePort(base_address, 0, address))
130    return ReportError("PPB_NetAddress_Private::ReplacePort", 0);
131  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
132  callback.WaitForResult(
133      socket->Listen(address, backlog, callback.GetCallback()));
134  CHECK_CALLBACK_BEHAVIOR(callback);
135  ASSERT_EQ(PP_OK, callback.result());
136  int32_t rv = socket->GetLocalAddress(address);
137  ASSERT_EQ(PP_OK, rv);
138  ASSERT_TRUE(NetAddressPrivate::GetPort(*address) != 0);
139  PASS();
140}
141
142std::string TestTCPServerSocketPrivate::TestListen() {
143  static const int kBacklog = 2;
144
145  TCPServerSocketPrivate server_socket(instance_);
146  PP_NetAddress_Private address;
147  ASSERT_SUBTEST_SUCCESS(SyncListen(&server_socket, &address, kBacklog));
148
149  // We can't use a blocking callback for Accept, because it will wait forever
150  // for the client to connect, since the client connects after.
151  TestCompletionCallback accept_callback(instance_->pp_instance(), PP_REQUIRED);
152  // We need to make sure there's a message loop to run accept_callback on.
153  pp::MessageLoop current_thread_loop(pp::MessageLoop::GetCurrent());
154  if (current_thread_loop.is_null() && testing_interface_->IsOutOfProcess()) {
155    current_thread_loop = pp::MessageLoop(instance_);
156    current_thread_loop.AttachToCurrentThread();
157  }
158
159  PP_Resource resource;
160  int32_t accept_rv = server_socket.Accept(&resource,
161                                           accept_callback.GetCallback());
162
163  TCPSocketPrivate client_socket(instance_);
164  ForceConnect(&client_socket, &address);
165
166  PP_NetAddress_Private client_local_addr, client_remote_addr;
167  ASSERT_TRUE(client_socket.GetLocalAddress(&client_local_addr));
168  ASSERT_TRUE(client_socket.GetRemoteAddress(&client_remote_addr));
169
170  accept_callback.WaitForResult(accept_rv);
171  CHECK_CALLBACK_BEHAVIOR(accept_callback);
172  ASSERT_EQ(PP_OK, accept_callback.result());
173
174  ASSERT_TRUE(resource != 0);
175  TCPSocketPrivate accepted_socket(pp::PassRef(), resource);
176  PP_NetAddress_Private accepted_local_addr, accepted_remote_addr;
177  ASSERT_TRUE(accepted_socket.GetLocalAddress(&accepted_local_addr));
178  ASSERT_TRUE(accepted_socket.GetRemoteAddress(&accepted_remote_addr));
179  ASSERT_TRUE(NetAddressPrivate::AreEqual(client_local_addr,
180                                          accepted_remote_addr));
181
182  const char kSentByte = 'a';
183  ASSERT_SUBTEST_SUCCESS(SyncWrite(&client_socket,
184                                   &kSentByte,
185                                   sizeof(kSentByte)));
186
187  char received_byte;
188  ASSERT_SUBTEST_SUCCESS(SyncRead(&accepted_socket,
189                                  &received_byte,
190                                  sizeof(received_byte)));
191  ASSERT_EQ(kSentByte, received_byte);
192
193  accepted_socket.Disconnect();
194  client_socket.Disconnect();
195  server_socket.StopListening();
196
197  PASS();
198}
199
200std::string TestTCPServerSocketPrivate::TestBacklog() {
201  static const size_t kBacklog = 5;
202
203  TCPServerSocketPrivate server_socket(instance_);
204  PP_NetAddress_Private address;
205  ASSERT_SUBTEST_SUCCESS(SyncListen(&server_socket, &address, 2 * kBacklog));
206
207  std::vector<TCPSocketPrivate*> client_sockets(kBacklog);
208  std::vector<TestCompletionCallback*> connect_callbacks(kBacklog);
209  std::vector<int32_t> connect_rv(kBacklog);
210  for (size_t i = 0; i < kBacklog; ++i) {
211    client_sockets[i] = new TCPSocketPrivate(instance_);
212    connect_callbacks[i] = new TestCompletionCallback(instance_->pp_instance(),
213                                                      callback_type());
214    connect_rv[i] = client_sockets[i]->ConnectWithNetAddress(
215        &address,
216        connect_callbacks[i]->GetCallback());
217  }
218
219  std::vector<PP_Resource> resources(kBacklog);
220  std::vector<TCPSocketPrivate*> accepted_sockets(kBacklog);
221  for (size_t i = 0; i < kBacklog; ++i) {
222    TestCompletionCallback callback(instance_->pp_instance(), callback_type());
223    callback.WaitForResult(
224        server_socket.Accept(&resources[i], callback.GetCallback()));
225    CHECK_CALLBACK_BEHAVIOR(callback);
226    ASSERT_EQ(PP_OK, callback.result());
227
228    ASSERT_TRUE(resources[i] != 0);
229    accepted_sockets[i] = new TCPSocketPrivate(pp::PassRef(), resources[i]);
230  }
231
232  for (size_t i = 0; i < kBacklog; ++i) {
233    connect_callbacks[i]->WaitForResult(connect_rv[i]);
234    CHECK_CALLBACK_BEHAVIOR(*connect_callbacks[i]);
235    ASSERT_EQ(PP_OK, connect_callbacks[i]->result());
236  }
237
238  for (size_t i = 0; i < kBacklog; ++i) {
239    const char byte = 'a' + i;
240    ASSERT_SUBTEST_SUCCESS(SyncWrite(client_sockets[i], &byte, sizeof(byte)));
241  }
242
243  bool byte_received[kBacklog] = {};
244  for (size_t i = 0; i < kBacklog; ++i) {
245    char byte;
246    ASSERT_SUBTEST_SUCCESS(SyncRead(accepted_sockets[i], &byte, sizeof(byte)));
247    const size_t index = byte - 'a';
248    ASSERT_FALSE(byte_received[index]);
249    byte_received[index] = true;
250  }
251
252  for (size_t i = 0; i < kBacklog; ++i) {
253    client_sockets[i]->Disconnect();
254    delete client_sockets[i];
255    delete connect_callbacks[i];
256    accepted_sockets[i]->Disconnect();
257    delete accepted_sockets[i];
258  }
259
260  server_socket.StopListening();
261  PASS();
262}
263