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_utils.h"
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #if defined(_MSC_VER)
11 #include <windows.h>
12 #else
13 #include <unistd.h>
14 #endif
15
16 #include "ppapi/c/pp_errors.h"
17 #include "ppapi/cpp/instance_handle.h"
18 #include "ppapi/cpp/module.h"
19 #include "ppapi/cpp/net_address.h"
20 #include "ppapi/cpp/private/host_resolver_private.h"
21 #include "ppapi/cpp/private/net_address_private.h"
22 #include "ppapi/cpp/var.h"
23
24 namespace {
25
IsBigEndian()26 bool IsBigEndian() {
27 union {
28 uint32_t integer32;
29 uint8_t integer8[4];
30 } data = { 0x01020304 };
31
32 return data.integer8[0] == 1;
33 }
34
35 } // namespace
36
37 const int kActionTimeoutMs = 10000;
38
GetTestingInterface()39 const PPB_Testing_Private* GetTestingInterface() {
40 static const PPB_Testing_Private* g_testing_interface =
41 static_cast<const PPB_Testing_Private*>(
42 pp::Module::Get()->GetBrowserInterface(
43 PPB_TESTING_PRIVATE_INTERFACE));
44 return g_testing_interface;
45 }
46
ReportError(const char * method,int32_t error)47 std::string ReportError(const char* method, int32_t error) {
48 char error_as_string[12];
49 sprintf(error_as_string, "%d", static_cast<int>(error));
50 std::string result = method + std::string(" failed with error: ") +
51 error_as_string;
52 return result;
53 }
54
PlatformSleep(int duration_ms)55 void PlatformSleep(int duration_ms) {
56 #if defined(_MSC_VER)
57 ::Sleep(duration_ms);
58 #else
59 usleep(duration_ms * 1000);
60 #endif
61 }
62
GetLocalHostPort(PP_Instance instance,std::string * host,uint16_t * port)63 bool GetLocalHostPort(PP_Instance instance, std::string* host, uint16_t* port) {
64 if (!host || !port)
65 return false;
66
67 const PPB_Testing_Private* testing = GetTestingInterface();
68 if (!testing)
69 return false;
70
71 PP_URLComponents_Dev components;
72 pp::Var pp_url(pp::PASS_REF,
73 testing->GetDocumentURL(instance, &components));
74 if (!pp_url.is_string())
75 return false;
76 std::string url = pp_url.AsString();
77
78 if (components.host.len < 0)
79 return false;
80 host->assign(url.substr(components.host.begin, components.host.len));
81
82 if (components.port.len <= 0)
83 return false;
84
85 int i = atoi(url.substr(components.port.begin, components.port.len).c_str());
86 if (i < 0 || i > 65535)
87 return false;
88 *port = static_cast<uint16_t>(i);
89
90 return true;
91 }
92
ConvertFromNetEndian16(uint16_t x)93 uint16_t ConvertFromNetEndian16(uint16_t x) {
94 if (IsBigEndian())
95 return x;
96 else
97 return (x << 8) | (x >> 8);
98 }
99
ConvertToNetEndian16(uint16_t x)100 uint16_t ConvertToNetEndian16(uint16_t x) {
101 if (IsBigEndian())
102 return x;
103 else
104 return (x << 8) | (x >> 8);
105 }
106
EqualNetAddress(const pp::NetAddress & addr1,const pp::NetAddress & addr2)107 bool EqualNetAddress(const pp::NetAddress& addr1, const pp::NetAddress& addr2) {
108 if (addr1.GetFamily() == PP_NETADDRESS_FAMILY_UNSPECIFIED ||
109 addr2.GetFamily() == PP_NETADDRESS_FAMILY_UNSPECIFIED) {
110 return false;
111 }
112
113 if (addr1.GetFamily() == PP_NETADDRESS_FAMILY_IPV4) {
114 PP_NetAddress_IPv4 ipv4_addr1, ipv4_addr2;
115 if (!addr1.DescribeAsIPv4Address(&ipv4_addr1) ||
116 !addr2.DescribeAsIPv4Address(&ipv4_addr2)) {
117 return false;
118 }
119
120 return ipv4_addr1.port == ipv4_addr2.port &&
121 !memcmp(ipv4_addr1.addr, ipv4_addr2.addr, sizeof(ipv4_addr1.addr));
122 } else {
123 PP_NetAddress_IPv6 ipv6_addr1, ipv6_addr2;
124 if (!addr1.DescribeAsIPv6Address(&ipv6_addr1) ||
125 !addr2.DescribeAsIPv6Address(&ipv6_addr2)) {
126 return false;
127 }
128
129 return ipv6_addr1.port == ipv6_addr2.port &&
130 !memcmp(ipv6_addr1.addr, ipv6_addr2.addr, sizeof(ipv6_addr1.addr));
131 }
132 }
133
ResolveHost(PP_Instance instance,const std::string & host,uint16_t port,pp::NetAddress * addr)134 bool ResolveHost(PP_Instance instance,
135 const std::string& host,
136 uint16_t port,
137 pp::NetAddress* addr) {
138 // TODO(yzshen): Change to use the public host resolver once it is supported.
139 pp::InstanceHandle instance_handle(instance);
140 pp::HostResolverPrivate host_resolver(instance_handle);
141 PP_HostResolver_Private_Hint hint =
142 { PP_NETADDRESSFAMILY_PRIVATE_UNSPECIFIED, 0 };
143
144 TestCompletionCallback callback(instance);
145 callback.WaitForResult(
146 host_resolver.Resolve(host, port, hint, callback.GetCallback()));
147
148 PP_NetAddress_Private addr_private;
149 if (callback.result() != PP_OK || host_resolver.GetSize() == 0 ||
150 !host_resolver.GetNetAddress(0, &addr_private)) {
151 return false;
152 }
153
154 switch (pp::NetAddressPrivate::GetFamily(addr_private)) {
155 case PP_NETADDRESSFAMILY_PRIVATE_IPV4: {
156 PP_NetAddress_IPv4 ipv4_addr;
157 ipv4_addr.port = ConvertToNetEndian16(
158 pp::NetAddressPrivate::GetPort(addr_private));
159 if (!pp::NetAddressPrivate::GetAddress(addr_private, ipv4_addr.addr,
160 sizeof(ipv4_addr.addr))) {
161 return false;
162 }
163 *addr = pp::NetAddress(instance_handle, ipv4_addr);
164 return true;
165 }
166 case PP_NETADDRESSFAMILY_PRIVATE_IPV6: {
167 PP_NetAddress_IPv6 ipv6_addr;
168 ipv6_addr.port = ConvertToNetEndian16(
169 pp::NetAddressPrivate::GetPort(addr_private));
170 if (!pp::NetAddressPrivate::GetAddress(addr_private, ipv6_addr.addr,
171 sizeof(ipv6_addr.addr))) {
172 return false;
173 }
174 *addr = pp::NetAddress(instance_handle, ipv6_addr);
175 return true;
176 }
177 default: {
178 return false;
179 }
180 }
181 }
182
ReplacePort(PP_Instance instance,const pp::NetAddress & input_addr,uint16_t port,pp::NetAddress * output_addr)183 bool ReplacePort(PP_Instance instance,
184 const pp::NetAddress& input_addr,
185 uint16_t port,
186 pp::NetAddress* output_addr) {
187 switch (input_addr.GetFamily()) {
188 case PP_NETADDRESS_FAMILY_IPV4: {
189 PP_NetAddress_IPv4 ipv4_addr;
190 if (!input_addr.DescribeAsIPv4Address(&ipv4_addr))
191 return false;
192 ipv4_addr.port = ConvertToNetEndian16(port);
193 *output_addr = pp::NetAddress(pp::InstanceHandle(instance), ipv4_addr);
194 return true;
195 }
196 case PP_NETADDRESS_FAMILY_IPV6: {
197 PP_NetAddress_IPv6 ipv6_addr;
198 if (!input_addr.DescribeAsIPv6Address(&ipv6_addr))
199 return false;
200 ipv6_addr.port = ConvertToNetEndian16(port);
201 *output_addr = pp::NetAddress(pp::InstanceHandle(instance), ipv6_addr);
202 return true;
203 }
204 default: {
205 return false;
206 }
207 }
208 }
209
GetPort(const pp::NetAddress & addr)210 uint16_t GetPort(const pp::NetAddress& addr) {
211 switch (addr.GetFamily()) {
212 case PP_NETADDRESS_FAMILY_IPV4: {
213 PP_NetAddress_IPv4 ipv4_addr;
214 if (!addr.DescribeAsIPv4Address(&ipv4_addr))
215 return 0;
216 return ConvertFromNetEndian16(ipv4_addr.port);
217 }
218 case PP_NETADDRESS_FAMILY_IPV6: {
219 PP_NetAddress_IPv6 ipv6_addr;
220 if (!addr.DescribeAsIPv6Address(&ipv6_addr))
221 return 0;
222 return ConvertFromNetEndian16(ipv6_addr.port);
223 }
224 default: {
225 return 0;
226 }
227 }
228 }
229
Wait()230 void NestedEvent::Wait() {
231 PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
232 // Don't allow nesting more than once; it doesn't work with the code as-is,
233 // and probably is a bad idea most of the time anyway.
234 PP_DCHECK(!waiting_);
235 if (signalled_)
236 return;
237 waiting_ = true;
238 while (!signalled_)
239 GetTestingInterface()->RunMessageLoop(instance_);
240 waiting_ = false;
241 }
242
Signal()243 void NestedEvent::Signal() {
244 if (pp::Module::Get()->core()->IsMainThread())
245 SignalOnMainThread();
246 else
247 PostSignal(0);
248 }
249
PostSignal(int32_t wait_ms)250 void NestedEvent::PostSignal(int32_t wait_ms) {
251 pp::Module::Get()->core()->CallOnMainThread(
252 wait_ms,
253 pp::CompletionCallback(&SignalThunk, this),
254 0);
255 }
256
Reset()257 void NestedEvent::Reset() {
258 PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
259 // It doesn't make sense to reset when we're still waiting.
260 PP_DCHECK(!waiting_);
261 signalled_ = false;
262 }
263
SignalOnMainThread()264 void NestedEvent::SignalOnMainThread() {
265 PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
266 signalled_ = true;
267 if (waiting_)
268 GetTestingInterface()->QuitMessageLoop(instance_);
269 }
270
SignalThunk(void * event,int32_t)271 void NestedEvent::SignalThunk(void* event, int32_t /* result */) {
272 static_cast<NestedEvent*>(event)->SignalOnMainThread();
273 }
274
TestCompletionCallback(PP_Instance instance)275 TestCompletionCallback::TestCompletionCallback(PP_Instance instance)
276 : wait_for_result_called_(false),
277 have_result_(false),
278 result_(PP_OK_COMPLETIONPENDING),
279 // TODO(dmichael): The default should probably be PP_REQUIRED, but this is
280 // what the tests currently expect.
281 callback_type_(PP_OPTIONAL),
282 post_quit_task_(false),
283 instance_(instance),
284 delegate_(NULL) {
285 }
286
TestCompletionCallback(PP_Instance instance,bool force_async)287 TestCompletionCallback::TestCompletionCallback(PP_Instance instance,
288 bool force_async)
289 : wait_for_result_called_(false),
290 have_result_(false),
291 result_(PP_OK_COMPLETIONPENDING),
292 callback_type_(force_async ? PP_REQUIRED : PP_OPTIONAL),
293 post_quit_task_(false),
294 instance_(instance),
295 delegate_(NULL) {
296 }
297
TestCompletionCallback(PP_Instance instance,CallbackType callback_type)298 TestCompletionCallback::TestCompletionCallback(PP_Instance instance,
299 CallbackType callback_type)
300 : wait_for_result_called_(false),
301 have_result_(false),
302 result_(PP_OK_COMPLETIONPENDING),
303 callback_type_(callback_type),
304 post_quit_task_(false),
305 instance_(instance),
306 delegate_(NULL) {
307 }
308
WaitForResult(int32_t result)309 void TestCompletionCallback::WaitForResult(int32_t result) {
310 PP_DCHECK(!wait_for_result_called_);
311 wait_for_result_called_ = true;
312 errors_.clear();
313 if (result == PP_OK_COMPLETIONPENDING) {
314 if (!have_result_) {
315 post_quit_task_ = true;
316 RunMessageLoop();
317 }
318 if (callback_type_ == PP_BLOCKING) {
319 errors_.assign(
320 ReportError("TestCompletionCallback: Call did not run synchronously "
321 "when passed a blocking completion callback!",
322 result_));
323 return;
324 }
325 } else {
326 result_ = result;
327 have_result_ = true;
328 if (callback_type_ == PP_REQUIRED) {
329 errors_.assign(
330 ReportError("TestCompletionCallback: Call ran synchronously when "
331 "passed a required completion callback!",
332 result_));
333 return;
334 }
335 }
336 PP_DCHECK(have_result_ == true);
337 }
338
WaitForAbortResult(int32_t result)339 void TestCompletionCallback::WaitForAbortResult(int32_t result) {
340 WaitForResult(result);
341 int32_t final_result = result_;
342 if (result == PP_OK_COMPLETIONPENDING) {
343 if (final_result != PP_ERROR_ABORTED) {
344 errors_.assign(
345 ReportError("TestCompletionCallback: Expected PP_ERROR_ABORTED or "
346 "PP_OK. Ran asynchronously.",
347 final_result));
348 return;
349 }
350 } else if (result < PP_OK) {
351 errors_.assign(
352 ReportError("TestCompletionCallback: Expected PP_ERROR_ABORTED or "
353 "non-error response. Ran synchronously.",
354 result));
355 return;
356 }
357 }
358
GetCallback()359 pp::CompletionCallback TestCompletionCallback::GetCallback() {
360 Reset();
361 int32_t flags = 0;
362 if (callback_type_ == PP_BLOCKING)
363 return pp::CompletionCallback();
364 else if (callback_type_ == PP_OPTIONAL)
365 flags = PP_COMPLETIONCALLBACK_FLAG_OPTIONAL;
366 target_loop_ = pp::MessageLoop::GetCurrent();
367 return pp::CompletionCallback(&TestCompletionCallback::Handler,
368 const_cast<TestCompletionCallback*>(this),
369 flags);
370 }
371
Reset()372 void TestCompletionCallback::Reset() {
373 wait_for_result_called_ = false;
374 result_ = PP_OK_COMPLETIONPENDING;
375 have_result_ = false;
376 post_quit_task_ = false;
377 delegate_ = NULL;
378 errors_.clear();
379 }
380
381 // static
Handler(void * user_data,int32_t result)382 void TestCompletionCallback::Handler(void* user_data, int32_t result) {
383 TestCompletionCallback* callback =
384 static_cast<TestCompletionCallback*>(user_data);
385 // If this check fails, it means that the callback was invoked twice or that
386 // the PPAPI call completed synchronously, but also ran the callback.
387 PP_DCHECK(!callback->have_result_);
388 callback->result_ = result;
389 callback->have_result_ = true;
390 if (callback->delegate_)
391 callback->delegate_->OnCallback(user_data, result);
392 if (callback->post_quit_task_) {
393 callback->post_quit_task_ = false;
394 callback->QuitMessageLoop();
395 }
396 if (callback->target_loop_ != pp::MessageLoop::GetCurrent()) {
397 // Note, in-process, loop_ and GetCurrent() will both be NULL, so should
398 // still be equal.
399 callback->errors_.assign(
400 ReportError("TestCompletionCallback: Callback ran on the wrong message "
401 "loop!",
402 result));
403 }
404 }
405
RunMessageLoop()406 void TestCompletionCallback::RunMessageLoop() {
407 pp::MessageLoop loop(pp::MessageLoop::GetCurrent());
408 // If we don't have a message loop, we're probably running in process, where
409 // PPB_MessageLoop is not supported. Just use the Testing message loop.
410 if (loop.is_null() || loop == pp::MessageLoop::GetForMainThread())
411 GetTestingInterface()->RunMessageLoop(instance_);
412 else
413 loop.Run();
414 }
415
QuitMessageLoop()416 void TestCompletionCallback::QuitMessageLoop() {
417 pp::MessageLoop loop(pp::MessageLoop::GetCurrent());
418 // If we don't have a message loop, we're probably running in process, where
419 // PPB_MessageLoop is not supported. Just use the Testing message loop.
420 if (loop.is_null() || loop == pp::MessageLoop::GetForMainThread()) {
421 GetTestingInterface()->QuitMessageLoop(instance_);
422 } else {
423 const bool should_quit = false;
424 loop.PostQuit(should_quit);
425 }
426 }
427