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: { | |
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 && | |
bbudge
2013/06/10 12:59:56
It would look nicer if tcp_socket_is_available was
yzshen1
2013/06/10 22:10:35
I thought this way conforms to the style guide?
Pu
bbudge
2013/06/11 00:30:39
OK
| |
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 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); | |
159 PP_Resource out_address = 0; | |
160 callback.WaitForResult( | |
161 socket->RecvFrom(&buffer[0], size, &out_address, 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 = pp::NetAddress_Dev(pp::PASS_REF, out_address); | |
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, 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, 0, { 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|. | |
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|. | |
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 |