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 16REGISTER_TEST_CASE(UDPSocket); 17 18namespace { 19 20const uint16_t kPortScanFrom = 1024; 21const uint16_t kPortScanTo = 4096; 22 23pp::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 50TestUDPSocket::TestUDPSocket(TestingInstance* instance) : TestCase(instance) { 51} 52 53bool 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 82void 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 88std::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 100std::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 117std::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 126std::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 150std::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 167std::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 188std::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 212std::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 258std::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