Home | History | Annotate | Download | only in tests
      1 // Copyright 2013 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_socket.h"
      6 
      7 #include <vector>
      8 
      9 #include "ppapi/cpp/message_loop.h"
     10 #include "ppapi/cpp/tcp_socket.h"
     11 #include "ppapi/tests/test_utils.h"
     12 #include "ppapi/tests/testing_instance.h"
     13 
     14 namespace {
     15 
     16 // Validates the first line of an HTTP response.
     17 bool ValidateHttpResponse(const std::string& s) {
     18   // Just check that it begins with "HTTP/" and ends with a "\r\n".
     19   return s.size() >= 5 &&
     20          s.substr(0, 5) == "HTTP/" &&
     21          s.substr(s.size() - 2) == "\r\n";
     22 }
     23 
     24 }  // namespace
     25 
     26 REGISTER_TEST_CASE(TCPSocket);
     27 
     28 TestTCPSocket::TestTCPSocket(TestingInstance* instance)
     29     : TestCase(instance),
     30       socket_interface_1_0_(NULL) {
     31 }
     32 
     33 bool TestTCPSocket::Init() {
     34   if (!pp::TCPSocket::IsAvailable())
     35     return false;
     36   socket_interface_1_0_ =
     37       static_cast<const PPB_TCPSocket_1_0*>(
     38           pp::Module::Get()->GetBrowserInterface(PPB_TCPSOCKET_INTERFACE_1_0));
     39   if (!socket_interface_1_0_)
     40     return false;
     41 
     42   // We need something to connect to, so we connect to the HTTP server whence we
     43   // came. Grab the host and port.
     44   if (!EnsureRunningOverHTTP())
     45     return false;
     46 
     47   std::string host;
     48   uint16_t port = 0;
     49   if (!GetLocalHostPort(instance_->pp_instance(), &host, &port))
     50     return false;
     51 
     52   if (!ResolveHost(instance_->pp_instance(), host, port, &addr_))
     53     return false;
     54 
     55   return true;
     56 }
     57 
     58 void TestTCPSocket::RunTests(const std::string& filter) {
     59   RUN_CALLBACK_TEST(TestTCPSocket, Connect, filter);
     60   RUN_CALLBACK_TEST(TestTCPSocket, ReadWrite, filter);
     61   RUN_CALLBACK_TEST(TestTCPSocket, SetOption, filter);
     62   RUN_CALLBACK_TEST(TestTCPSocket, Listen, filter);
     63   RUN_CALLBACK_TEST(TestTCPSocket, Backlog, filter);
     64   RUN_CALLBACK_TEST(TestTCPSocket, Interface_1_0, filter);
     65 }
     66 
     67 std::string TestTCPSocket::TestConnect() {
     68   {
     69     // The basic case.
     70     pp::TCPSocket socket(instance_);
     71     TestCompletionCallback cb(instance_->pp_instance(), callback_type());
     72 
     73     cb.WaitForResult(socket.Connect(addr_, cb.GetCallback()));
     74     CHECK_CALLBACK_BEHAVIOR(cb);
     75     ASSERT_EQ(PP_OK, cb.result());
     76 
     77     pp::NetAddress local_addr, remote_addr;
     78     local_addr = socket.GetLocalAddress();
     79     remote_addr = socket.GetRemoteAddress();
     80 
     81     ASSERT_NE(0, local_addr.pp_resource());
     82     ASSERT_NE(0, remote_addr.pp_resource());
     83     ASSERT_TRUE(EqualNetAddress(addr_, remote_addr));
     84 
     85     socket.Close();
     86   }
     87 
     88   {
     89     // Connect a bound socket.
     90     pp::TCPSocket socket(instance_);
     91     TestCompletionCallback cb(instance_->pp_instance(), callback_type());
     92 
     93     pp::NetAddress any_port_address;
     94     ASSERT_SUBTEST_SUCCESS(GetAddressToBind(&any_port_address));
     95 
     96     cb.WaitForResult(socket.Bind(any_port_address, cb.GetCallback()));
     97     CHECK_CALLBACK_BEHAVIOR(cb);
     98     ASSERT_EQ(PP_OK, cb.result());
     99 
    100     cb.WaitForResult(socket.Connect(addr_, cb.GetCallback()));
    101     CHECK_CALLBACK_BEHAVIOR(cb);
    102     ASSERT_EQ(PP_OK, cb.result());
    103 
    104     pp::NetAddress local_addr, remote_addr;
    105     local_addr = socket.GetLocalAddress();
    106     remote_addr = socket.GetRemoteAddress();
    107 
    108     ASSERT_NE(0, local_addr.pp_resource());
    109     ASSERT_NE(0, remote_addr.pp_resource());
    110     ASSERT_TRUE(EqualNetAddress(addr_, remote_addr));
    111     ASSERT_NE(0u, GetPort(local_addr));
    112 
    113     socket.Close();
    114   }
    115 
    116   PASS();
    117 }
    118 
    119 std::string TestTCPSocket::TestReadWrite() {
    120   pp::TCPSocket socket(instance_);
    121   TestCompletionCallback cb(instance_->pp_instance(), callback_type());
    122 
    123   cb.WaitForResult(socket.Connect(addr_, cb.GetCallback()));
    124   CHECK_CALLBACK_BEHAVIOR(cb);
    125   ASSERT_EQ(PP_OK, cb.result());
    126 
    127   ASSERT_SUBTEST_SUCCESS(WriteToSocket(&socket, "GET / HTTP/1.0\r\n\r\n"));
    128 
    129   // Read up to the first \n and check that it looks like valid HTTP response.
    130   std::string s;
    131   ASSERT_SUBTEST_SUCCESS(ReadFirstLineFromSocket(&socket, &s));
    132   ASSERT_TRUE(ValidateHttpResponse(s));
    133 
    134   PASS();
    135 }
    136 
    137 std::string TestTCPSocket::TestSetOption() {
    138   pp::TCPSocket socket(instance_);
    139   TestCompletionCallback cb_1(instance_->pp_instance(), callback_type());
    140   TestCompletionCallback cb_2(instance_->pp_instance(), callback_type());
    141   TestCompletionCallback cb_3(instance_->pp_instance(), callback_type());
    142 
    143   // These options cannot be set before the socket is connected.
    144   int32_t result_1 = socket.SetOption(PP_TCPSOCKET_OPTION_NO_DELAY,
    145                                       true, cb_1.GetCallback());
    146   int32_t result_2 = socket.SetOption(PP_TCPSOCKET_OPTION_SEND_BUFFER_SIZE,
    147                                       256, cb_2.GetCallback());
    148   int32_t result_3 = socket.SetOption(PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE,
    149                                       512, cb_3.GetCallback());
    150 
    151   cb_1.WaitForResult(result_1);
    152   CHECK_CALLBACK_BEHAVIOR(cb_1);
    153   ASSERT_EQ(PP_ERROR_FAILED, cb_1.result());
    154 
    155   cb_2.WaitForResult(result_2);
    156   CHECK_CALLBACK_BEHAVIOR(cb_2);
    157   ASSERT_EQ(PP_ERROR_FAILED, cb_2.result());
    158 
    159   cb_3.WaitForResult(result_3);
    160   CHECK_CALLBACK_BEHAVIOR(cb_3);
    161   ASSERT_EQ(PP_ERROR_FAILED, cb_3.result());
    162 
    163   cb_1.WaitForResult(socket.Connect(addr_, cb_1.GetCallback()));
    164   CHECK_CALLBACK_BEHAVIOR(cb_1);
    165   ASSERT_EQ(PP_OK, cb_1.result());
    166 
    167   result_1 = socket.SetOption(PP_TCPSOCKET_OPTION_NO_DELAY,
    168                               false, cb_1.GetCallback());
    169   result_2 = socket.SetOption(PP_TCPSOCKET_OPTION_SEND_BUFFER_SIZE,
    170                               512, cb_2.GetCallback());
    171   result_3 = socket.SetOption(PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE,
    172                               1024, cb_3.GetCallback());
    173 
    174   cb_1.WaitForResult(result_1);
    175   CHECK_CALLBACK_BEHAVIOR(cb_1);
    176   ASSERT_EQ(PP_OK, cb_1.result());
    177 
    178   cb_2.WaitForResult(result_2);
    179   CHECK_CALLBACK_BEHAVIOR(cb_2);
    180   ASSERT_EQ(PP_OK, cb_2.result());
    181 
    182   cb_3.WaitForResult(result_3);
    183   CHECK_CALLBACK_BEHAVIOR(cb_3);
    184   ASSERT_EQ(PP_OK, cb_3.result());
    185 
    186   PASS();
    187 }
    188 
    189 std::string TestTCPSocket::TestListen() {
    190   static const int kBacklog = 2;
    191 
    192   pp::TCPSocket server_socket(instance_);
    193   ASSERT_SUBTEST_SUCCESS(StartListen(&server_socket, kBacklog));
    194 
    195   // We can't use a blocking callback for Accept, because it will wait forever
    196   // for the client to connect, since the client connects after.
    197   TestCompletionCallbackWithOutput<pp::TCPSocket>
    198       accept_callback(instance_->pp_instance(), PP_REQUIRED);
    199   // We need to make sure there's a message loop to run accept_callback on.
    200   pp::MessageLoop current_thread_loop(pp::MessageLoop::GetCurrent());
    201   if (current_thread_loop.is_null() && testing_interface_->IsOutOfProcess()) {
    202     current_thread_loop = pp::MessageLoop(instance_);
    203     current_thread_loop.AttachToCurrentThread();
    204   }
    205 
    206   int32_t accept_rv = server_socket.Accept(accept_callback.GetCallback());
    207 
    208   pp::TCPSocket client_socket;
    209   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
    210   do {
    211     client_socket = pp::TCPSocket(instance_);
    212 
    213     callback.WaitForResult(client_socket.Connect(
    214         server_socket.GetLocalAddress(), callback.GetCallback()));
    215   } while (callback.result() != PP_OK);
    216 
    217   pp::NetAddress client_local_addr = client_socket.GetLocalAddress();
    218   pp::NetAddress client_remote_addr = client_socket.GetRemoteAddress();
    219   ASSERT_FALSE(client_local_addr.is_null());
    220   ASSERT_FALSE(client_remote_addr.is_null());
    221 
    222   accept_callback.WaitForResult(accept_rv);
    223   CHECK_CALLBACK_BEHAVIOR(accept_callback);
    224   ASSERT_EQ(PP_OK, accept_callback.result());
    225 
    226   pp::TCPSocket accepted_socket(accept_callback.output());
    227   pp::NetAddress accepted_local_addr = accepted_socket.GetLocalAddress();
    228   pp::NetAddress accepted_remote_addr = accepted_socket.GetRemoteAddress();
    229   ASSERT_FALSE(accepted_local_addr.is_null());
    230   ASSERT_FALSE(accepted_remote_addr.is_null());
    231 
    232   ASSERT_TRUE(EqualNetAddress(client_local_addr, accepted_remote_addr));
    233 
    234   const char kSentByte = 'a';
    235   ASSERT_SUBTEST_SUCCESS(WriteToSocket(&client_socket,
    236                                        std::string(1, kSentByte)));
    237 
    238   char received_byte;
    239   ASSERT_SUBTEST_SUCCESS(ReadFromSocket(&accepted_socket,
    240                                         &received_byte,
    241                                         sizeof(received_byte)));
    242   ASSERT_EQ(kSentByte, received_byte);
    243 
    244   accepted_socket.Close();
    245   client_socket.Close();
    246   server_socket.Close();
    247 
    248   PASS();
    249 }
    250 
    251 std::string TestTCPSocket::TestBacklog() {
    252   static const size_t kBacklog = 5;
    253 
    254   pp::TCPSocket server_socket(instance_);
    255   ASSERT_SUBTEST_SUCCESS(StartListen(&server_socket, 2 * kBacklog));
    256 
    257   std::vector<pp::TCPSocket*> client_sockets(kBacklog);
    258   std::vector<TestCompletionCallback*> connect_callbacks(kBacklog);
    259   std::vector<int32_t> connect_rv(kBacklog);
    260   pp::NetAddress address = server_socket.GetLocalAddress();
    261   for (size_t i = 0; i < kBacklog; ++i) {
    262     client_sockets[i] = new pp::TCPSocket(instance_);
    263     connect_callbacks[i] = new TestCompletionCallback(instance_->pp_instance(),
    264                                                       callback_type());
    265     connect_rv[i] = client_sockets[i]->Connect(
    266         address, connect_callbacks[i]->GetCallback());
    267   }
    268 
    269   std::vector<pp::TCPSocket*> accepted_sockets(kBacklog);
    270   for (size_t i = 0; i < kBacklog; ++i) {
    271     TestCompletionCallbackWithOutput<pp::TCPSocket> callback(
    272         instance_->pp_instance(), callback_type());
    273     callback.WaitForResult(server_socket.Accept(callback.GetCallback()));
    274     CHECK_CALLBACK_BEHAVIOR(callback);
    275     ASSERT_EQ(PP_OK, callback.result());
    276 
    277     accepted_sockets[i] = new pp::TCPSocket(callback.output());
    278     ASSERT_FALSE(accepted_sockets[i]->is_null());
    279   }
    280 
    281   for (size_t i = 0; i < kBacklog; ++i) {
    282     connect_callbacks[i]->WaitForResult(connect_rv[i]);
    283     CHECK_CALLBACK_BEHAVIOR(*connect_callbacks[i]);
    284     ASSERT_EQ(PP_OK, connect_callbacks[i]->result());
    285   }
    286 
    287   for (size_t i = 0; i < kBacklog; ++i) {
    288     const char byte = 'a' + i;
    289     ASSERT_SUBTEST_SUCCESS(WriteToSocket(client_sockets[i],
    290                                          std::string(1, byte)));
    291   }
    292 
    293   bool byte_received[kBacklog] = {};
    294   for (size_t i = 0; i < kBacklog; ++i) {
    295     char byte;
    296     ASSERT_SUBTEST_SUCCESS(ReadFromSocket(
    297         accepted_sockets[i], &byte, sizeof(byte)));
    298     const size_t index = byte - 'a';
    299     ASSERT_GE(index, 0u);
    300     ASSERT_LT(index, kBacklog);
    301     ASSERT_FALSE(byte_received[index]);
    302     byte_received[index] = true;
    303   }
    304 
    305   for (size_t i = 0; i < kBacklog; ++i) {
    306     ASSERT_TRUE(byte_received[i]);
    307 
    308     delete client_sockets[i];
    309     delete connect_callbacks[i];
    310     delete accepted_sockets[i];
    311   }
    312 
    313   PASS();
    314 }
    315 
    316 std::string TestTCPSocket::TestInterface_1_0() {
    317   PP_Resource socket = socket_interface_1_0_->Create(instance_->pp_instance());
    318   ASSERT_NE(0, socket);
    319 
    320   TestCompletionCallback cb(instance_->pp_instance(), callback_type());
    321   cb.WaitForResult(socket_interface_1_0_->Connect(
    322       socket, addr_.pp_resource(), cb.GetCallback().pp_completion_callback()));
    323   CHECK_CALLBACK_BEHAVIOR(cb);
    324   ASSERT_EQ(PP_OK, cb.result());
    325 
    326   ASSERT_SUBTEST_SUCCESS(WriteToSocket_1_0(socket, "GET / HTTP/1.0\r\n\r\n"));
    327 
    328   // Read up to the first \n and check that it looks like valid HTTP response.
    329   std::string s;
    330   ASSERT_SUBTEST_SUCCESS(ReadFirstLineFromSocket_1_0(socket, &s));
    331   ASSERT_TRUE(ValidateHttpResponse(s));
    332 
    333   pp::Module::Get()->core()->ReleaseResource(socket);
    334   PASS();
    335 }
    336 
    337 std::string TestTCPSocket::ReadFirstLineFromSocket(pp::TCPSocket* socket,
    338                                                    std::string* s) {
    339   char buffer[1000];
    340 
    341   s->clear();
    342   // Make sure we don't just hang if |Read()| spews.
    343   while (s->size() < 10000) {
    344     TestCompletionCallback cb(instance_->pp_instance(), callback_type());
    345     cb.WaitForResult(socket->Read(buffer, sizeof(buffer), cb.GetCallback()));
    346     CHECK_CALLBACK_BEHAVIOR(cb);
    347     ASSERT_GT(cb.result(), 0);
    348     s->reserve(s->size() + cb.result());
    349     for (int32_t i = 0; i < cb.result(); ++i) {
    350       s->push_back(buffer[i]);
    351       if (buffer[i] == '\n')
    352         PASS();
    353     }
    354   }
    355   PASS();
    356 }
    357 
    358 std::string TestTCPSocket::ReadFirstLineFromSocket_1_0(PP_Resource socket,
    359                                                        std::string* s) {
    360   char buffer[1000];
    361 
    362   s->clear();
    363   // Make sure we don't just hang if |Read()| spews.
    364   while (s->size() < 10000) {
    365     TestCompletionCallback cb(instance_->pp_instance(), callback_type());
    366     cb.WaitForResult(socket_interface_1_0_->Read(
    367         socket, buffer, sizeof(buffer),
    368         cb.GetCallback().pp_completion_callback()));
    369     CHECK_CALLBACK_BEHAVIOR(cb);
    370     ASSERT_GT(cb.result(), 0);
    371     s->reserve(s->size() + cb.result());
    372     for (int32_t i = 0; i < cb.result(); ++i) {
    373       s->push_back(buffer[i]);
    374       if (buffer[i] == '\n')
    375         PASS();
    376     }
    377   }
    378   PASS();
    379 }
    380 
    381 std::string TestTCPSocket::ReadFromSocket(pp::TCPSocket* socket,
    382                                           char* buffer,
    383                                           size_t num_bytes) {
    384   while (num_bytes > 0) {
    385     TestCompletionCallback callback(instance_->pp_instance(), callback_type());
    386     callback.WaitForResult(
    387         socket->Read(buffer, num_bytes, callback.GetCallback()));
    388     CHECK_CALLBACK_BEHAVIOR(callback);
    389     ASSERT_GT(callback.result(), 0);
    390     buffer += callback.result();
    391     num_bytes -= callback.result();
    392   }
    393   ASSERT_EQ(0u, num_bytes);
    394   PASS();
    395 }
    396 
    397 std::string TestTCPSocket::WriteToSocket(pp::TCPSocket* socket,
    398                                          const std::string& s) {
    399   const char* buffer = s.data();
    400   size_t written = 0;
    401   while (written < s.size()) {
    402     TestCompletionCallback cb(instance_->pp_instance(), callback_type());
    403     cb.WaitForResult(
    404         socket->Write(buffer + written, s.size() - written, cb.GetCallback()));
    405     CHECK_CALLBACK_BEHAVIOR(cb);
    406     ASSERT_GT(cb.result(), 0);
    407     written += cb.result();
    408   }
    409   ASSERT_EQ(written, s.size());
    410   PASS();
    411 }
    412 
    413 std::string TestTCPSocket::WriteToSocket_1_0(
    414     PP_Resource socket,
    415     const std::string& s) {
    416   const char* buffer = s.data();
    417   size_t written = 0;
    418   while (written < s.size()) {
    419     TestCompletionCallback cb(instance_->pp_instance(), callback_type());
    420     cb.WaitForResult(socket_interface_1_0_->Write(
    421         socket, buffer + written, s.size() - written,
    422         cb.GetCallback().pp_completion_callback()));
    423     CHECK_CALLBACK_BEHAVIOR(cb);
    424     ASSERT_GT(cb.result(), 0);
    425     written += cb.result();
    426   }
    427   ASSERT_EQ(written, s.size());
    428   PASS();
    429 }
    430 
    431 std::string TestTCPSocket::GetAddressToBind(pp::NetAddress* address) {
    432   pp::TCPSocket socket(instance_);
    433   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
    434   callback.WaitForResult(socket.Connect(addr_, callback.GetCallback()));
    435   CHECK_CALLBACK_BEHAVIOR(callback);
    436   ASSERT_EQ(PP_OK, callback.result());
    437 
    438   ASSERT_TRUE(ReplacePort(instance_->pp_instance(), socket.GetLocalAddress(), 0,
    439                           address));
    440   ASSERT_FALSE(address->is_null());
    441   PASS();
    442 }
    443 
    444 std::string TestTCPSocket::StartListen(pp::TCPSocket* socket, int32_t backlog) {
    445   pp::NetAddress any_port_address;
    446   ASSERT_SUBTEST_SUCCESS(GetAddressToBind(&any_port_address));
    447 
    448   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
    449   callback.WaitForResult(
    450       socket->Bind(any_port_address, callback.GetCallback()));
    451   CHECK_CALLBACK_BEHAVIOR(callback);
    452   ASSERT_EQ(PP_OK, callback.result());
    453 
    454   callback.WaitForResult(
    455       socket->Listen(backlog, callback.GetCallback()));
    456   CHECK_CALLBACK_BEHAVIOR(callback);
    457   ASSERT_EQ(PP_OK, callback.result());
    458 
    459   PASS();
    460 }
    461 
    462