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_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 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 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 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 93 uint16_t ConvertFromNetEndian16(uint16_t x) { 94 if (IsBigEndian()) 95 return x; 96 else 97 return (x << 8) | (x >> 8); 98 } 99 100 uint16_t ConvertToNetEndian16(uint16_t x) { 101 if (IsBigEndian()) 102 return x; 103 else 104 return (x << 8) | (x >> 8); 105 } 106 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 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 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 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 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 243 void NestedEvent::Signal() { 244 if (pp::Module::Get()->core()->IsMainThread()) 245 SignalOnMainThread(); 246 else 247 PostSignal(0); 248 } 249 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 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 264 void NestedEvent::SignalOnMainThread() { 265 PP_DCHECK(pp::Module::Get()->core()->IsMainThread()); 266 signalled_ = true; 267 if (waiting_) 268 GetTestingInterface()->QuitMessageLoop(instance_); 269 } 270 271 void NestedEvent::SignalThunk(void* event, int32_t /* result */) { 272 static_cast<NestedEvent*>(event)->SignalOnMainThread(); 273 } 274 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 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 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 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 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 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 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 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 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 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