Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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_udp_socket.h" | |
| 6 | |
| 7 #include <vector> | |
| 8 | |
| 9 #include "ppapi/cpp/dev/tcp_socket_dev.h" | |
| 10 #include "ppapi/cpp/dev/udp_socket_dev.h" | |
| 11 #include "ppapi/cpp/pass_ref.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_Dev ReplacePort(const pp::InstanceHandle& instance, | |
| 24 const pp::NetAddress_Dev& addr, | |
| 25 uint16_t port) { | |
| 26 switch (addr.GetFamily()) { | |
| 27 case PP_NETADDRESS_FAMILY_UNSPECIFIED: { | |
|
bbudge
2013/06/12 18:52:37
Could this case be handled by the default case bel
yzshen1
2013/06/12 19:32:53
Done.
| |
| 28 break; | |
| 29 } | |
| 30 case PP_NETADDRESS_FAMILY_IPV4: { | |
| 31 PP_NetAddress_IPv4_Dev ipv4_addr; | |
| 32 if (!addr.DescribeAsIPv4Address(&ipv4_addr)) | |
| 33 break; | |
| 34 ipv4_addr.port = ConvertToNetEndian16(port); | |
| 35 return pp::NetAddress_Dev(instance, ipv4_addr); | |
| 36 } | |
| 37 case PP_NETADDRESS_FAMILY_IPV6: { | |
| 38 PP_NetAddress_IPv6_Dev ipv6_addr; | |
| 39 if (!addr.DescribeAsIPv6Address(&ipv6_addr)) | |
| 40 break; | |
| 41 ipv6_addr.port = ConvertToNetEndian16(port); | |
| 42 return pp::NetAddress_Dev(instance, ipv6_addr); | |
| 43 } | |
| 44 default: { | |
| 45 PP_NOTREACHED(); | |
| 46 } | |
| 47 } | |
| 48 return pp::NetAddress_Dev(); | |
| 49 } | |
| 50 | |
| 51 } // namespace | |
| 52 | |
| 53 TestUDPSocket::TestUDPSocket(TestingInstance* instance) : TestCase(instance) { | |
| 54 } | |
| 55 | |
| 56 bool TestUDPSocket::Init() { | |
| 57 bool tcp_socket_is_available = pp::TCPSocket_Dev::IsAvailable(); | |
| 58 if (!tcp_socket_is_available) | |
| 59 instance_->AppendError("PPB_TCPSocket interface not available"); | |
| 60 | |
| 61 bool udp_socket_is_available = pp::UDPSocket_Dev::IsAvailable(); | |
| 62 if (!udp_socket_is_available) | |
| 63 instance_->AppendError("PPB_UDPSocket interface not available"); | |
| 64 | |
| 65 bool net_address_is_available = pp::NetAddress_Dev::IsAvailable(); | |
| 66 if (!net_address_is_available) | |
| 67 instance_->AppendError("PPB_NetAddress interface not available"); | |
| 68 | |
| 69 std::string host; | |
| 70 uint16_t port = 0; | |
| 71 bool init_address = | |
| 72 GetLocalHostPort(instance_->pp_instance(), &host, &port) && | |
| 73 ResolveHost(instance_->pp_instance(), host, port, &address_); | |
| 74 if (!init_address) | |
| 75 instance_->AppendError("Can't init address"); | |
| 76 | |
| 77 return tcp_socket_is_available && | |
| 78 udp_socket_is_available && | |
| 79 net_address_is_available && | |
| 80 init_address && | |
| 81 CheckTestingInterface() && | |
| 82 EnsureRunningOverHTTP(); | |
| 83 } | |
| 84 | |
| 85 void TestUDPSocket::RunTests(const std::string& filter) { | |
| 86 RUN_CALLBACK_TEST(TestUDPSocket, ReadWrite, filter); | |
| 87 RUN_CALLBACK_TEST(TestUDPSocket, Broadcast, filter); | |
| 88 RUN_CALLBACK_TEST(TestUDPSocket, SetOption, filter); | |
| 89 } | |
| 90 | |
| 91 std::string TestUDPSocket::GetLocalAddress(pp::NetAddress_Dev* address) { | |
| 92 pp::TCPSocket_Dev socket(instance_); | |
| 93 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); | |
| 94 callback.WaitForResult(socket.Connect(address_, callback.GetCallback())); | |
| 95 CHECK_CALLBACK_BEHAVIOR(callback); | |
| 96 ASSERT_EQ(PP_OK, callback.result()); | |
| 97 *address = socket.GetLocalAddress(); | |
| 98 ASSERT_NE(0, address->pp_resource()); | |
| 99 socket.Close(); | |
| 100 PASS(); | |
| 101 } | |
| 102 | |
| 103 std::string TestUDPSocket::SetBroadcastOptions(pp::UDPSocket_Dev* socket) { | |
| 104 TestCompletionCallback callback_1(instance_->pp_instance(), callback_type()); | |
| 105 callback_1.WaitForResult(socket->SetOption( | |
| 106 PP_UDPSOCKET_OPTION_ADDRESS_REUSE, pp::Var(true), | |
| 107 callback_1.GetCallback())); | |
| 108 CHECK_CALLBACK_BEHAVIOR(callback_1); | |
| 109 ASSERT_EQ(PP_OK, callback_1.result()); | |
| 110 | |
| 111 TestCompletionCallback callback_2(instance_->pp_instance(), callback_type()); | |
| 112 callback_2.WaitForResult(socket->SetOption( | |
| 113 PP_UDPSOCKET_OPTION_BROADCAST, pp::Var(true), callback_2.GetCallback())); | |
| 114 CHECK_CALLBACK_BEHAVIOR(callback_2); | |
| 115 ASSERT_EQ(PP_OK, callback_2.result()); | |
| 116 | |
| 117 PASS(); | |
| 118 } | |
| 119 | |
| 120 std::string TestUDPSocket::BindUDPSocket(pp::UDPSocket_Dev* socket, | |
| 121 const pp::NetAddress_Dev& address) { | |
| 122 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); | |
| 123 callback.WaitForResult(socket->Bind(address, callback.GetCallback())); | |
| 124 CHECK_CALLBACK_BEHAVIOR(callback); | |
| 125 ASSERT_EQ(PP_OK, callback.result()); | |
| 126 PASS(); | |
| 127 } | |
| 128 | |
| 129 std::string TestUDPSocket::LookupPortAndBindUDPSocket( | |
| 130 pp::UDPSocket_Dev* socket, | |
| 131 pp::NetAddress_Dev* address) { | |
| 132 pp::NetAddress_Dev base_address; | |
| 133 ASSERT_SUBTEST_SUCCESS(GetLocalAddress(&base_address)); | |
| 134 | |
| 135 bool is_free_port_found = false; | |
| 136 for (uint16_t port = kPortScanFrom; port < kPortScanTo; ++port) { | |
| 137 pp::NetAddress_Dev new_address = ReplacePort(instance_, base_address, port); | |
| 138 ASSERT_NE(0, new_address.pp_resource()); | |
| 139 if (BindUDPSocket(socket, new_address).empty()) { | |
| 140 is_free_port_found = true; | |
| 141 break; | |
| 142 } | |
| 143 } | |
| 144 if (!is_free_port_found) | |
| 145 return "Can't find available port"; | |
| 146 | |
| 147 *address = socket->GetBoundAddress(); | |
| 148 ASSERT_NE(0, address->pp_resource()); | |
| 149 | |
| 150 PASS(); | |
| 151 } | |
| 152 | |
| 153 std::string TestUDPSocket::ReadSocket(pp::UDPSocket_Dev* socket, | |
| 154 pp::NetAddress_Dev* address, | |
| 155 size_t size, | |
| 156 std::string* message) { | |
| 157 std::vector<char> buffer(size); | |
| 158 TestCompletionCallbackWithOutput<pp::NetAddress_Dev> callback( | |
| 159 instance_->pp_instance(), callback_type()); | |
| 160 callback.WaitForResult( | |
| 161 socket->RecvFrom(&buffer[0], size, callback.GetCallback())); | |
| 162 CHECK_CALLBACK_BEHAVIOR(callback); | |
| 163 ASSERT_FALSE(callback.result() < 0); | |
| 164 ASSERT_EQ(size, static_cast<size_t>(callback.result())); | |
| 165 *address = callback.output(); | |
| 166 message->assign(buffer.begin(), buffer.end()); | |
| 167 PASS(); | |
| 168 } | |
| 169 | |
| 170 std::string TestUDPSocket::PassMessage(pp::UDPSocket_Dev* target, | |
| 171 pp::UDPSocket_Dev* source, | |
| 172 const pp::NetAddress_Dev& target_address, | |
| 173 const std::string& message, | |
| 174 pp::NetAddress_Dev* recvfrom_address) { | |
| 175 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); | |
| 176 int32_t rv = source->SendTo(message.c_str(), message.size(), | |
| 177 target_address, | |
| 178 callback.GetCallback()); | |
| 179 std::string str; | |
| 180 ASSERT_SUBTEST_SUCCESS(ReadSocket(target, recvfrom_address, message.size(), | |
| 181 &str)); | |
| 182 | |
| 183 callback.WaitForResult(rv); | |
| 184 CHECK_CALLBACK_BEHAVIOR(callback); | |
| 185 ASSERT_FALSE(callback.result() < 0); | |
| 186 ASSERT_EQ(message.size(), static_cast<size_t>(callback.result())); | |
| 187 ASSERT_EQ(message, str); | |
| 188 PASS(); | |
| 189 } | |
| 190 | |
| 191 std::string TestUDPSocket::TestReadWrite() { | |
| 192 pp::UDPSocket_Dev server_socket(instance_), client_socket(instance_); | |
| 193 pp::NetAddress_Dev server_address, client_address; | |
| 194 | |
| 195 ASSERT_SUBTEST_SUCCESS(LookupPortAndBindUDPSocket(&server_socket, | |
| 196 &server_address)); | |
| 197 ASSERT_SUBTEST_SUCCESS(LookupPortAndBindUDPSocket(&client_socket, | |
| 198 &client_address)); | |
| 199 const std::string message = "Simple message that will be sent via UDP"; | |
| 200 pp::NetAddress_Dev recvfrom_address; | |
| 201 ASSERT_SUBTEST_SUCCESS(PassMessage(&server_socket, &client_socket, | |
| 202 server_address, message, | |
| 203 &recvfrom_address)); | |
| 204 ASSERT_TRUE(EqualNetAddress(recvfrom_address, client_address)); | |
| 205 | |
| 206 server_socket.Close(); | |
| 207 client_socket.Close(); | |
| 208 | |
| 209 if (server_socket.GetBoundAddress().pp_resource() != 0) | |
| 210 return "PPB_UDPSocket::GetBoundAddress: expected failure"; | |
| 211 | |
| 212 PASS(); | |
| 213 } | |
| 214 | |
| 215 std::string TestUDPSocket::TestBroadcast() { | |
| 216 pp::UDPSocket_Dev server1(instance_), server2(instance_); | |
| 217 | |
| 218 ASSERT_SUBTEST_SUCCESS(SetBroadcastOptions(&server1)); | |
| 219 ASSERT_SUBTEST_SUCCESS(SetBroadcastOptions(&server2)); | |
| 220 | |
| 221 PP_NetAddress_IPv4_Dev any_ipv4_address = { 0, { 0, 0, 0, 0 } }; | |
| 222 pp::NetAddress_Dev any_address(instance_, any_ipv4_address); | |
| 223 ASSERT_SUBTEST_SUCCESS(BindUDPSocket(&server1, any_address)); | |
| 224 // Fill port field of |server_address|. | |
| 225 pp::NetAddress_Dev server_address = server1.GetBoundAddress(); | |
| 226 ASSERT_NE(0, server_address.pp_resource()); | |
| 227 ASSERT_SUBTEST_SUCCESS(BindUDPSocket(&server2, server_address)); | |
| 228 | |
| 229 PP_NetAddress_IPv4_Dev server_ipv4_address; | |
| 230 ASSERT_TRUE(server_address.DescribeAsIPv4Address(&server_ipv4_address)); | |
| 231 | |
| 232 PP_NetAddress_IPv4_Dev broadcast_ipv4_address = { | |
| 233 server_ipv4_address.port, { 0xff, 0xff, 0xff, 0xff } | |
| 234 }; | |
| 235 pp::NetAddress_Dev broadcast_address(instance_, broadcast_ipv4_address); | |
| 236 | |
| 237 std::string message; | |
| 238 const std::string first_message = "first message"; | |
| 239 const std::string second_message = "second_message"; | |
| 240 | |
| 241 pp::NetAddress_Dev recvfrom_address; | |
| 242 ASSERT_SUBTEST_SUCCESS(PassMessage(&server1, &server2, broadcast_address, | |
| 243 first_message, &recvfrom_address)); | |
| 244 // |first_message| also arrived to |server2|. | |
|
bbudge
2013/06/12 18:52:37
s/arrived to/arrived at/
or say 'was received by'.
yzshen1
2013/06/12 19:32:53
Done.
| |
| 245 ASSERT_SUBTEST_SUCCESS(ReadSocket(&server2, &recvfrom_address, | |
| 246 first_message.size(), &message)); | |
| 247 ASSERT_EQ(first_message, message); | |
| 248 | |
| 249 ASSERT_SUBTEST_SUCCESS(PassMessage(&server2, &server1, broadcast_address, | |
| 250 second_message, &recvfrom_address)); | |
| 251 // |second_message| also arrived to |server1|. | |
|
bbudge
2013/06/12 18:52:37
Ditto.
yzshen1
2013/06/12 19:32:53
Done.
| |
| 252 ASSERT_SUBTEST_SUCCESS(ReadSocket(&server1, &recvfrom_address, | |
| 253 second_message.size(), &message)); | |
| 254 ASSERT_EQ(second_message, message); | |
| 255 | |
| 256 server1.Close(); | |
| 257 server2.Close(); | |
| 258 PASS(); | |
| 259 } | |
| 260 | |
| 261 std::string TestUDPSocket::TestSetOption() { | |
| 262 pp::UDPSocket_Dev socket(instance_); | |
| 263 | |
| 264 ASSERT_SUBTEST_SUCCESS(SetBroadcastOptions(&socket)); | |
| 265 | |
| 266 // Try to pass incorrect option value's type. | |
| 267 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); | |
| 268 callback.WaitForResult(socket.SetOption( | |
| 269 PP_UDPSOCKET_OPTION_ADDRESS_REUSE, pp::Var(1), callback.GetCallback())); | |
| 270 CHECK_CALLBACK_BEHAVIOR(callback); | |
| 271 ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result()); | |
| 272 | |
| 273 PASS(); | |
| 274 } | |
| OLD | NEW |