• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ReplacePort(const pp::InstanceHandle & instance,const pp::NetAddress & addr,uint16_t port)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 
TestUDPSocket(TestingInstance * instance)50 TestUDPSocket::TestUDPSocket(TestingInstance* instance) : TestCase(instance) {
51 }
52 
Init()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 
RunTests(const std::string & filter)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 
GetLocalAddress(pp::NetAddress * address)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 
SetBroadcastOptions(pp::UDPSocket * socket)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 
BindUDPSocket(pp::UDPSocket * socket,const pp::NetAddress & address)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 
LookupPortAndBindUDPSocket(pp::UDPSocket * socket,pp::NetAddress * address)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 
ReadSocket(pp::UDPSocket * socket,pp::NetAddress * address,size_t size,std::string * message)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 
PassMessage(pp::UDPSocket * target,pp::UDPSocket * source,const pp::NetAddress & target_address,const std::string & message,pp::NetAddress * recvfrom_address)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 
TestReadWrite()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 
TestBroadcast()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 
TestSetOption()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