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_udp_socket.h"
      6 
      7 #include <vector>
      8 
      9 #include "ppapi/cpp/pass_ref.h"
     10 #include "ppapi/cpp/tcp_socket.h"
     11 #include "ppapi/cpp/udp_socket.h"
     12 #include "ppapi/cpp/var.h"
     13 #include "ppapi/tests/test_utils.h"
     14 #include "ppapi/tests/testing_instance.h"
     15 
     16 REGISTER_TEST_CASE(UDPSocket);
     17 
     18 namespace {
     19 
     20 const uint16_t kPortScanFrom = 1024;
     21 const uint16_t kPortScanTo = 4096;
     22 
     23 pp::NetAddress ReplacePort(const pp::InstanceHandle& instance,
     24                            const pp::NetAddress& addr,
     25                            uint16_t port) {
     26   switch (addr.GetFamily()) {
     27     case PP_NETADDRESS_FAMILY_IPV4: {
     28       PP_NetAddress_IPv4 ipv4_addr;
     29       if (!addr.DescribeAsIPv4Address(&ipv4_addr))
     30         break;
     31       ipv4_addr.port = ConvertToNetEndian16(port);
     32       return pp::NetAddress(instance, ipv4_addr);
     33     }
     34     case PP_NETADDRESS_FAMILY_IPV6: {
     35       PP_NetAddress_IPv6 ipv6_addr;
     36       if (!addr.DescribeAsIPv6Address(&ipv6_addr))
     37         break;
     38       ipv6_addr.port = ConvertToNetEndian16(port);
     39       return pp::NetAddress(instance, ipv6_addr);
     40     }
     41     default: {
     42       PP_NOTREACHED();
     43     }
     44   }
     45   return pp::NetAddress();
     46 }
     47 
     48 }  // namespace
     49 
     50 TestUDPSocket::TestUDPSocket(TestingInstance* instance) : TestCase(instance) {
     51 }
     52 
     53 bool TestUDPSocket::Init() {
     54   bool tcp_socket_is_available = pp::TCPSocket::IsAvailable();
     55   if (!tcp_socket_is_available)
     56     instance_->AppendError("PPB_TCPSocket interface not available");
     57 
     58   bool udp_socket_is_available = pp::UDPSocket::IsAvailable();
     59   if (!udp_socket_is_available)
     60     instance_->AppendError("PPB_UDPSocket interface not available");
     61 
     62   bool net_address_is_available = pp::NetAddress::IsAvailable();
     63   if (!net_address_is_available)
     64     instance_->AppendError("PPB_NetAddress interface not available");
     65 
     66   std::string host;
     67   uint16_t port = 0;
     68   bool init_address =
     69       GetLocalHostPort(instance_->pp_instance(), &host, &port) &&
     70       ResolveHost(instance_->pp_instance(), host, port, &address_);
     71   if (!init_address)
     72     instance_->AppendError("Can't init address");
     73 
     74   return tcp_socket_is_available &&
     75       udp_socket_is_available &&
     76       net_address_is_available &&
     77       init_address &&
     78       CheckTestingInterface() &&
     79       EnsureRunningOverHTTP();
     80 }
     81 
     82 void TestUDPSocket::RunTests(const std::string& filter) {
     83   RUN_CALLBACK_TEST(TestUDPSocket, ReadWrite, filter);
     84   RUN_CALLBACK_TEST(TestUDPSocket, Broadcast, filter);
     85   RUN_CALLBACK_TEST(TestUDPSocket, SetOption, filter);
     86 }
     87 
     88 std::string TestUDPSocket::GetLocalAddress(pp::NetAddress* address) {
     89   pp::TCPSocket socket(instance_);
     90   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
     91   callback.WaitForResult(socket.Connect(address_, callback.GetCallback()));
     92   CHECK_CALLBACK_BEHAVIOR(callback);
     93   ASSERT_EQ(PP_OK, callback.result());
     94   *address = socket.GetLocalAddress();
     95   ASSERT_NE(0, address->pp_resource());
     96   socket.Close();
     97   PASS();
     98 }
     99 
    100 std::string TestUDPSocket::SetBroadcastOptions(pp::UDPSocket* socket) {
    101   TestCompletionCallback callback_1(instance_->pp_instance(), callback_type());
    102   callback_1.WaitForResult(socket->SetOption(
    103       PP_UDPSOCKET_OPTION_ADDRESS_REUSE, pp::Var(true),
    104       callback_1.GetCallback()));
    105   CHECK_CALLBACK_BEHAVIOR(callback_1);
    106   ASSERT_EQ(PP_OK, callback_1.result());
    107 
    108   TestCompletionCallback callback_2(instance_->pp_instance(), callback_type());
    109   callback_2.WaitForResult(socket->SetOption(
    110       PP_UDPSOCKET_OPTION_BROADCAST, pp::Var(true), callback_2.GetCallback()));
    111   CHECK_CALLBACK_BEHAVIOR(callback_2);
    112   ASSERT_EQ(PP_OK, callback_2.result());
    113 
    114   PASS();
    115 }
    116 
    117 std::string TestUDPSocket::BindUDPSocket(pp::UDPSocket* socket,
    118                                          const pp::NetAddress& address) {
    119   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
    120   callback.WaitForResult(socket->Bind(address, callback.GetCallback()));
    121   CHECK_CALLBACK_BEHAVIOR(callback);
    122   ASSERT_EQ(PP_OK, callback.result());
    123   PASS();
    124 }
    125 
    126 std::string TestUDPSocket::LookupPortAndBindUDPSocket(
    127     pp::UDPSocket* socket,
    128     pp::NetAddress* address) {
    129   pp::NetAddress base_address;
    130   ASSERT_SUBTEST_SUCCESS(GetLocalAddress(&base_address));
    131 
    132   bool is_free_port_found = false;
    133   for (uint16_t port = kPortScanFrom; port < kPortScanTo; ++port) {
    134     pp::NetAddress new_address = ReplacePort(instance_, base_address, port);
    135     ASSERT_NE(0, new_address.pp_resource());
    136     if (BindUDPSocket(socket, new_address).empty()) {
    137       is_free_port_found = true;
    138       break;
    139     }
    140   }
    141   if (!is_free_port_found)
    142     return "Can't find available port";
    143 
    144   *address = socket->GetBoundAddress();
    145   ASSERT_NE(0, address->pp_resource());
    146 
    147   PASS();
    148 }
    149 
    150 std::string TestUDPSocket::ReadSocket(pp::UDPSocket* socket,
    151                                       pp::NetAddress* address,
    152                                       size_t size,
    153                                       std::string* message) {
    154   std::vector<char> buffer(size);
    155   TestCompletionCallbackWithOutput<pp::NetAddress> callback(
    156       instance_->pp_instance(), callback_type());
    157   callback.WaitForResult(
    158       socket->RecvFrom(&buffer[0], size, callback.GetCallback()));
    159   CHECK_CALLBACK_BEHAVIOR(callback);
    160   ASSERT_FALSE(callback.result() < 0);
    161   ASSERT_EQ(size, static_cast<size_t>(callback.result()));
    162   *address = callback.output();
    163   message->assign(buffer.begin(), buffer.end());
    164   PASS();
    165 }
    166 
    167 std::string TestUDPSocket::PassMessage(pp::UDPSocket* target,
    168                                        pp::UDPSocket* source,
    169                                        const pp::NetAddress& target_address,
    170                                        const std::string& message,
    171                                        pp::NetAddress* recvfrom_address) {
    172   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
    173   int32_t rv = source->SendTo(message.c_str(), message.size(),
    174                               target_address,
    175                               callback.GetCallback());
    176   std::string str;
    177   ASSERT_SUBTEST_SUCCESS(ReadSocket(target, recvfrom_address, message.size(),
    178                                     &str));
    179 
    180   callback.WaitForResult(rv);
    181   CHECK_CALLBACK_BEHAVIOR(callback);
    182   ASSERT_FALSE(callback.result() < 0);
    183   ASSERT_EQ(message.size(), static_cast<size_t>(callback.result()));
    184   ASSERT_EQ(message, str);
    185   PASS();
    186 }
    187 
    188 std::string TestUDPSocket::TestReadWrite() {
    189   pp::UDPSocket server_socket(instance_), client_socket(instance_);
    190   pp::NetAddress server_address, client_address;
    191 
    192   ASSERT_SUBTEST_SUCCESS(LookupPortAndBindUDPSocket(&server_socket,
    193                                                     &server_address));
    194   ASSERT_SUBTEST_SUCCESS(LookupPortAndBindUDPSocket(&client_socket,
    195                                                     &client_address));
    196   const std::string message = "Simple message that will be sent via UDP";
    197   pp::NetAddress recvfrom_address;
    198   ASSERT_SUBTEST_SUCCESS(PassMessage(&server_socket, &client_socket,
    199                                      server_address, message,
    200                                      &recvfrom_address));
    201   ASSERT_TRUE(EqualNetAddress(recvfrom_address, client_address));
    202 
    203   server_socket.Close();
    204   client_socket.Close();
    205 
    206   if (server_socket.GetBoundAddress().pp_resource() != 0)
    207     return "PPB_UDPSocket::GetBoundAddress: expected failure";
    208 
    209   PASS();
    210 }
    211 
    212 std::string TestUDPSocket::TestBroadcast() {
    213   pp::UDPSocket server1(instance_), server2(instance_);
    214 
    215   ASSERT_SUBTEST_SUCCESS(SetBroadcastOptions(&server1));
    216   ASSERT_SUBTEST_SUCCESS(SetBroadcastOptions(&server2));
    217 
    218   PP_NetAddress_IPv4 any_ipv4_address = { 0, { 0, 0, 0, 0 } };
    219   pp::NetAddress any_address(instance_, any_ipv4_address);
    220   ASSERT_SUBTEST_SUCCESS(BindUDPSocket(&server1, any_address));
    221   // Fill port field of |server_address|.
    222   pp::NetAddress server_address = server1.GetBoundAddress();
    223   ASSERT_NE(0, server_address.pp_resource());
    224   ASSERT_SUBTEST_SUCCESS(BindUDPSocket(&server2, server_address));
    225 
    226   PP_NetAddress_IPv4 server_ipv4_address;
    227   ASSERT_TRUE(server_address.DescribeAsIPv4Address(&server_ipv4_address));
    228 
    229   PP_NetAddress_IPv4 broadcast_ipv4_address = {
    230     server_ipv4_address.port, { 0xff, 0xff, 0xff, 0xff }
    231   };
    232   pp::NetAddress broadcast_address(instance_, broadcast_ipv4_address);
    233 
    234   std::string message;
    235   const std::string first_message = "first message";
    236   const std::string second_message = "second_message";
    237 
    238   pp::NetAddress recvfrom_address;
    239   ASSERT_SUBTEST_SUCCESS(PassMessage(&server1, &server2, broadcast_address,
    240                                      first_message, &recvfrom_address));
    241   // |first_message| was also received by |server2|.
    242   ASSERT_SUBTEST_SUCCESS(ReadSocket(&server2, &recvfrom_address,
    243                                     first_message.size(), &message));
    244   ASSERT_EQ(first_message, message);
    245 
    246   ASSERT_SUBTEST_SUCCESS(PassMessage(&server2, &server1, broadcast_address,
    247                                      second_message, &recvfrom_address));
    248   // |second_message| was also received by |server1|.
    249   ASSERT_SUBTEST_SUCCESS(ReadSocket(&server1, &recvfrom_address,
    250                                     second_message.size(), &message));
    251   ASSERT_EQ(second_message, message);
    252 
    253   server1.Close();
    254   server2.Close();
    255   PASS();
    256 }
    257 
    258 std::string TestUDPSocket::TestSetOption() {
    259   pp::UDPSocket socket(instance_);
    260 
    261   ASSERT_SUBTEST_SUCCESS(SetBroadcastOptions(&socket));
    262 
    263   // Try to pass incorrect option value's type.
    264   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
    265   callback.WaitForResult(socket.SetOption(
    266       PP_UDPSOCKET_OPTION_ADDRESS_REUSE, pp::Var(1), callback.GetCallback()));
    267   CHECK_CALLBACK_BEHAVIOR(callback);
    268   ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result());
    269 
    270   callback.WaitForResult(socket.SetOption(
    271       PP_UDPSOCKET_OPTION_BROADCAST, pp::Var(false), callback.GetCallback()));
    272   CHECK_CALLBACK_BEHAVIOR(callback);
    273   ASSERT_EQ(PP_OK, callback.result());
    274 
    275   // SEND_BUFFER_SIZE and RECV_BUFFER_SIZE shouldn't be set before the socket is
    276   // bound.
    277   callback.WaitForResult(socket.SetOption(
    278       PP_UDPSOCKET_OPTION_SEND_BUFFER_SIZE, pp::Var(4096),
    279       callback.GetCallback()));
    280   CHECK_CALLBACK_BEHAVIOR(callback);
    281   ASSERT_EQ(PP_ERROR_FAILED, callback.result());
    282 
    283   callback.WaitForResult(socket.SetOption(
    284       PP_UDPSOCKET_OPTION_RECV_BUFFER_SIZE, pp::Var(512),
    285       callback.GetCallback()));
    286   CHECK_CALLBACK_BEHAVIOR(callback);
    287   ASSERT_EQ(PP_ERROR_FAILED, callback.result());
    288 
    289   pp::NetAddress address;
    290   ASSERT_SUBTEST_SUCCESS(LookupPortAndBindUDPSocket(&socket, &address));
    291 
    292   // ADDRESS_REUSE and BROADCAST won't take effect after the socket is bound.
    293   callback.WaitForResult(socket.SetOption(
    294       PP_UDPSOCKET_OPTION_ADDRESS_REUSE, pp::Var(true),
    295       callback.GetCallback()));
    296   CHECK_CALLBACK_BEHAVIOR(callback);
    297   ASSERT_EQ(PP_ERROR_FAILED, callback.result());
    298 
    299   callback.WaitForResult(socket.SetOption(
    300       PP_UDPSOCKET_OPTION_BROADCAST, pp::Var(true), callback.GetCallback()));
    301   CHECK_CALLBACK_BEHAVIOR(callback);
    302   ASSERT_EQ(PP_ERROR_FAILED, callback.result());
    303 
    304   // SEND_BUFFER_SIZE and RECV_BUFFER_SIZE can be set after the socket is bound.
    305   callback.WaitForResult(socket.SetOption(
    306       PP_UDPSOCKET_OPTION_SEND_BUFFER_SIZE, pp::Var(2048),
    307       callback.GetCallback()));
    308   CHECK_CALLBACK_BEHAVIOR(callback);
    309   ASSERT_EQ(PP_OK, callback.result());
    310 
    311   callback.WaitForResult(socket.SetOption(
    312       PP_UDPSOCKET_OPTION_RECV_BUFFER_SIZE, pp::Var(1024),
    313       callback.GetCallback()));
    314   CHECK_CALLBACK_BEHAVIOR(callback);
    315   ASSERT_EQ(PP_OK, callback.result());
    316 
    317   PASS();
    318 }
    319