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
24namespace {
25
26bool 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
37const int kActionTimeoutMs = 10000;
38
39const 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
47std::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
55void PlatformSleep(int duration_ms) {
56#if defined(_MSC_VER)
57  ::Sleep(duration_ms);
58#else
59  usleep(duration_ms * 1000);
60#endif
61}
62
63bool 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
93uint16_t ConvertFromNetEndian16(uint16_t x) {
94  if (IsBigEndian())
95    return x;
96  else
97    return (x << 8) | (x >> 8);
98}
99
100uint16_t ConvertToNetEndian16(uint16_t x) {
101  if (IsBigEndian())
102    return x;
103  else
104    return (x << 8) | (x >> 8);
105}
106
107bool 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
134bool 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
183bool 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
210uint16_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
230void 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
243void NestedEvent::Signal() {
244  if (pp::Module::Get()->core()->IsMainThread())
245    SignalOnMainThread();
246  else
247    PostSignal(0);
248}
249
250void NestedEvent::PostSignal(int32_t wait_ms) {
251  pp::Module::Get()->core()->CallOnMainThread(
252      wait_ms,
253      pp::CompletionCallback(&SignalThunk, this),
254      0);
255}
256
257void 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
264void NestedEvent::SignalOnMainThread() {
265  PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
266  signalled_ = true;
267  if (waiting_)
268    GetTestingInterface()->QuitMessageLoop(instance_);
269}
270
271void NestedEvent::SignalThunk(void* event, int32_t /* result */) {
272  static_cast<NestedEvent*>(event)->SignalOnMainThread();
273}
274
275TestCompletionCallback::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
287TestCompletionCallback::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
298TestCompletionCallback::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
309void 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
339void 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
359pp::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
372void 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
382void 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
406void 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
416void 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