• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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