Web MIDI: MidiManager crashes if a session is ended while initializing
[chromium-blink-merge.git] / ppapi / tests / test_broker.cc
blobdb2fa3ffbb39e2e7d2bd6c33a2f483cf7e4f872e
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.
5 #include "ppapi/tests/test_broker.h"
7 #if defined(_MSC_VER)
8 #define OS_WIN 1
9 #include <windows.h>
10 #else
11 #define OS_POSIX 1
12 #include <errno.h>
13 #include <unistd.h>
14 #endif
16 #include <cstdio>
17 #include <cstring>
18 #include <fstream>
19 #include <limits>
21 #include "ppapi/c/pp_errors.h"
22 #include "ppapi/c/trusted/ppp_broker.h"
23 #include "ppapi/c/trusted/ppb_broker_trusted.h"
24 #include "ppapi/tests/test_utils.h"
25 #include "ppapi/tests/testing_instance.h"
27 REGISTER_TEST_CASE(Broker);
29 namespace {
31 const char kHelloMessage[] = "Hello Plugin! This is Broker!";
32 // Message sent from broker to plugin if the broker is unsandboxed.
33 const char kBrokerUnsandboxed[] = "Broker is Unsandboxed!";
34 // Message sent from broker to plugin if the broker is sandboxed. This message
35 // needs to be longer than |kBrokerUnsandboxed| because the plugin is expecting
36 // |kBrokerUnsandboxed|. If it's shorter and the broker doesn't close its handle
37 // properly the plugin will hang waiting for all data of |kBrokerUnsandboxed| to
38 // be read.
39 const char kBrokerSandboxed[] = "Broker is Sandboxed! Verification failed!";
41 #if defined(OS_WIN)
42 typedef HANDLE PlatformFile;
43 const PlatformFile kInvalidPlatformFileValue = INVALID_HANDLE_VALUE;
44 const int32_t kInvalidHandle = static_cast<int32_t>(
45 reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE));
46 #elif defined(OS_POSIX)
47 typedef int PlatformFile;
48 const PlatformFile kInvalidPlatformFileValue = -1;
49 const int32_t kInvalidHandle = -1;
50 #endif
52 PlatformFile IntToPlatformFile(int32_t handle) {
53 #if defined(OS_WIN)
54 return reinterpret_cast<HANDLE>(static_cast<intptr_t>(handle));
55 #elif defined(OS_POSIX)
56 return handle;
57 #endif
60 #if defined(OS_POSIX)
62 #define HANDLE_EINTR(x) ({ \
63 typeof(x) eintr_wrapper_result; \
64 do { \
65 eintr_wrapper_result = (x); \
66 } while (eintr_wrapper_result == -1 && errno == EINTR); \
67 eintr_wrapper_result; \
70 #define IGNORE_EINTR(x) ({ \
71 typeof(x) eintr_wrapper_result; \
72 do { \
73 eintr_wrapper_result = (x); \
74 if (eintr_wrapper_result == -1 && errno == EINTR) { \
75 eintr_wrapper_result = 0; \
76 } \
77 } while (0); \
78 eintr_wrapper_result; \
81 #endif
83 bool ReadMessage(PlatformFile file, size_t message_len, char* message) {
84 #if defined(OS_WIN)
85 assert(message_len < std::numeric_limits<DWORD>::max());
86 DWORD read = 0;
87 const DWORD size = static_cast<DWORD>(message_len);
88 return ::ReadFile(file, message, size, &read, NULL) && read == size;
89 #elif defined(OS_POSIX)
90 assert(message_len <
91 static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
92 size_t total_read = 0;
93 while (total_read < message_len) {
94 ssize_t read = HANDLE_EINTR(::read(file, message + total_read,
95 message_len - total_read));
96 if (read <= 0)
97 break;
98 total_read += read;
100 return total_read == message_len;
101 #endif
104 bool WriteMessage(PlatformFile file, size_t message_len, const char* message) {
105 #if defined(OS_WIN)
106 assert(message_len < std::numeric_limits<DWORD>::max());
107 DWORD written = 0;
108 const DWORD size = static_cast<DWORD>(message_len);
109 return ::WriteFile(file, message, size, &written, NULL) && written == size;
110 #elif defined(OS_POSIX)
111 assert(message_len <
112 static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
113 size_t total_written = 0;
114 while (total_written < message_len) {
115 ssize_t written = HANDLE_EINTR(::write(file, message + total_written,
116 message_len - total_written));
117 if (written <= 0)
118 break;
119 total_written += written;
121 return total_written == message_len;
122 #endif
125 bool VerifyMessage(PlatformFile file, size_t message_len, const char* message) {
126 char* message_received = new char[message_len];
127 bool success = ReadMessage(file, message_len, message_received) &&
128 !::strcmp(message_received, message);
129 delete [] message_received;
130 return success;
133 bool ClosePlatformFile(PlatformFile file) {
134 #if defined(OS_WIN)
135 return !!::CloseHandle(file);
136 #elif defined(OS_POSIX)
137 return !IGNORE_EINTR(::close(file));
138 #endif
141 bool VerifyIsUnsandboxed() {
142 #if defined(OS_WIN)
143 FILE* file = NULL;
144 wchar_t temp_path[MAX_PATH] = {'\0'};
145 wchar_t file_name[MAX_PATH] = {'\0'};
146 if (!::GetTempPath(MAX_PATH, temp_path) ||
147 !::GetTempFileName(temp_path, L"test_pepper_broker", 0, file_name) ||
148 ::_wfopen_s(&file, file_name, L"w"))
149 return false;
151 if (::fclose(file)) {
152 ::DeleteFile(file_name);
153 return false;
156 return !!::DeleteFile(file_name);
157 #elif defined(OS_POSIX)
158 char file_name[] = "/tmp/test_pepper_broker_XXXXXX";
159 int fd = ::mkstemp(file_name);
160 if (-1 == fd)
161 return false;
163 if (IGNORE_EINTR(::close(fd))) {
164 ::remove(file_name);
165 return false;
168 return !::remove(file_name);
169 #endif
172 // Callback in the broker when a new broker connection occurs.
173 int32_t OnInstanceConnected(PP_Instance instance, int32_t handle) {
174 PlatformFile file = IntToPlatformFile(handle);
175 if (file == kInvalidPlatformFileValue)
176 return PP_ERROR_FAILED;
178 // Send hello message.
179 if (!WriteMessage(file, sizeof(kHelloMessage), kHelloMessage)) {
180 ClosePlatformFile(file);
181 return PP_ERROR_FAILED;
184 // Verify broker is not sandboxed and send result to plugin over the pipe.
185 if (VerifyIsUnsandboxed()) {
186 if (!WriteMessage(file, sizeof(kBrokerUnsandboxed), kBrokerUnsandboxed)) {
187 ClosePlatformFile(file);
188 return PP_ERROR_FAILED;
190 } else {
191 if (!WriteMessage(file, sizeof(kBrokerSandboxed), kBrokerSandboxed)) {
192 ClosePlatformFile(file);
193 return PP_ERROR_FAILED;
197 if (!ClosePlatformFile(file))
198 return PP_ERROR_FAILED;
200 return PP_OK;
203 } // namespace
205 PP_EXPORT int32_t PPP_InitializeBroker(
206 PP_ConnectInstance_Func* connect_instance_func) {
207 *connect_instance_func = &OnInstanceConnected;
208 return PP_OK;
211 PP_EXPORT void PPP_ShutdownBroker() {}
213 TestBroker::TestBroker(TestingInstance* instance)
214 : TestCase(instance),
215 broker_interface_(NULL) {
218 bool TestBroker::Init() {
219 broker_interface_ = static_cast<const PPB_BrokerTrusted*>(
220 pp::Module::Get()->GetBrowserInterface(PPB_BROKER_TRUSTED_INTERFACE));
221 return !!broker_interface_;
224 void TestBroker::RunTests(const std::string& filter) {
225 RUN_TEST(Create, filter);
226 RUN_TEST(Create, filter);
227 RUN_TEST(GetHandleFailure, filter);
228 RUN_TEST_FORCEASYNC_AND_NOT(ConnectFailure, filter);
229 RUN_TEST_FORCEASYNC_AND_NOT(ConnectAndPipe, filter);
231 // The following tests require special setup, so only run them if they're
232 // explicitly specified by the filter.
233 if (!ShouldRunAllTests(filter)) {
234 RUN_TEST(ConnectPermissionDenied, filter);
235 RUN_TEST(ConnectPermissionGranted, filter);
236 RUN_TEST(IsAllowedPermissionDenied, filter);
237 RUN_TEST(IsAllowedPermissionGranted, filter);
241 std::string TestBroker::TestCreate() {
242 // Very simplistic test to make sure we can create a broker interface.
243 // TODO(raymes): All of the resources created in this file are leaked. Write
244 // a C++ wrapper for PPB_Broker_Trusted to avoid these leaks.
245 PP_Resource broker = broker_interface_->CreateTrusted(
246 instance_->pp_instance());
247 ASSERT_TRUE(broker);
249 ASSERT_FALSE(broker_interface_->IsBrokerTrusted(0));
250 ASSERT_TRUE(broker_interface_->IsBrokerTrusted(broker));
252 PASS();
255 // Test connection on invalid resource.
256 std::string TestBroker::TestConnectFailure() {
257 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
258 callback.WaitForResult(broker_interface_->Connect(0,
259 callback.GetCallback().pp_completion_callback()));
260 CHECK_CALLBACK_BEHAVIOR(callback);
261 ASSERT_EQ(PP_ERROR_BADRESOURCE, callback.result());
263 PASS();
266 std::string TestBroker::TestGetHandleFailure() {
267 int32_t handle = kInvalidHandle;
269 // Test getting the handle for an invalid resource.
270 ASSERT_EQ(PP_ERROR_BADRESOURCE, broker_interface_->GetHandle(0, &handle));
272 // Connect hasn't been called so this should fail.
273 PP_Resource broker = broker_interface_->CreateTrusted(
274 instance_->pp_instance());
275 ASSERT_TRUE(broker);
276 ASSERT_EQ(PP_ERROR_FAILED, broker_interface_->GetHandle(broker, &handle));
278 PASS();
281 std::string TestBroker::TestConnectAndPipe() {
282 PP_Resource broker = broker_interface_->CreateTrusted(
283 instance_->pp_instance());
284 ASSERT_TRUE(broker);
286 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
287 callback.WaitForResult(broker_interface_->Connect(broker,
288 callback.GetCallback().pp_completion_callback()));
289 CHECK_CALLBACK_BEHAVIOR(callback);
290 ASSERT_EQ(PP_OK, callback.result());
292 int32_t handle = kInvalidHandle;
293 ASSERT_EQ(PP_OK, broker_interface_->GetHandle(broker, &handle));
294 ASSERT_NE(kInvalidHandle, handle);
296 PlatformFile file = IntToPlatformFile(handle);
297 ASSERT_TRUE(VerifyMessage(file, sizeof(kHelloMessage), kHelloMessage));
298 ASSERT_TRUE(VerifyMessage(file, sizeof(kBrokerUnsandboxed),
299 kBrokerUnsandboxed));
301 ASSERT_TRUE(ClosePlatformFile(file));
303 PASS();
306 std::string TestBroker::TestConnectPermissionDenied() {
307 // This assumes that the browser side is set up to deny access to the broker.
308 PP_Resource broker = broker_interface_->CreateTrusted(
309 instance_->pp_instance());
310 ASSERT_TRUE(broker);
312 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
313 callback.WaitForResult(broker_interface_->Connect(broker,
314 callback.GetCallback().pp_completion_callback()));
315 CHECK_CALLBACK_BEHAVIOR(callback);
316 ASSERT_EQ(PP_ERROR_NOACCESS, callback.result());
318 PASS();
321 std::string TestBroker::TestConnectPermissionGranted() {
322 // This assumes that the browser side is set up to allow access to the broker.
323 PP_Resource broker = broker_interface_->CreateTrusted(
324 instance_->pp_instance());
325 ASSERT_TRUE(broker);
327 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
328 callback.WaitForResult(broker_interface_->Connect(broker,
329 callback.GetCallback().pp_completion_callback()));
330 CHECK_CALLBACK_BEHAVIOR(callback);
331 ASSERT_EQ(PP_OK, callback.result());
333 PASS();
336 std::string TestBroker::TestIsAllowedPermissionDenied() {
337 PP_Resource broker = broker_interface_->CreateTrusted(
338 instance_->pp_instance());
339 ASSERT_TRUE(broker);
340 ASSERT_EQ(PP_FALSE, broker_interface_->IsAllowed(broker));
342 PASS();
345 std::string TestBroker::TestIsAllowedPermissionGranted() {
346 PP_Resource broker = broker_interface_->CreateTrusted(
347 instance_->pp_instance());
348 ASSERT_TRUE(broker);
349 ASSERT_EQ(PP_TRUE, broker_interface_->IsAllowed(broker));
351 PASS();