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 "build/build_config.h"
7 #include "ipc/ipc_tests.h"
17 #include "base/message_loop.h"
18 #include "base/posix/eintr_wrapper.h"
19 #include "ipc/ipc_channel.h"
20 #include "ipc/ipc_listener.h"
21 #include "ipc/ipc_message_utils.h"
22 #include "ipc/ipc_multiprocess_test.h"
23 #include "testing/multiprocess_func_list.h"
26 #include "base/file_descriptor_posix.h"
30 const unsigned kNumFDsToSend
= 20;
31 const char* kDevZeroPath
= "/dev/zero";
33 static void VerifyAndCloseDescriptor(int fd
, ino_t inode_num
) {
34 // Check that we can read from the FD.
36 ssize_t amt_read
= read(fd
, &buf
, 1);
37 ASSERT_EQ(amt_read
, 1);
38 ASSERT_EQ(buf
, 0); // /dev/zero always reads NUL bytes.
41 ASSERT_EQ(fstat(fd
, &st
), 0);
43 ASSERT_EQ(close(fd
), 0);
45 // We compare iNode numbers to check that the file sent over the wire
46 // was actually the same physical file as the one we were expecting.
47 ASSERT_EQ(inode_num
, st
.st_ino
);
50 class MyChannelDescriptorListener
: public IPC::Listener
{
52 MyChannelDescriptorListener(ino_t expected_inode_num
)
53 : expected_inode_num_(expected_inode_num
),
54 num_fds_received_(0) {}
56 virtual bool OnMessageReceived(const IPC::Message
& message
) {
57 PickleIterator
iter(message
);
60 base::FileDescriptor descriptor
;
62 IPC::ParamTraits
<base::FileDescriptor
>::Read(
63 &message
, &iter
, &descriptor
);
65 VerifyAndCloseDescriptor(descriptor
.fd
, expected_inode_num_
);
66 if (num_fds_received_
== kNumFDsToSend
) {
67 MessageLoop::current()->Quit();
72 virtual void OnChannelError() {
73 MessageLoop::current()->Quit();
76 bool GotExpectedNumberOfDescriptors() {
77 return kNumFDsToSend
== num_fds_received_
;
81 ino_t expected_inode_num_
;
82 unsigned num_fds_received_
;
85 void TestDescriptorServer(IPC::Channel
& chan
,
86 base::ProcessHandle process_handle
) {
87 ASSERT_TRUE(process_handle
);
89 for (unsigned i
= 0; i
< kNumFDsToSend
; ++i
) {
90 base::FileDescriptor descriptor
;
91 const int fd
= open(kDevZeroPath
, O_RDONLY
);
93 descriptor
.auto_close
= true;
96 IPC::Message
* message
= new IPC::Message(0, // routing_id
98 IPC::Message::PRIORITY_NORMAL
);
99 IPC::ParamTraits
<base::FileDescriptor
>::Write(message
, descriptor
);
100 ASSERT_TRUE(chan
.Send(message
));
104 MessageLoop::current()->Run();
106 // Close Channel so client gets its OnChannelError() callback fired.
109 // Cleanup child process.
110 EXPECT_TRUE(base::WaitForSingleProcess(
111 process_handle
, base::TimeDelta::FromSeconds(5)));
114 int TestDescriptorClient(ino_t expected_inode_num
) {
115 MessageLoopForIO main_message_loop
;
116 MyChannelDescriptorListener
listener(expected_inode_num
);
118 // Setup IPC channel.
119 IPC::Channel
chan(kTestClientChannel
, IPC::Channel::MODE_CLIENT
,
121 CHECK(chan
.Connect());
123 // Run message loop so IPC Channel can handle message IO.
124 MessageLoop::current()->Run();
126 // Verify that the message loop was exited due to getting the correct
127 // number of descriptors, and not because the channel closing unexpectedly.
128 CHECK(listener
.GotExpectedNumberOfDescriptors());
135 // ---------------------------------------------------------------------------
136 #if defined(OS_MACOSX)
137 // TODO(port): Make this test cross-platform.
138 MULTIPROCESS_IPC_TEST_MAIN(RunTestDescriptorClientSandboxed
) {
140 const int fd
= open(kDevZeroPath
, O_RDONLY
);
142 if (HANDLE_EINTR(close(fd
)) < 0) {
146 // Enable the Sandbox.
147 char* error_buff
= NULL
;
148 int error
= sandbox_init(kSBXProfilePureComputation
, SANDBOX_NAMED
,
150 bool success
= (error
== 0 && error_buff
== NULL
);
155 sandbox_free_error(error_buff
);
157 // Make sure Sandbox is really enabled.
158 if (open(kDevZeroPath
, O_RDONLY
) != -1) {
159 LOG(ERROR
) << "Sandbox wasn't properly enabled";
163 // See if we can receive a file descriptor.
164 return TestDescriptorClient(st
.st_ino
);
167 // Test that FDs are correctly sent to a sandboxed process.
168 TEST_F(IPCChannelTest
, DescriptorTestSandboxed
) {
169 // Setup IPC channel.
170 MyChannelDescriptorListener
listener(-1);
172 IPC::Channel
chan(kTestClientChannel
, IPC::Channel::MODE_SERVER
,
174 ASSERT_TRUE(chan
.Connect());
176 base::ProcessHandle process_handle
= SpawnChild(
177 TEST_DESCRIPTOR_CLIENT_SANDBOXED
,
179 TestDescriptorServer(chan
, process_handle
);
181 #endif // defined(OS_MACOSX)
183 MULTIPROCESS_IPC_TEST_MAIN(RunTestDescriptorClient
) {
185 const int fd
= open(kDevZeroPath
, O_RDONLY
);
187 EXPECT_GE(HANDLE_EINTR(close(fd
)), 0);
189 return TestDescriptorClient(st
.st_ino
);
192 TEST_F(IPCChannelTest
, DescriptorTest
) {
193 // Setup IPC channel.
194 MyChannelDescriptorListener
listener(-1);
196 IPC::Channel
chan(kTestClientChannel
, IPC::Channel::MODE_SERVER
,
198 ASSERT_TRUE(chan
.Connect());
200 base::ProcessHandle process_handle
= SpawnChild(TEST_DESCRIPTOR_CLIENT
,
202 TestDescriptorServer(chan
, process_handle
);
205 #endif // defined(OS_POSIX)