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"
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
);
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
39 const char kBrokerSandboxed
[] = "Broker is Sandboxed! Verification failed!";
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;
52 PlatformFile
IntToPlatformFile(int32_t handle
) {
54 return reinterpret_cast<HANDLE
>(static_cast<intptr_t>(handle
));
55 #elif defined(OS_POSIX)
62 #define HANDLE_EINTR(x) ({ \
63 typeof(x) eintr_wrapper_result; \
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; \
73 eintr_wrapper_result = (x); \
74 if (eintr_wrapper_result == -1 && errno == EINTR) { \
75 eintr_wrapper_result = 0; \
78 eintr_wrapper_result; \
83 bool ReadMessage(PlatformFile file
, size_t message_len
, char* message
) {
85 assert(message_len
< std::numeric_limits
<DWORD
>::max());
87 const DWORD size
= static_cast<DWORD
>(message_len
);
88 return ::ReadFile(file
, message
, size
, &read
, NULL
) && read
== size
;
89 #elif defined(OS_POSIX)
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
));
100 return total_read
== message_len
;
104 bool WriteMessage(PlatformFile file
, size_t message_len
, const char* message
) {
106 assert(message_len
< std::numeric_limits
<DWORD
>::max());
108 const DWORD size
= static_cast<DWORD
>(message_len
);
109 return ::WriteFile(file
, message
, size
, &written
, NULL
) && written
== size
;
110 #elif defined(OS_POSIX)
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
));
119 total_written
+= written
;
121 return total_written
== message_len
;
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
;
133 bool ClosePlatformFile(PlatformFile file
) {
135 return !!::CloseHandle(file
);
136 #elif defined(OS_POSIX)
137 return !IGNORE_EINTR(::close(file
));
141 bool VerifyIsUnsandboxed() {
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"))
151 if (::fclose(file
)) {
152 ::DeleteFile(file_name
);
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
);
163 if (IGNORE_EINTR(::close(fd
))) {
168 return !::remove(file_name
);
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
;
191 if (!WriteMessage(file
, sizeof(kBrokerSandboxed
), kBrokerSandboxed
)) {
192 ClosePlatformFile(file
);
193 return PP_ERROR_FAILED
;
197 if (!ClosePlatformFile(file
))
198 return PP_ERROR_FAILED
;
205 PP_EXPORT
int32_t PPP_InitializeBroker(
206 PP_ConnectInstance_Func
* connect_instance_func
) {
207 *connect_instance_func
= &OnInstanceConnected
;
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());
249 ASSERT_FALSE(broker_interface_
->IsBrokerTrusted(0));
250 ASSERT_TRUE(broker_interface_
->IsBrokerTrusted(broker
));
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());
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());
276 ASSERT_EQ(PP_ERROR_FAILED
, broker_interface_
->GetHandle(broker
, &handle
));
281 std::string
TestBroker::TestConnectAndPipe() {
282 PP_Resource broker
= broker_interface_
->CreateTrusted(
283 instance_
->pp_instance());
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
));
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());
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());
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());
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());
336 std::string
TestBroker::TestIsAllowedPermissionDenied() {
337 PP_Resource broker
= broker_interface_
->CreateTrusted(
338 instance_
->pp_instance());
340 ASSERT_EQ(PP_FALSE
, broker_interface_
->IsAllowed(broker
));
345 std::string
TestBroker::TestIsAllowedPermissionGranted() {
346 PP_Resource broker
= broker_interface_
->CreateTrusted(
347 instance_
->pp_instance());
349 ASSERT_EQ(PP_TRUE
, broker_interface_
->IsAllowed(broker
));