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